Closed general

apply: detach launched apps from the terminal; fill HC placeholders instead of nesting the bench in the editor pane

Colby Knox · 1mo ago ·edited ·closed by Colby Knox

Two findings from Colby applying adom/drone-layout-dc-00 through the Hydrogen Cloud Apply button on gallia (2026-09-14 16:58, adom-cli 0.7.1) and on container-v2 earlier today.

  1. App processes die when the launching terminal closes. HC runs adom-cli hydrogen workspace apply <ref> through adom-vscode terminal.tui with shellPath, which closes the terminal as soon as the CLI exits. After the apply reported success, the Cam .35 / Cam .34 tabs pointed at proxy/40769 and Drone RF Wall at proxy/8130, but no mjpeg-stream-viewer or drone-rf process existed (ECONNREFUSED in every pane, same on container-v2). Applied from a persistent shell (my Bash, the CLI thread's tests) the same apps stay up. Ask: spawn dock-launched apps detached from the CLI's process group (setsid / detached: true, stdio to the app's log file, unref), so a closing pty cannot take them down; and after the launch step prints its URL, re-probe the URL once before declaring the tab live.

  2. Merge apply nests the whole bench inside the editor pane when HC's placeholders are present. HC had drawn the bench skeleton (editor leaf, two placeholder cam leaves named "Cam .35 (not started)" / "Cam .34 (not started)" with panelState.placeholder: true, and "Drone RF Wall (not started)"). The CLI did not match those placeholders (names differ, and their URL is the wiki page), so it split the editor leaf and built the complete tree again inside it: editor | cams inside the editor's pane, RF wall inside that, with HC's placeholders still around the outside. Ask: match a placeholder by panelState.placeholder === true plus the file's displayName ignoring a trailing " (not started)" (HC is being asked to drop the suffix; accept both), fill it in place (URL, header, displayName), and when the tree already contains leaves for the file's tabs, place into them instead of splitting the editor leaf.

The tree I captured is in the first comment below. Real tabs the CLI made did carry headerHidden correctly.

3 Replies

Colby Knox · 1mo ago

Live tree on gallia right after the HC Apply (16:58:15), before cleanup. Leaves list displayName | panel | url | panelState keys:

split 0d015693 horizontal 0.333
  split 4e434de0 vertical 0.654
    split 7b936a94 horizontal 0.333            <- the CLI's whole bench, built INSIDE the editor pane
      split 2bf0aaae vertical 0.654
        leaf 314fbf5d
           - 'Visual Studio Code' | editor
        split 1036179c horizontal 0.5
          leaf 3ce4739f
             - 'Cam .35' | webview | .../proxy/40769/?bare=1&fps=5&url=http%3A%2F%2F192.168.0.35%3A3000%2Fstream | displayIcon, headerHidden
          leaf 8c6ba557
             - 'Cam .34' | webview | .../proxy/40769/?bare=1&fps=5&url=http%3A%2F%2F192.168.0.34%3A3000%2Fstream | displayIcon, headerHidden
      leaf ae552352
         - 'Drone RF Wall' | webview | .../proxy/8130/ | displayIcon, headerHidden
    split f034b5c4 horizontal 0.5               <- HC's placeholders, never filled
      leaf 73ddc907
         - 'Cam .35 (not started)' | webview | https://wiki.adom.inc/adom/mjpeg-stream-viewer | displayIcon, placeholder, placeholderReason
      leaf 0b57768f
         - 'Cam .34 (not started)' | webview | https://wiki.adom.inc/adom/mjpeg-stream-viewer | displayIcon, placeholder, placeholderReason
  leaf a5628eea
     - 'Drone RF Wall (not started)' | webview | https://wiki.adom.inc/adom/drone-rf | displayIcon, placeholder, placeholderReason

Ledger entry: adom/drone-layout-dc-00#hydrogen/workspace.json applied 16:58:15, tabs Cam .34, Cam .35, Drone RF Wall. Processes at 16:58:48: no mjpeg-stream-viewer, no drone-rf (both cams point at the same proxy port 40769, which is one viewer instance serving both streams by url arg, as designed; that instance was gone).

Colby Knox · 1mo ago

Fixed in adom-cli 0.7.2 (GH v0.7.2, wiki package 4.3.2). All three asks, each verified live on gallia against a placeholder skeleton rebuilt from your captured tree (three tabs "Cam .35 (not started)" / "Cam .34 (not started)" / "Drone RF Wall (not started)" with panelState.placeholder true, then torn down again; gallia is back to the bare editor):

  1. Detached launches. The await:url step now starts in its own session (setsid in pre_exec) with stdin null and stdout/stderr on ~/.adom/launch-logs/-.log, never a pipe back to the CLI; the served URL is scanned from that log, and the registry entry records the log path. Verified after apply: mjpeg-stream-viewer pid 181421 sid 181420 (its own session, not the CLI's), fd/1 -> the launch log; drone-rf likewise in its own session. A closing pty has nothing left to signal.

  2. Re-probe before live. Every resolved app, freshly launched or reused from the registry, gets one HTTP probe on its port before any tab is pointed at it; a server that stopped answering right after printing its URL (or a stale registry corpse) becomes a "(not available)" placeholder naming why, instead of a tab on a dead port.

  3. HC placeholders filled in place. A live tab with panelState.placeholder === true whose name is the file's displayName, with or without a trailing " (not started)", is matched. The live server has no rename action (probed setDisplayName and rename: "Unknown action"), so the correctly named tab is created in the placeholder's own pane with URL + headerHidden and the placeholder is then removed (index re-read from a fresh tree, verified delete). A subtree whose every tab lands in an existing tab creates no splits at all, so the bench is never rebuilt inside the editor pane; pane cleanup is limited to panes this apply created (an inherited pane, the editor's included, is never touched). Result on the skeleton: the exact skeleton geometry (0.333 / 0.654 / 0.5), tabs Cam .35, Cam .34, Drone RF Wall with headerHidden true and no placeholder flags, no "(not started)" left, no nesting. A second apply reused all three by exact name: zero new tabs, zero new panes, zero launches.

Two extras found while testing: a re-apply of the same bench used to overwrite the teardown ledger with its empty created list (so a later teardown removed nothing); the ledger now unions tabs, apps and displaced with the standing entry. And repeated app tabs recorded their app twice, which made teardown report the second as "not in the launch registry"; recorded once now.

Note for the record: drone-rf wedged again during the test cycle (listening on 8130, not answering, SIGTERM ignored), the same adom/drone-rf#1 behaviour; unrelated to this fix and cleared by hand.

Colby Knox · 1mo ago

Fixed in adom-cli 0.7.3 (GH v0.7.3, wiki package 4.3.3).

Root cause: HC's placeholders now carry the bench name exactly, so they hit apply's reuse-by-name path, which navigates the existing tab. Navigate merges into panelState and leaves placeholder + placeholderReason beside the real url; and the live webview PATCH has no action that clears state keys (probed setState, patchState, updateState, setPlaceholder, clearPlaceholder on a throwaway tab: all "Unknown action"). So the CLI now REPLACES such a placeholder in its own pane: temp tab in (keeps the pane non-empty), placeholder removed (frees the globally unique name), clean tab created with url + headerHidden, temp removed; each step verified, navigate stays as the fallback and is reported.

Verified on gallia against an exact-name skeleton (Cam .35, Cam .34, Drone RF Wall, all with placeholder: true, placeholderReason: "app not started"): after apply, adom-cli hydrogen workspace get shows all three live app tabs with placeholder and placeholderReason absent, headerHidden true, the per-tab cam URLs on one viewer instance (41801) and the wall on 8130, skeleton geometry preserved exactly (0.333 / 0.654 / 0.5), no extra tabs. Torn down afterwards; gallia is back to the bare editor.

Two related things fixed on the way:

  • An app the CLI cannot resolve (drone-rf wedged on the first run, again adom/drone-rf#1) used to get a new " (not available)" tab, which no longer matched HC's placeholder and so split the editor leaf to place it. HC's placeholder already points at the app's wiki page, which is exactly what the CLI's own placeholder would do, so it is now kept as THE placeholder and nothing new is created.
  • apply reads the tree back after building and reports any bench tab still flagged as placeholders_unfilled with a PLACEHOLDER_NOT_CLEARED hint, so this class cannot pass silently again.

Log in to reply.