@crouton-kit/crouter 0.3.27 → 0.3.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/build-root.js +4 -2
- package/dist/builtin-memory/crouter-development/marketplaces.md +7 -6
- package/dist/builtin-memory/crouter-development/personas/base-prompt.md +1 -1
- package/dist/builtin-memory/crouter-development/personas/orchestrator-prompt.md +1 -1
- package/dist/builtin-memory/crouter-development/personas.md +1 -1
- package/dist/builtin-memory/crouter-development/plugins.md +20 -18
- package/dist/builtin-memory/design.md +1 -1
- package/dist/builtin-memory/development.md +1 -1
- package/dist/builtin-memory/internal/INDEX.md +1 -1
- package/dist/builtin-memory/internal/examples/INDEX.md +1 -1
- package/dist/builtin-memory/internal/examples/imessage-assistant.md +2 -2
- package/dist/builtin-memory/internal/nodes-and-canvas.md +1 -1
- package/dist/builtin-memory/internal/storage-tiers.md +1 -1
- package/dist/builtin-memory/planning.md +1 -1
- package/dist/builtin-memory/spec.md +6 -4
- package/dist/builtin-personas/orchestration-kernel.md +4 -5
- package/dist/builtin-personas/runtime-base.md +8 -4
- package/dist/builtin-personas/spec/PERSONA.md +8 -4
- package/dist/builtin-personas/spec/orchestrator.md +5 -3
- package/dist/builtin-personas/spec/requirements/PERSONA.md +10 -0
- package/dist/builtin-views/canvas/core.mjs +586 -0
- package/dist/builtin-views/canvas/text.mjs +58 -0
- package/dist/builtin-views/canvas/tui.mjs +165 -0
- package/dist/builtin-views/canvas/web.jsx +120 -0
- package/dist/builtin-views/git-pr/core.mjs +673 -0
- package/dist/builtin-views/git-pr/text.mjs +84 -0
- package/dist/builtin-views/git-pr/tui.mjs +302 -0
- package/dist/builtin-views/git-pr/web.jsx +216 -0
- package/dist/builtin-views/inbox/_lib/render.mjs +1 -3
- package/dist/builtin-views/inbox/core.mjs +1273 -0
- package/dist/builtin-views/inbox/text.mjs +73 -0
- package/dist/builtin-views/inbox/tui.mjs +312 -0
- package/dist/builtin-views/inbox/web.jsx +188 -0
- package/dist/builtin-views/linkedin/core.mjs +906 -0
- package/dist/builtin-views/linkedin/text.mjs +69 -0
- package/dist/builtin-views/linkedin/tui.mjs +427 -0
- package/dist/builtin-views/linkedin/web.jsx +206 -0
- package/dist/builtin-views/workspace-sidebar/core.mjs +621 -0
- package/dist/builtin-views/workspace-sidebar/text.mjs +53 -0
- package/dist/builtin-views/workspace-sidebar/tui.mjs +142 -0
- package/dist/builtin-views/workspace-sidebar/web.jsx +109 -0
- package/dist/cli.js +3 -3
- package/dist/clients/attach/__tests__/action-parity.test.js +48 -0
- package/dist/clients/attach/__tests__/clipboard-image.test.js +76 -0
- package/dist/clients/attach/__tests__/editor-newline.test.js +57 -0
- package/dist/clients/attach/__tests__/git-info.test.js +31 -0
- package/dist/clients/attach/__tests__/onrequest-wired.test.js +20 -0
- package/dist/clients/attach/__tests__/reconnect-giveup.test.js +30 -0
- package/dist/clients/attach/__tests__/slash-quit-copy.test.js +42 -0
- package/dist/clients/attach/__tests__/titled-editor.test.d.ts +1 -0
- package/dist/clients/attach/__tests__/titled-editor.test.js +39 -0
- package/dist/clients/attach/attach-cmd.js +445 -41
- package/dist/clients/attach/auth-pickers.d.ts +9 -0
- package/dist/clients/attach/auth-pickers.js +194 -0
- package/dist/clients/attach/canvas-panels.d.ts +12 -0
- package/dist/clients/attach/canvas-panels.js +78 -0
- package/dist/clients/attach/chat-view.d.ts +27 -2
- package/dist/clients/attach/chat-view.js +98 -9
- package/dist/clients/attach/clipboard-image.d.ts +47 -8
- package/dist/clients/attach/clipboard-image.js +150 -26
- package/dist/clients/attach/clipboard-text.d.ts +3 -0
- package/dist/clients/attach/clipboard-text.js +39 -0
- package/dist/clients/attach/config-load.d.ts +54 -7
- package/dist/clients/attach/config-load.js +99 -3
- package/dist/clients/attach/context-message.d.ts +12 -0
- package/dist/clients/attach/context-message.js +72 -0
- package/dist/clients/attach/git-info.d.ts +20 -0
- package/dist/clients/attach/git-info.js +44 -0
- package/dist/clients/attach/graph-overlay.d.ts +43 -0
- package/dist/clients/attach/graph-overlay.js +306 -0
- package/dist/clients/attach/input-controller.d.ts +81 -13
- package/dist/clients/attach/input-controller.js +307 -67
- package/dist/clients/attach/pickers.d.ts +58 -0
- package/dist/clients/attach/pickers.js +171 -0
- package/dist/clients/attach/slash-commands.d.ts +44 -1
- package/dist/clients/attach/slash-commands.js +250 -27
- package/dist/clients/attach/titled-editor.d.ts +33 -0
- package/dist/clients/attach/titled-editor.js +84 -0
- package/dist/clients/attach/view-socket.d.ts +37 -2
- package/dist/clients/attach/view-socket.js +131 -7
- package/dist/clients/web/dev-server.d.ts +7 -0
- package/dist/clients/web/dev-server.js +59 -0
- package/dist/clients/web/events.d.ts +14 -0
- package/dist/clients/web/events.js +151 -0
- package/dist/clients/web/server.d.ts +18 -0
- package/dist/clients/web/server.js +450 -0
- package/dist/clients/web/web-cmd.d.ts +2 -0
- package/dist/clients/web/web-cmd.js +120 -0
- package/dist/commands/canvas.js +1 -2
- package/dist/commands/chord.js +1 -1
- package/dist/commands/dashboard.js +5 -1
- package/dist/commands/human/prompts.js +3 -3
- package/dist/commands/human/queue.d.ts +17 -0
- package/dist/commands/human/queue.js +111 -4
- package/dist/commands/memory/__tests__/lint-schema.test.js +27 -4
- package/dist/commands/memory/lint.d.ts +5 -4
- package/dist/commands/memory/lint.js +23 -7
- package/dist/commands/memory/read.js +2 -2
- package/dist/commands/memory/shared.d.ts +7 -1
- package/dist/commands/memory/shared.js +18 -3
- package/dist/commands/memory/write.js +20 -7
- package/dist/commands/memory.js +4 -4
- package/dist/commands/node.d.ts +1 -1
- package/dist/commands/node.js +64 -65
- package/dist/commands/pkg.js +1 -2
- package/dist/commands/revive.js +11 -3
- package/dist/commands/sys/feedback.d.ts +1 -0
- package/dist/commands/sys/feedback.js +163 -0
- package/dist/commands/sys/sync.d.ts +1 -0
- package/dist/commands/sys/sync.js +187 -0
- package/dist/commands/sys.js +4 -2
- package/dist/commands/view-cycle.js +2 -2
- package/dist/commands/view-list.js +8 -8
- package/dist/commands/view-new.js +21 -17
- package/dist/commands/view-pick.js +1 -1
- package/dist/commands/view-run.js +35 -14
- package/dist/commands/view.js +8 -6
- package/dist/commands/workspace.d.ts +2 -0
- package/dist/commands/workspace.js +161 -0
- package/dist/core/__tests__/broker-double-spawn.test.d.ts +1 -0
- package/dist/core/__tests__/broker-double-spawn.test.js +143 -0
- package/dist/core/__tests__/broker-fork-seam.test.d.ts +1 -0
- package/dist/core/__tests__/broker-fork-seam.test.js +102 -0
- package/dist/core/__tests__/broker-sdk-wiring.test.js +2 -0
- package/dist/core/__tests__/broker-snapshot-history.test.d.ts +1 -0
- package/dist/core/__tests__/broker-snapshot-history.test.js +105 -0
- package/dist/core/__tests__/child-death-wake.test.js +56 -111
- package/dist/core/__tests__/close.test.js +14 -20
- package/dist/core/__tests__/context-intro.test.js +19 -19
- package/dist/core/__tests__/daemon-boot.test.js +30 -23
- package/dist/core/__tests__/draw-style.test.js +1 -1
- package/dist/core/__tests__/error-stall-recycle.test.d.ts +1 -0
- package/dist/core/__tests__/error-stall-recycle.test.js +141 -0
- package/dist/core/__tests__/fixtures/fake-engine.d.ts +24 -1
- package/dist/core/__tests__/fixtures/fake-engine.js +32 -2
- package/dist/core/__tests__/fixtures/fake-pi-host.js +2 -2
- package/dist/core/__tests__/focuses.test.js +25 -13
- package/dist/core/__tests__/fork.test.js +22 -5
- package/dist/core/__tests__/full/broker-control-preempt.test.d.ts +1 -0
- package/dist/core/__tests__/full/broker-control-preempt.test.js +61 -0
- package/dist/core/__tests__/full/broker-model-changed-broadcast.test.d.ts +1 -0
- package/dist/core/__tests__/full/broker-model-changed-broadcast.test.js +57 -0
- package/dist/core/__tests__/full/broker-navigate-tree-rewelcome.test.d.ts +1 -0
- package/dist/core/__tests__/full/broker-navigate-tree-rewelcome.test.js +80 -0
- package/dist/core/__tests__/full/broker-pane-resolution.test.js +90 -0
- package/dist/core/__tests__/full/cascade-close.test.js +22 -8
- package/dist/core/__tests__/full/detach-focus.test.js +66 -169
- package/dist/core/__tests__/helpers/harness.d.ts +6 -9
- package/dist/core/__tests__/helpers/harness.js +19 -36
- package/dist/core/__tests__/human-node-not-supervised.test.d.ts +1 -0
- package/dist/core/__tests__/human-node-not-supervised.test.js +83 -0
- package/dist/core/__tests__/human-stranded-deliver.test.d.ts +1 -0
- package/dist/core/__tests__/human-stranded-deliver.test.js +108 -0
- package/dist/core/__tests__/lifecycle.test.js +1 -19
- package/dist/core/__tests__/live-mutation-verbs.test.js +5 -5
- package/dist/core/__tests__/memory-resolver.test.js +1 -1
- package/dist/core/__tests__/on-read-dedup-resume.test.d.ts +1 -0
- package/dist/core/__tests__/on-read-dedup-resume.test.js +81 -0
- package/dist/core/__tests__/refresh-stall-recycle.test.d.ts +1 -0
- package/dist/core/__tests__/refresh-stall-recycle.test.js +88 -0
- package/dist/core/__tests__/relaunch-root.test.d.ts +1 -0
- package/dist/core/__tests__/relaunch-root.test.js +114 -0
- package/dist/core/__tests__/reset.test.js +19 -79
- package/dist/core/__tests__/steer-note.test.js +9 -7
- package/dist/core/__tests__/tmux-surface.test.js +13 -7
- package/dist/core/bootstrap.d.ts +0 -3
- package/dist/core/bootstrap.js +1 -143
- package/dist/core/canvas/browse/__tests__/model.test.js +86 -1
- package/dist/core/canvas/browse/__tests__/render.test.js +2 -1
- package/dist/core/canvas/browse/app.js +131 -8
- package/dist/core/canvas/browse/model.d.ts +23 -5
- package/dist/core/canvas/browse/model.js +68 -13
- package/dist/core/canvas/browse/render.d.ts +7 -1
- package/dist/core/canvas/browse/render.js +178 -47
- package/dist/core/canvas/canvas.js +1 -1
- package/dist/core/canvas/focuses.d.ts +4 -4
- package/dist/core/canvas/focuses.js +7 -7
- package/dist/core/canvas/nav-model.d.ts +162 -0
- package/dist/core/canvas/nav-model.js +487 -0
- package/dist/core/canvas/paths.d.ts +7 -0
- package/dist/core/canvas/paths.js +9 -0
- package/dist/core/canvas/render.d.ts +68 -9
- package/dist/core/canvas/render.js +195 -61
- package/dist/core/canvas/types.d.ts +16 -23
- package/dist/core/config.js +1 -4
- package/dist/core/memory-resolver.js +43 -5
- package/dist/core/runtime/bearings.d.ts +1 -1
- package/dist/core/runtime/bearings.js +8 -8
- package/dist/core/runtime/branded-host.d.ts +16 -0
- package/dist/core/runtime/branded-host.js +127 -0
- package/dist/core/runtime/broker-protocol.d.ts +212 -6
- package/dist/core/runtime/broker-sdk.d.ts +0 -12
- package/dist/core/runtime/broker-sdk.js +77 -6
- package/dist/core/runtime/broker.d.ts +5 -1
- package/dist/core/runtime/broker.js +520 -59
- package/dist/core/runtime/close.d.ts +12 -2
- package/dist/core/runtime/close.js +37 -16
- package/dist/core/runtime/front-door.js +14 -7
- package/dist/core/runtime/host.d.ts +14 -34
- package/dist/core/runtime/host.js +14 -50
- package/dist/core/runtime/launch.d.ts +12 -9
- package/dist/core/runtime/launch.js +27 -15
- package/dist/core/runtime/lifecycle.d.ts +1 -1
- package/dist/core/runtime/lifecycle.js +15 -19
- package/dist/core/runtime/nodes.d.ts +0 -55
- package/dist/core/runtime/nodes.js +6 -74
- package/dist/core/runtime/placement.d.ts +91 -334
- package/dist/core/runtime/placement.js +262 -828
- package/dist/core/runtime/promote.d.ts +2 -0
- package/dist/core/runtime/promote.js +24 -6
- package/dist/core/runtime/recap.d.ts +8 -0
- package/dist/core/runtime/recap.js +107 -0
- package/dist/core/runtime/recycle.js +25 -61
- package/dist/core/runtime/reset.d.ts +43 -37
- package/dist/core/runtime/reset.js +131 -218
- package/dist/core/runtime/revive.d.ts +9 -29
- package/dist/core/runtime/revive.js +45 -135
- package/dist/core/runtime/spawn.d.ts +15 -11
- package/dist/core/runtime/spawn.js +168 -136
- package/dist/core/runtime/surface-bg.d.ts +11 -0
- package/dist/core/runtime/surface-bg.js +68 -0
- package/dist/core/runtime/tmux.d.ts +15 -43
- package/dist/core/runtime/tmux.js +38 -80
- package/dist/core/scope.d.ts +1 -2
- package/dist/core/scope.js +1 -5
- package/dist/core/skill-sync/__tests__/dry-run-wrote-count.test.d.ts +1 -0
- package/dist/core/skill-sync/__tests__/dry-run-wrote-count.test.js +57 -0
- package/dist/core/skill-sync/builtins.d.ts +42 -0
- package/dist/core/skill-sync/builtins.js +112 -0
- package/dist/core/skill-sync/claude-plugins.d.ts +23 -0
- package/dist/core/skill-sync/claude-plugins.js +71 -0
- package/dist/core/skill-sync/engine.d.ts +42 -0
- package/dist/core/skill-sync/engine.js +633 -0
- package/dist/core/skill-sync/export.d.ts +23 -0
- package/dist/core/skill-sync/export.js +86 -0
- package/dist/core/skill-sync/manifest.d.ts +64 -0
- package/dist/core/skill-sync/manifest.js +181 -0
- package/dist/core/skill-sync/profile.d.ts +76 -0
- package/dist/core/skill-sync/profile.js +173 -0
- package/dist/core/skill-sync/snapshot.d.ts +57 -0
- package/dist/core/skill-sync/snapshot.js +120 -0
- package/dist/core/spawn.d.ts +14 -0
- package/dist/core/spawn.js +29 -9
- package/dist/core/substrate/index.d.ts +2 -2
- package/dist/core/substrate/index.js +7 -7
- package/dist/core/substrate/injected-store.d.ts +10 -0
- package/dist/core/substrate/injected-store.js +55 -0
- package/dist/core/substrate/on-read.js +68 -6
- package/dist/core/substrate/render.d.ts +8 -11
- package/dist/core/substrate/render.js +29 -43
- package/dist/core/substrate/schema.d.ts +16 -11
- package/dist/core/substrate/schema.js +32 -31
- package/dist/core/tui/host.d.ts +12 -4
- package/dist/core/tui/host.js +280 -149
- package/dist/core/view/bridge.d.ts +10 -0
- package/dist/core/view/bridge.js +31 -0
- package/dist/core/view/chrome.d.ts +9 -0
- package/dist/core/view/chrome.js +22 -0
- package/dist/core/view/contract.d.ts +171 -0
- package/dist/core/view/contract.js +23 -0
- package/dist/core/view/loader.d.ts +31 -0
- package/dist/core/view/loader.js +188 -0
- package/dist/core/view/transport-local.d.ts +7 -0
- package/dist/core/view/transport-local.js +70 -0
- package/dist/core/view/transport.d.ts +4 -0
- package/dist/core/view/transport.js +15 -0
- package/dist/daemon/crtrd.d.ts +38 -27
- package/dist/daemon/crtrd.js +303 -376
- package/dist/daemon/manage.js +6 -1
- package/dist/index.js +1 -1
- package/dist/pi-extensions/__tests__/canvas-stophook-agentend.test.js +28 -20
- package/dist/pi-extensions/canvas-context-intro.js +4 -4
- package/dist/pi-extensions/canvas-doc-substrate.js +29 -20
- package/dist/pi-extensions/canvas-nav.js +35 -385
- package/dist/pi-extensions/canvas-recap.d.ts +37 -0
- package/dist/pi-extensions/canvas-recap.js +236 -0
- package/dist/pi-extensions/canvas-resume.js +2 -1
- package/dist/pi-extensions/canvas-stophook.d.ts +15 -13
- package/dist/pi-extensions/canvas-stophook.js +119 -103
- package/dist/pi-extensions/canvas-view.js +2 -1
- package/dist/pi-extensions/widget-order-bus.d.ts +6 -0
- package/dist/pi-extensions/widget-order-bus.js +34 -0
- package/dist/prompts/view.d.ts +2 -2
- package/dist/prompts/view.js +145 -73
- package/dist/types.d.ts +1 -6
- package/dist/types.js +1 -3
- package/dist/web/ViewChrome.d.ts +7 -0
- package/dist/web/ViewChrome.js +28 -0
- package/dist/web/ViewPane.d.ts +39 -0
- package/dist/web/ViewPane.js +48 -0
- package/dist/web/index.d.ts +6 -0
- package/dist/web/index.js +16 -0
- package/dist/web/runtime.d.ts +39 -0
- package/dist/web/runtime.js +133 -0
- package/dist/web/states.d.ts +24 -0
- package/dist/web/states.js +24 -0
- package/dist/web/transport-http.d.ts +5 -0
- package/dist/web/transport-http.js +28 -0
- package/dist/web-client/assets/index-BUvQb4hR.css +2 -0
- package/dist/web-client/assets/index-ClLQXYAE.js +10 -0
- package/dist/web-client/index.html +13 -0
- package/package.json +20 -6
- package/dist/builtin-views/canvas/client.mjs +0 -303
- package/dist/builtin-views/canvas/view.mjs +0 -576
- package/dist/builtin-views/git-pr/client.mjs +0 -440
- package/dist/builtin-views/git-pr/view.mjs +0 -675
- package/dist/builtin-views/inbox/sources/gmail.mjs +0 -965
- package/dist/builtin-views/inbox/sources/linkedin.mjs +0 -427
- package/dist/builtin-views/inbox/view.mjs +0 -889
- package/dist/builtin-views/linkedin/client.mjs +0 -610
- package/dist/builtin-views/linkedin/view.mjs +0 -1171
- package/dist/commands/pkg/bridge.d.ts +0 -1
- package/dist/commands/pkg/bridge.js +0 -137
- package/dist/commands/skill/author.d.ts +0 -3
- package/dist/commands/skill/author.js +0 -140
- package/dist/commands/skill/shared.d.ts +0 -3
- package/dist/commands/skill/shared.js +0 -19
- package/dist/commands/skill.d.ts +0 -2
- package/dist/commands/skill.js +0 -21
- package/dist/commands/tmux-spread.d.ts +0 -2
- package/dist/commands/tmux-spread.js +0 -144
- package/dist/core/__tests__/full/daemon-liveness-pane.full.test.js +0 -292
- package/dist/core/__tests__/full/placement-focus.test.js +0 -309
- package/dist/core/__tests__/full/placement-reconcile.test.js +0 -212
- package/dist/core/__tests__/full/placement-revive.test.js +0 -238
- package/dist/core/__tests__/full/placement-teardown.test.js +0 -221
- package/dist/core/__tests__/home-session.test.js +0 -186
- package/dist/core/__tests__/relaunch.test.js +0 -335
- package/dist/core/bridge-map.d.ts +0 -19
- package/dist/core/bridge-map.js +0 -73
- package/dist/core/tui/contract.d.ts +0 -83
- package/dist/core/tui/contract.js +0 -8
- package/dist/core/tui/loader.d.ts +0 -16
- package/dist/core/tui/loader.js +0 -94
- package/dist/prompts/skill.d.ts +0 -2
- package/dist/prompts/skill.js +0 -650
- /package/dist/{core/__tests__/full/daemon-liveness-pane.full.test.d.ts → clients/attach/__tests__/action-parity.test.d.ts} +0 -0
- /package/dist/{core/__tests__/full/placement-focus.test.d.ts → clients/attach/__tests__/clipboard-image.test.d.ts} +0 -0
- /package/dist/{core/__tests__/full/placement-reconcile.test.d.ts → clients/attach/__tests__/editor-newline.test.d.ts} +0 -0
- /package/dist/{core/__tests__/full/placement-revive.test.d.ts → clients/attach/__tests__/git-info.test.d.ts} +0 -0
- /package/dist/{core/__tests__/full/placement-teardown.test.d.ts → clients/attach/__tests__/onrequest-wired.test.d.ts} +0 -0
- /package/dist/{core/__tests__/home-session.test.d.ts → clients/attach/__tests__/reconnect-giveup.test.d.ts} +0 -0
- /package/dist/{core/__tests__/relaunch.test.d.ts → clients/attach/__tests__/slash-quit-copy.test.d.ts} +0 -0
|
@@ -38,71 +38,6 @@ export function rootOfSpine(nodeId) {
|
|
|
38
38
|
cur = row.parent;
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
|
-
/** The single, shared tmux session that ALL canvas node windows live in.
|
|
42
|
-
* Overridable with CRTR_NODE_SESSION (default `crtr`). Every root and every
|
|
43
|
-
* child opens a window here rather than cluttering the user's own working
|
|
44
|
-
* session — switch to it to browse the whole live graph, ignore it otherwise.
|
|
45
|
-
* Pure policy (env only, no tmux call), so it lives in the node layer, not the
|
|
46
|
-
* driver; the tmux driver imports it from here for installMenuBinding's use. */
|
|
47
|
-
export function nodeSession() {
|
|
48
|
-
const v = process.env['CRTR_NODE_SESSION'];
|
|
49
|
-
return v !== undefined && v !== '' ? v : 'crtr';
|
|
50
|
-
}
|
|
51
|
-
// ---------------------------------------------------------------------------
|
|
52
|
-
// REVIVE-HOME (home_session) — the durable session a node is (re)opened into
|
|
53
|
-
// ---------------------------------------------------------------------------
|
|
54
|
-
/** Resolve the tmux session a freshly-born node's window/pane opens into — and
|
|
55
|
-
* thus its durable REVIVE-HOME (`home_session`). Pure so the birth decision is
|
|
56
|
-
* unit-testable without a live tmux:
|
|
57
|
-
* - managed background child (`adoptCaller=false`) → the shared backstage:
|
|
58
|
-
* the inherited `CRTR_ROOT_SESSION`, else `nodeSession()` (`crtr`).
|
|
59
|
-
* - independent `--root` / inline front door (`adoptCaller=true`) → the
|
|
60
|
-
* caller's CURRENT session when inside tmux (`here`), else the backstage.
|
|
61
|
-
* This is exactly the session each birth site already places the node into;
|
|
62
|
-
* centralizing it keeps `home_session` and the actual placement in lockstep. */
|
|
63
|
-
export function resolveBirthSession(opts) {
|
|
64
|
-
const backstage = opts.rootSession !== undefined && opts.rootSession !== null && opts.rootSession !== ''
|
|
65
|
-
? opts.rootSession
|
|
66
|
-
: nodeSession();
|
|
67
|
-
if (opts.adoptCaller && opts.here !== null)
|
|
68
|
-
return opts.here.session;
|
|
69
|
-
return backstage;
|
|
70
|
-
}
|
|
71
|
-
/** A node's durable REVIVE-HOME, with the legacy back-compat default. Nodes born
|
|
72
|
-
* before `home_session` existed have no such field in meta — they fall back to
|
|
73
|
-
* their last live LOCATION (`tmux_session`), then to the shared backstage
|
|
74
|
-
* (`nodeSession()`). The defaulted read for the placement layer; a present
|
|
75
|
-
* `home_session` is always returned verbatim. */
|
|
76
|
-
export function homeSessionOf(nodeId) {
|
|
77
|
-
const meta = getNode(nodeId);
|
|
78
|
-
if (meta === null)
|
|
79
|
-
return nodeSession();
|
|
80
|
-
return meta.home_session ?? meta.tmux_session ?? nodeSession();
|
|
81
|
-
}
|
|
82
|
-
/** The session a node's CHILDREN spawn into — the value its pi process exports
|
|
83
|
-
* as CRTR_ROOT_SESSION (the subtree's backstage). NOT the same as where the
|
|
84
|
-
* node's OWN pane lives.
|
|
85
|
-
*
|
|
86
|
-
* For a managed CHILD this is its `home_session`: a child's home_session is
|
|
87
|
-
* ALWAYS the backstage it was born into (focus may move its live pane into a
|
|
88
|
-
* user session, but home_session stays the taint-immune backstage), so its
|
|
89
|
-
* descendants correctly inherit that backstage.
|
|
90
|
-
*
|
|
91
|
-
* For a ROOT (`parent === null`) `home_session` may be a USER session it
|
|
92
|
-
* ADOPTED — the inline front door keeps the root's own pane where the user is
|
|
93
|
-
* working (`home_session = cli`). Sourcing children's CRTR_ROOT_SESSION from
|
|
94
|
-
* that would exile the root's entire subtree into the user's session. A root's
|
|
95
|
-
* children must instead flow to the shared backstage `nodeSession()`, NEVER the
|
|
96
|
-
* user's session — mirroring spawnRoot's birth-time split (root pane → user
|
|
97
|
-
* session; children → nodeSession() via CRTR_ROOT_SESSION). The revive paths
|
|
98
|
-
* MUST honor the same split, or a refreshed front-door root re-points its whole
|
|
99
|
-
* subtree into the user's session on every yield (the bug this fixes). */
|
|
100
|
-
export function childBackstageOf(nodeId) {
|
|
101
|
-
const meta = getNode(nodeId);
|
|
102
|
-
if (meta !== null && meta.parent === null)
|
|
103
|
-
return nodeSession();
|
|
104
|
-
return homeSessionOf(nodeId);
|
|
105
|
-
}
|
|
106
41
|
/** Read the current node's identity from the environment. A spawned pi process
|
|
107
42
|
* runs with CRTR_NODE_ID set; its own `crtr` invocations spawn children under
|
|
108
43
|
* it by reading CRTR_NODE_ID as the parent. */
|
|
@@ -131,14 +66,9 @@ export function nodeEnv(meta) {
|
|
|
131
66
|
const home = process.env['CRTR_HOME'];
|
|
132
67
|
if (home !== undefined && home !== '')
|
|
133
68
|
env['CRTR_HOME'] = home;
|
|
134
|
-
// Propagate the root
|
|
135
|
-
//
|
|
136
|
-
|
|
137
|
-
if (rootSession !== undefined && rootSession !== '')
|
|
138
|
-
env['CRTR_ROOT_SESSION'] = rootSession;
|
|
139
|
-
// Propagate the subtree-root node id (additive in Phase 3; tmux still keys on
|
|
140
|
-
// CRTR_ROOT_SESSION). The broker uses it to group a subtree; each launch site
|
|
141
|
-
// also emits the authoritative rootOfSpine(nodeId) over this passthrough.
|
|
69
|
+
// Propagate the subtree-root node id. The broker uses it to group a subtree;
|
|
70
|
+
// each launch site also emits the authoritative rootOfSpine(nodeId) over this
|
|
71
|
+
// passthrough.
|
|
142
72
|
const subtree = process.env['CRTR_SUBTREE'];
|
|
143
73
|
if (subtree !== undefined && subtree !== '')
|
|
144
74
|
env['CRTR_SUBTREE'] = subtree;
|
|
@@ -167,7 +97,9 @@ export function spawnNode(opts) {
|
|
|
167
97
|
cycles: 0,
|
|
168
98
|
created: new Date().toISOString(),
|
|
169
99
|
cwd: opts.cwd,
|
|
170
|
-
|
|
100
|
+
// Broker is the only host: every node runs on the headless broker; a tmux
|
|
101
|
+
// pane is only an attach viewer.
|
|
102
|
+
host_kind: 'broker',
|
|
171
103
|
kind: opts.kind,
|
|
172
104
|
mode,
|
|
173
105
|
lifecycle,
|
|
@@ -1,357 +1,114 @@
|
|
|
1
|
-
import { type
|
|
2
|
-
import { homeSessionOf, childBackstageOf } from './nodes.js';
|
|
3
|
-
export { homeSessionOf, childBackstageOf };
|
|
1
|
+
import { type FocusRow } from '../canvas/index.js';
|
|
4
2
|
export type { FocusRow };
|
|
5
|
-
export {
|
|
3
|
+
export { splitWindow, focusWindow, selectWindow, switchClient, openNodeWindow, ensureSession, paneLocation, paneExists, paneRunning, paneCurrentPath, currentTmux, inTmux, installMenuBinding, setPaneOption, getPaneOption, piCommand, respawnPaneSync, closePane, windowOfPane, renameWindow, paneOfWindow, windowAlive, listLivePanes, } from './tmux.js';
|
|
6
4
|
export type { RespawnPaneOpts } from './tmux.js';
|
|
7
|
-
|
|
8
|
-
/** The focus a node occupies, or null. UNIQUE(node_id) ⇒ at most one. */
|
|
5
|
+
/** The viewer a node has on screen, or null. UNIQUE(node_id) ⇒ at most one. */
|
|
9
6
|
export declare function focusOf(nodeId: string): FocusRow | null;
|
|
10
|
-
/**
|
|
7
|
+
/** Does this node have a live viewer on screen? */
|
|
11
8
|
export declare function isFocused(nodeId: string): boolean;
|
|
12
|
-
/** The
|
|
9
|
+
/** The viewer realized by a given pane (`%id`), or null. */
|
|
13
10
|
export declare function focusByPane(pane: string): FocusRow | null;
|
|
14
|
-
/** The set of node ids currently
|
|
11
|
+
/** The set of node ids that currently have a live viewer. */
|
|
15
12
|
export declare function focusedNodes(): Set<string>;
|
|
16
|
-
/** Every
|
|
13
|
+
/** Every live viewer row (GC'ing any whose pane has gone). */
|
|
17
14
|
export declare function listFocuses(): FocusRow[];
|
|
18
|
-
/** The on-screen
|
|
19
|
-
* surface into: the HIGHEST
|
|
20
|
-
* closest to the graph root, i.e. the session/window the user is actually
|
|
15
|
+
/** The on-screen viewer a human-in-the-loop prompt raised by `nodeId` should
|
|
16
|
+
* surface into: the HIGHEST node of nodeId's graph that has a viewer — the
|
|
17
|
+
* viewer closest to the graph root, i.e. the session/window the user is actually
|
|
21
18
|
* watching this work in. Walks nodeId's spine to its root, enumerates the whole
|
|
22
|
-
* tree root-first (`view` is BFS ⇒ shallowest first), and returns the
|
|
23
|
-
* of the first node that
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
19
|
+
* tree root-first (`view` is BFS ⇒ shallowest first), and returns the viewer row
|
|
20
|
+
* of the first node that has one. null when nothing in the graph is on screen —
|
|
21
|
+
* the caller then surfaces in the user's attached pane. PURE (db reads only): no
|
|
22
|
+
* tmux probe, so the pane may be stale; the caller liveness-checks before
|
|
23
|
+
* targeting it. */
|
|
27
24
|
export declare function graphSurfaceTarget(nodeId: string): FocusRow | null;
|
|
28
|
-
/**
|
|
29
|
-
*
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
* or null when the pane is gone. Only meaningful when `cached.pane != null`.
|
|
39
|
-
* - `windowPane`: `paneOfWindow(cached.tmux_session, cached.window)` — the live
|
|
40
|
-
* window's active pane, for the legacy backfill case (`cached.pane == null`). */
|
|
41
|
-
export interface LiveProbe {
|
|
42
|
-
paneLoc: {
|
|
43
|
-
session: string;
|
|
44
|
-
window: string;
|
|
45
|
-
} | null;
|
|
46
|
-
windowPane: string | null;
|
|
47
|
-
}
|
|
48
|
-
/** The presence patch `reconcile` should write, or `{ kind: 'none' }` for a no-op.
|
|
49
|
-
* - `none` — the cache already matches reality (or there's nothing to do).
|
|
50
|
-
* - `gone` — the durable pane is gone → null the whole LOCATION.
|
|
51
|
-
* - `follow` — the pane moved (user move) → re-point the cache at its new
|
|
52
|
-
* window/session, keeping the same pane id.
|
|
53
|
-
* - `backfill` — a legacy row had no pane but a live window → adopt the
|
|
54
|
-
* window's active pane as the durable handle (begins populating
|
|
55
|
-
* `pane` for pre-existing nodes). */
|
|
56
|
-
export type ReconcileDecision = {
|
|
57
|
-
kind: 'none';
|
|
58
|
-
} | {
|
|
59
|
-
kind: 'gone';
|
|
60
|
-
} | {
|
|
61
|
-
kind: 'follow';
|
|
62
|
-
pane: string;
|
|
63
|
-
tmux_session: string;
|
|
64
|
-
window: string;
|
|
65
|
-
} | {
|
|
66
|
-
kind: 'backfill';
|
|
67
|
-
pane: string;
|
|
68
|
-
tmux_session: string;
|
|
69
|
-
window: string;
|
|
70
|
-
};
|
|
71
|
-
/** PURE reconciliation decision (§2.4) — unit-testable without a live tmux.
|
|
72
|
-
* Given the cached row LOCATION and what tmux currently reports, decide the
|
|
73
|
-
* presence patch. Mirrors the pure-core/impure-shell split (cf. `livenessVerdict`
|
|
74
|
-
* vs `handleLiveWindow`): this is the decision, `reconcile` wires it to the
|
|
75
|
-
* driver reads + `setPresence`. */
|
|
76
|
-
export declare function reconcileDecision(cached: CachedLocation, live: LiveProbe): ReconcileDecision;
|
|
77
|
-
/** Reconcile a node's LOCATION against tmux reality (§2.4) — the impure shell.
|
|
78
|
-
* Reads `row.pane`, resolves its CURRENT session/window via the driver, and
|
|
79
|
-
* writes the resulting presence patch through `setPresence` (never a raw UPDATE):
|
|
80
|
-
* - pane moved → FOLLOW (re-point window/session, keep the pane id)
|
|
81
|
-
* - pane gone → null the whole LOCATION
|
|
82
|
-
* - legacy/no pane + live window → backfill the pane from `paneOfWindow`
|
|
83
|
-
* A no-op when there's nothing to resolve (genuinely no pane, or the cache is
|
|
84
|
-
* already current). Call this before any swap/kill/focus/revive so the act lands
|
|
85
|
-
* on the pane's current window, never a stale one. */
|
|
86
|
-
export declare function reconcile(nodeId: string): void;
|
|
87
|
-
/** Reconcile a FOCUS's derived `session` cache against tmux reality (§2.4, Q4) —
|
|
88
|
-
* the focus-row analogue of `reconcile`. A focus is anchored on its durable
|
|
89
|
-
* `%pane_id`; `session` is a derived cache. If the user moved the focus pane to
|
|
90
|
-
* another session, re-point the cache so a resume-into-focus lands in the pane's
|
|
91
|
-
* CURRENT session. A no-op when the focus has no pane, the cache is already
|
|
92
|
-
* current, or the pane is GONE — in the gone case reconcileFocus does NOT null
|
|
93
|
-
* the row; the caller (reviveIntoPlacement) instead falls to the backstage
|
|
94
|
-
* branch via `paneExists(pane)` being false. */
|
|
95
|
-
export declare function reconcileFocus(focusId: string): void;
|
|
96
|
-
/** Is this node's pane (its LOCATION) alive? The v3 PRIMARY liveness probe,
|
|
97
|
-
* PURE / non-mutating so the daemon can gate on it without side effects:
|
|
98
|
-
* - `pane != null` → `paneExists(pane)` (display-message on the `%id`), so a
|
|
99
|
-
* user moving the pane to another window/session never reads as "gone".
|
|
100
|
-
* - `pane == null` → window-keyed FALLBACK (`windowAlive`) for legacy/no-pane
|
|
101
|
-
* rows that haven't been backfilled yet.
|
|
102
|
-
* Accepts a node id (re-reads the row) or a `NodeRow` already in hand. */
|
|
103
|
-
export declare function isNodePaneAlive(node: string | NodeRow): boolean;
|
|
104
|
-
/** The launch recipe `reviveIntoPlacement` plays into a pane. `command` is the
|
|
105
|
-
* full shell string (`piCommand(argv)`); `env`/`cwd`/`name` describe the
|
|
106
|
-
* window/pane; `resuming` is carried through for the caller's ReviveResult. */
|
|
107
|
-
export interface ReviveLaunch {
|
|
108
|
-
command: string;
|
|
109
|
-
env: Record<string, string>;
|
|
110
|
-
cwd: string;
|
|
111
|
-
name: string;
|
|
112
|
-
resuming: boolean;
|
|
113
|
-
}
|
|
114
|
-
/** Where a revive physically landed: the new/derived window, the session it ran
|
|
115
|
-
* in, and the durable pane id. */
|
|
116
|
-
export interface PlacementResult {
|
|
117
|
-
window: string | null;
|
|
118
|
-
session: string;
|
|
119
|
-
pane: string | null;
|
|
120
|
-
}
|
|
121
|
-
/** The PURE revive-target decision (§1.4/§5.1) — THE assertion that the
|
|
122
|
-
* "unbidden windows" bug is structurally dead. Given a node's focus (or null),
|
|
123
|
-
* whether that focus's pane is still alive, and the node's durable REVIVE-HOME
|
|
124
|
-
* (`home_session`), decide WHERE a revive must land:
|
|
125
|
-
* - occupies a LIVE focus → resume IN PLACE in that focus pane (no new window).
|
|
126
|
-
* - otherwise → a new window in `homeSession`, and NOTHING ELSE.
|
|
127
|
-
*
|
|
128
|
-
* The backstage branch's session is `homeSession` ONLY — never
|
|
129
|
-
* `meta.tmux_session`, the field focus taints to a user session. For a
|
|
130
|
-
* post-Step-1 child `homeSession` is the backstage `crtr` (never a user
|
|
131
|
-
* session), so a non-focused child — INCLUDING a once-focused-now-unfocused
|
|
132
|
-
* child whose `tmux_session` was tainted — can NEVER revive into a user session.
|
|
133
|
-
* A root's `homeSession` is its own session, so reviving a root into its own
|
|
134
|
-
* session is correct, not the bug. */
|
|
135
|
-
export type ReviveTargetDecision = {
|
|
136
|
-
kind: 'focus-pane';
|
|
137
|
-
pane: string;
|
|
138
|
-
session: string;
|
|
139
|
-
} | {
|
|
140
|
-
kind: 'backstage';
|
|
141
|
-
session: string;
|
|
142
|
-
};
|
|
143
|
-
export declare function reviveTarget(focus: FocusRow | null, focusPaneAlive: boolean, homeSession: string): ReviveTargetDecision;
|
|
144
|
-
/** Place a reviving node into its CORRECT location (§1.4) — the single decision
|
|
145
|
-
* that replaces revive.ts's old `session = meta.tmux_session ?? nodeSession()` +
|
|
146
|
-
* `openNodeWindow`. Reconcile first (§2.4), then dispatch on `reviveTarget`:
|
|
147
|
-
* - the node occupies a LIVE focus → `reconcileFocus` (resolve the pane's
|
|
148
|
-
* CURRENT session, Q4) and `respawn-pane -k` the pi INTO that focus pane —
|
|
149
|
-
* no new window (F3 resume-in-place).
|
|
150
|
-
* - otherwise → the node is NOT focused (or its focus pane already collapsed,
|
|
151
|
-
* the Step-5 limitation: remain-on-exit lands in Step 6), so it may ONLY
|
|
152
|
-
* (re)appear in its durable REVIVE-HOME: a fresh window in `homeSession`.
|
|
153
|
-
* **There is NO code path here by which a non-focused node's new-window
|
|
154
|
-
* targets a user session** — `openNodeWindow`'s session is `homeSession` and
|
|
155
|
-
* nothing else. That is the structural bug-kill.
|
|
156
|
-
*
|
|
157
|
-
* `setPresence` (the one atomic LOCATION write) records where the node landed.
|
|
158
|
-
* CRTR_ROOT_SESSION is forced to the node's children-backstage (childBackstageOf)
|
|
159
|
-
* in BOTH branches so the node's children always flow to the backstage, never
|
|
160
|
-
* into the focus session — and, for a front-door ROOT, never into the user
|
|
161
|
-
* session its own pane adopted. */
|
|
162
|
-
export declare function reviveIntoPlacement(nodeId: string, launch: ReviveLaunch): PlacementResult;
|
|
163
|
-
/** Relocate a node's still-running agent to the background `crtr` session,
|
|
164
|
-
* freeing the foreground pane WITHOUT killing the pi. `break-pane` moves the
|
|
165
|
-
* pane out of the foreground window into a fresh window in the shared backstage
|
|
166
|
-
* (the pi keeps generating); the node becomes a background window — switchable
|
|
167
|
-
* but not rendered, like any other node. Reconcile first (act on the pane's
|
|
168
|
-
* CURRENT location, §2.4) and again after (presence FOLLOWS the move). No-op
|
|
169
|
-
* (false) when there is no live pane to relocate or tmux refuses the break.
|
|
170
|
-
* `pane` is the authoritative node pane the caller acts on (the Alt+C menu's
|
|
171
|
-
* `#{pane_id}`); falls back to the node's durable handle.
|
|
172
|
-
*
|
|
173
|
-
* Invariant P gate (Bug 1): the backstage holds ONLY generating-but-unfocused
|
|
174
|
-
* nodes. A node that is NOT mid-turn (e.g. a resident root parked idle between
|
|
175
|
-
* turns, detached via Alt+C → D) must never be parked there as a live-idle pi —
|
|
176
|
-
* nothing would re-enter agent_end to release it and, with no live subscription,
|
|
177
|
-
* nothing would wake it, so it would hold a backstage pane forever, reaped by
|
|
178
|
-
* nothing. Such a node is RELEASED to dormant instead (mirrors the parked-viewer
|
|
179
|
-
* release on focus-away in retargetFocus). */
|
|
180
|
-
export declare function detachToBackground(nodeId: string, pane?: string): boolean;
|
|
181
|
-
/** A reviver: resume a DORMANT node into its backstage placement (a fresh `crtr`
|
|
182
|
-
* window via reviveIntoPlacement). Injected so placement.ts need not import
|
|
183
|
-
* revive.ts (which imports placement.ts — a cycle). The node's landed pane is
|
|
184
|
-
* read back from its row afterwards. */
|
|
25
|
+
/** Synchronously wait until a broker's view.sock accepts a connection. The spawn
|
|
26
|
+
* and focus flows are sync (the command layer calls them directly), so the
|
|
27
|
+
* readiness probe lives in a short child Node process that can use async net
|
|
28
|
+
* events while this process blocks in `spawnSync`. Success proves more than file
|
|
29
|
+
* existence: it is robust to a stale leftover socket the launching broker has
|
|
30
|
+
* not unlinked yet, because only an accepting listener exits 0. */
|
|
31
|
+
export declare function waitForBrokerViewSocket(nodeId: string): boolean;
|
|
32
|
+
/** A reviver: ensure a node's broker ENGINE is alive (idempotent → reviveNode →
|
|
33
|
+
* headlessBrokerHost.launch). Injected so placement.ts need not import revive.ts
|
|
34
|
+
* (which imports placement.ts — a cycle). */
|
|
185
35
|
export type Reviver = (nodeId: string) => void;
|
|
186
|
-
/** Result of a focus
|
|
36
|
+
/** Result of a focus op. `inPlace` = navigated to an existing viewer (no new
|
|
37
|
+
* pane); false = a fresh viewer pane was opened/moved. `revived` = this call
|
|
38
|
+
* had to (re)launch the broker engine. */
|
|
187
39
|
export interface FocusResult {
|
|
188
40
|
focused: boolean;
|
|
189
41
|
session: string | null;
|
|
190
42
|
inPlace: boolean;
|
|
191
43
|
revived: boolean;
|
|
192
44
|
}
|
|
193
|
-
/**
|
|
194
|
-
*
|
|
195
|
-
*
|
|
196
|
-
*
|
|
197
|
-
*
|
|
198
|
-
*
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
*
|
|
202
|
-
*
|
|
203
|
-
*
|
|
204
|
-
*
|
|
205
|
-
*
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
*
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
/** Open a NEW viewport (§2.3, F4) — the ONLY path a new pane appears in a user
|
|
223
|
-
* session. Default: `splitWindow(callerPane)` beside (Q3); `newWindow` opens a
|
|
224
|
-
* fresh window in the caller pane's session instead. Arms `remain-on-exit` on
|
|
225
|
-
* the new pane's window (F3) and inserts a focuses row anchored on it, occupied
|
|
226
|
-
* by a HOLDER until retargetFocus swaps a real node in. A benign long-sleep
|
|
227
|
-
* holds the pane open until the swap; retargetFocus reaps it. Returns the row,
|
|
228
|
-
* or null if tmux failed. */
|
|
229
|
-
export declare function openFocus(callerPane: string, opts?: {
|
|
230
|
-
newWindow?: boolean;
|
|
45
|
+
/** Env for a `crtr attach` VIEWER pane (the focus split, the spawn viewer
|
|
46
|
+
* window, AND recycle's re-attach respawn): propagate CRTR_HOME so the viewer
|
|
47
|
+
* resolves the SAME canvas home — and thus the right view.sock — under a
|
|
48
|
+
* non-default override; otherwise an empty env (the pane inherits the tmux
|
|
49
|
+
* server env, like every other crtr chrome pane). One helper so the viewer-pane
|
|
50
|
+
* sites can't drift. */
|
|
51
|
+
export declare function viewerSplitEnv(): Record<string, string>;
|
|
52
|
+
/** Register a `crtr attach` VIEWER pane as the node's one viewer focus row.
|
|
53
|
+
* UNIQUE(node_id) ⇒ one viewer per node: returns
|
|
54
|
+
* the existing row (no insert) when the pane or the node is already registered.
|
|
55
|
+
* `window` is accepted for the call contract (spawn passes it) but not stored —
|
|
56
|
+
* the focuses table keys on pane + session only. The attach client self-tags the
|
|
57
|
+
* pane `@crtr_node` on connect, so `nodeInPane` resolves it either way. */
|
|
58
|
+
export declare function registerViewerFocus(nodeId: string, pane: string, session: string | null, window: string | null): FocusRow | null;
|
|
59
|
+
/** Open a `crtr attach` VIEWER for `nodeId` and register its viewer focus row —
|
|
60
|
+
* the shared opener used by `focus` (a split beside the caller) and by a --root
|
|
61
|
+
* spawn (a fresh window in the caller's current session). Wraps `ensureSession`
|
|
62
|
+
* + `openNodeWindow`/`splitWindow` + `registerViewerFocus`. The attach client
|
|
63
|
+
* connects to the node's `view.sock` and renders/drives the live broker engine
|
|
64
|
+
* — it NEVER launches the engine (the one-writer invariant; the caller ensures
|
|
65
|
+
* the broker is alive first). Returns the registered viewer row, or null if tmux
|
|
66
|
+
* refused.
|
|
67
|
+
* - default → a fresh WINDOW in `session` (the --root spawn-viewer path).
|
|
68
|
+
* - `besidePane` → a SPLIT beside that pane in its own session (the focus
|
|
69
|
+
* open-beside-the-caller path); `session` is then only a fallback. */
|
|
70
|
+
export declare function openViewerWindow(nodeId: string, session: string, opts?: {
|
|
71
|
+
name?: string;
|
|
72
|
+
cwd?: string;
|
|
73
|
+
besidePane?: string;
|
|
231
74
|
}): FocusRow | null;
|
|
232
|
-
/**
|
|
233
|
-
*
|
|
234
|
-
*
|
|
235
|
-
*
|
|
236
|
-
*
|
|
237
|
-
*
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
*
|
|
241
|
-
*
|
|
242
|
-
*
|
|
243
|
-
*
|
|
244
|
-
*
|
|
245
|
-
*
|
|
246
|
-
*
|
|
247
|
-
*
|
|
248
|
-
*
|
|
249
|
-
*
|
|
250
|
-
*
|
|
251
|
-
*
|
|
252
|
-
*
|
|
253
|
-
export declare function retargetFocus(focusId: string, incoming: string, revive: Reviver): FocusResult;
|
|
254
|
-
/** The front door for `node focus` / `node cycle` (§2.3): resolve which focus the
|
|
255
|
-
* caller's pane acts on, then retarget `nodeId` onto it.
|
|
256
|
-
* - `newPane` → `openFocus` a fresh viewport beside the caller (F4), then
|
|
257
|
-
* retarget into it.
|
|
258
|
-
* - else → retarget the caller pane's focus IN PLACE (`focusByPane`); if the
|
|
259
|
-
* caller's pane is not yet a viewport, adopt it as one (occupied by whatever
|
|
260
|
-
* node sits there now — `callerNode`, else resolved by pane).
|
|
261
|
-
* - no caller pane (not in tmux) → best-effort: reconcile + report status,
|
|
262
|
-
* not-in-place (no viewport to swap into). */
|
|
75
|
+
/** Bring a node's ONE viewer pane forefront (§A.4). Every node is a detached
|
|
76
|
+
* broker, so there is no engine pane to swap into the caller's viewport — focus
|
|
77
|
+
* instead ensures the node's single `crtr attach` viewer is on screen beside (or
|
|
78
|
+
* navigated to) the caller:
|
|
79
|
+
* (a) ensure the broker ENGINE is alive (idempotent injected reviver) and its
|
|
80
|
+
* view.sock is ACCEPTING (closes the cold-start race against attach's
|
|
81
|
+
* single connect) — without this the freshly-opened viewer would exit
|
|
82
|
+
* "no broker".
|
|
83
|
+
* (b) `--new-pane` → always a fresh viewer beside the caller (e.g. two
|
|
84
|
+
* different nodes side by side); drop any prior viewer first (UNIQUE).
|
|
85
|
+
* (c) the node already has a live viewer:
|
|
86
|
+
* - in the caller's session ⇒ navigate to it (switchClient+selectWindow),
|
|
87
|
+
* no new pane (inPlace).
|
|
88
|
+
* - elsewhere (e.g. a --root's viewer in another session) ⇒ MOVE it: close the old
|
|
89
|
+
* viewer pane (the broker runs on; the fresh viewer replays full
|
|
90
|
+
* scrollback from the broker `welcome` snapshot), drop its row, reopen
|
|
91
|
+
* beside the caller.
|
|
92
|
+
* (d) no live viewer ⇒ open one beside the caller and register the row.
|
|
93
|
+
*
|
|
94
|
+
* crtr is tmux-only: with no caller pane there is no viewport to open and no
|
|
95
|
+
* non-tmux fallback — report not-focused. */
|
|
263
96
|
export declare function focus(nodeId: string, opts: {
|
|
264
97
|
pane?: string;
|
|
265
98
|
newPane?: boolean;
|
|
266
|
-
callerNode?: string;
|
|
267
99
|
revive: Reviver;
|
|
268
100
|
}): FocusResult;
|
|
269
|
-
/**
|
|
270
|
-
* is
|
|
271
|
-
*
|
|
272
|
-
*
|
|
273
|
-
*
|
|
274
|
-
* yet, because only an accepting listener exits 0. */
|
|
275
|
-
export declare function waitForBrokerViewSocket(nodeId: string): boolean;
|
|
276
|
-
/** Env for a `crtr attach` VIEWER pane (the focusBroker split AND recycle's
|
|
277
|
-
* re-attach respawn): propagate CRTR_HOME so the viewer resolves the SAME canvas
|
|
278
|
-
* home — and thus the right view.sock — under a non-default override; otherwise
|
|
279
|
-
* an empty env (the pane inherits the tmux server env, like every other crtr
|
|
280
|
-
* chrome pane). One helper so the two viewer-pane sites can't drift. */
|
|
281
|
-
export declare function viewerSplitEnv(): Record<string, string>;
|
|
282
|
-
/** Tear a node off its placement (close/reset teardown, §2.3, flow (e)).
|
|
283
|
-
* Reconcile first (follow a manual move / backfill a legacy pane), close the
|
|
284
|
-
* focus row it occupies (if any), kill its pane (pane-keyed via the durable
|
|
285
|
-
* `%id` — the window collapses once its last pane goes), and null its LOCATION.
|
|
286
|
-
* The focus row close is the record. Best-effort tmux; the
|
|
287
|
-
* DB writes always land. The pane kill is the sole teardown unit (Q1/§6: a
|
|
288
|
-
* split-pane focus returns its space to the surviving split; a standalone-window
|
|
289
|
-
* focus closes the window). */
|
|
101
|
+
/** Tear a node off its viewer (close/reset/cancel teardown). The broker engine
|
|
102
|
+
* is killed by its own host teardown over view.sock — this only closes the
|
|
103
|
+
* on-screen viewer: kill its pane (the window collapses once its last pane goes)
|
|
104
|
+
* and drop its registry row. Best-effort tmux; the DB write always lands. No-op
|
|
105
|
+
* when the node has no viewer. */
|
|
290
106
|
export declare function tearDownNode(nodeId: string): void;
|
|
291
|
-
/**
|
|
292
|
-
*
|
|
293
|
-
*
|
|
294
|
-
*
|
|
295
|
-
*
|
|
296
|
-
*
|
|
297
|
-
*
|
|
298
|
-
|
|
299
|
-
export declare function recycleFocusPane(nodeId: string, pane: string, launch: ReviveLaunch): boolean;
|
|
300
|
-
/** §1.6 lifecycle successor — hand a truly-done focused node's viewport to its
|
|
301
|
-
* manager. Repoints the focus row `focusId` to `managerId` (a DB swap of the
|
|
302
|
-
* occupant). Two takeover realizations, split on the manager's liveness:
|
|
303
|
-
* - DORMANT manager (dead pi) — ONLY when it is idle + idle-release: the row
|
|
304
|
-
* repoint is all this does; the manager, woken by the finished node's `push
|
|
305
|
-
* final` landing in its inbox, is revived by the external daemon INTO this
|
|
306
|
-
* node's now-frozen focus pane (remain-on-exit), where reviveIntoPlacement's
|
|
307
|
-
* focus-pane branch resumes it in place — no new window, no taint. A dormant
|
|
308
|
-
* manager that is NOT idle-release (done/dead/canceled, or idle with another
|
|
309
|
-
* intent) is one the daemon will NEVER revive, so this returns false WITHOUT
|
|
310
|
-
* repointing — the caller then disarms the freeze (see below).
|
|
311
|
-
* - LIVE manager (pi alive in the backstage, the normal multi-child state):
|
|
312
|
-
* the daemon never revives it (it only respawns dead-pi nodes), so we must
|
|
313
|
-
* bring it into the viewport SYNCHRONOUSLY here — swap its backstage pane
|
|
314
|
-
* into the focus slot (MAJOR 1). Otherwise the manager runs off-screen
|
|
315
|
-
* forever while %m sits orphaned in the viewport and the focus row lies
|
|
316
|
-
* about LOCATION.
|
|
317
|
-
* Returns false — the caller closes the focus (Q1: closeFocusToShell disarms
|
|
318
|
-
* remain-on-exit so the pane REAPS on exit) — whenever NO successor will claim
|
|
319
|
-
* the frozen pane: no manager, the manager IS this node, the manager already
|
|
320
|
-
* occupies another viewport (UNIQUE node_id: do NOT move it, §1.6 edge), the
|
|
321
|
-
* manager row is missing, or it is a dormant manager the daemon won't revive
|
|
322
|
-
* (not idle-release) / a live-but-paneless inline root. It does NOT repoint the
|
|
323
|
-
* occupant on any false path — repointing while returning false would strand the
|
|
324
|
-
* pane frozen forever with no reaper (the dead-focus-pane bug).
|
|
325
|
-
*
|
|
326
|
-
* Why the live swap is NOT the forbidden self-saw: `swap-pane -d` only EXCHANGES
|
|
327
|
-
* two panes' slot positions; it never respawns or kills the finishing node's own
|
|
328
|
-
* pi. The forbidden move is a synchronous `respawn-pane -k %m` from inside %m —
|
|
329
|
-
* we never do that here. After the swap, %m (the dying node's pane) sits in the
|
|
330
|
-
* manager's old backstage slot; the caller nulls this node's presence so nothing
|
|
331
|
-
* tracks the corpse. */
|
|
332
|
-
export declare function handFocusToManager(focusId: string, managerId: string | null): boolean;
|
|
333
|
-
/** Q1 close-to-shell for a truly-done focused node with no successor (§1.6 /
|
|
334
|
-
* flow (b)): close its focus row and DISARM the pane's
|
|
335
|
-
* freeze (`remain-on-exit` off) so it reaps when the finishing pi exits. The
|
|
336
|
-
* stophook calls this instead of `tearDownNode` because it runs INSIDE the pane
|
|
337
|
-
* it is closing: it cannot `closePane` its own pane (self-saw), but it is still
|
|
338
|
-
* alive to disarm the freeze, so the pane closes on exit (return-to-shell)
|
|
339
|
-
* rather than freezing into an orphan. (Keeps the stophook off the tmux driver,
|
|
340
|
-
* §2.1.) */
|
|
341
|
-
export declare function closeFocusToShell(focusId: string, nodeId: string): void;
|
|
342
|
-
export interface SpreadResult {
|
|
343
|
-
window: string | null;
|
|
344
|
-
session: string | null;
|
|
345
|
-
/** Child node ids whose panes were joined into the target window. */
|
|
346
|
-
joined: string[];
|
|
347
|
-
focused: boolean;
|
|
348
|
-
}
|
|
349
|
-
/** Join each of `childIds`' live panes into `targetId`'s window, lay them out
|
|
350
|
-
* (target wide on the left, children stacked right), and focus it. Reconcile
|
|
351
|
-
* drives both the target resolution and the per-join fix-up (a joined pane keeps
|
|
352
|
-
* its `%id` but changes window, so its LOCATION must FOLLOW — else the daemon
|
|
353
|
-
* reads it dormant). Caller revives dormant nodes first so they have live panes.
|
|
354
|
-
* No-op result when the target has no live pane. */
|
|
355
|
-
export declare function spreadNode(targetId: string, childIds: string[], opts?: {
|
|
356
|
-
mainPaneWidth?: string;
|
|
357
|
-
}): SpreadResult;
|
|
107
|
+
/** Detach a node from the foreground (the `node lifecycle --detach` / Alt+C → D
|
|
108
|
+
* half). Every node is a headless broker — the only thing on screen is its
|
|
109
|
+
* `crtr attach` VIEWER pane — so "detach" means STOP FOREGROUNDING it: close the
|
|
110
|
+
* viewer pane (and drop its row) and leave the broker engine running untouched,
|
|
111
|
+
* reconnectable by a later `focus`. `pane` is the authoritative pane the caller
|
|
112
|
+
* acts on (the Alt+C menu's `#{pane_id}`); falls back to the node's registered
|
|
113
|
+
* viewer pane. No-op (false) when there is no live viewer pane to close. */
|
|
114
|
+
export declare function detachToBackground(nodeId: string, pane?: string): boolean;
|