@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
|
@@ -17,6 +17,7 @@ export interface PromoteResult {
|
|
|
17
17
|
export declare function promote(nodeId: string, opts?: {
|
|
18
18
|
kind?: string;
|
|
19
19
|
resident?: boolean;
|
|
20
|
+
model?: string;
|
|
20
21
|
}): PromoteResult;
|
|
21
22
|
export interface YieldResult {
|
|
22
23
|
meta: NodeMeta;
|
|
@@ -32,4 +33,5 @@ export interface YieldResult {
|
|
|
32
33
|
* the daemon revives it fresh. */
|
|
33
34
|
export declare function requestYield(nodeId: string, opts?: {
|
|
34
35
|
kind?: string;
|
|
36
|
+
model?: string;
|
|
35
37
|
}): YieldResult;
|
|
@@ -36,6 +36,9 @@ export function promote(nodeId, opts = {}) {
|
|
|
36
36
|
throw new Error(`unknown node: ${nodeId}`);
|
|
37
37
|
// The node may specialize as it promotes; default to its current kind.
|
|
38
38
|
const targetKind = opts.kind ?? node.kind;
|
|
39
|
+
// ...and may raise/change its model tier; default to its current pin (so a
|
|
40
|
+
// promote with no --model preserves whatever it was running on).
|
|
41
|
+
const targetModel = opts.model ?? node.model_override ?? undefined;
|
|
39
42
|
// Rewrite the launch spec to the target kind's orchestrator persona so the
|
|
40
43
|
// *next* revive comes back orchestrating in that kind (polymorph stage 2).
|
|
41
44
|
// nodeEnv reads meta.{kind,mode}, so CRTR_KIND/CRTR_MODE flip immediately for
|
|
@@ -46,9 +49,11 @@ export function promote(nodeId, opts = {}) {
|
|
|
46
49
|
const { launch } = buildLaunchSpec(targetKind, 'orchestrator', {
|
|
47
50
|
lifecycle: opts.resident === true ? 'resident' : node.lifecycle,
|
|
48
51
|
hasManager: node.parent !== null,
|
|
49
|
-
//
|
|
50
|
-
// default is
|
|
51
|
-
|
|
52
|
+
// A model tier chosen on this call (opts.model) overrides the persona
|
|
53
|
+
// default and is persisted below; absent one, the existing pin carries
|
|
54
|
+
// across the polymorph (the persona default is recomputed fresh for
|
|
55
|
+
// targetKind).
|
|
56
|
+
model: targetModel,
|
|
52
57
|
});
|
|
53
58
|
// Seed a barebones roadmap scaffold if absent so the file exists for a
|
|
54
59
|
// refresh. Pre-fill its Goal from the node's goal doc when present (set at
|
|
@@ -67,6 +72,9 @@ export function promote(nodeId, opts = {}) {
|
|
|
67
72
|
kind: targetKind,
|
|
68
73
|
mode: 'orchestrator',
|
|
69
74
|
launch,
|
|
75
|
+
// Persist a newly-chosen tier so it is durable across future revives; omit
|
|
76
|
+
// when unchanged so the existing pin (or persona default) stands.
|
|
77
|
+
...(opts.model !== undefined ? { model_override: opts.model } : {}),
|
|
70
78
|
...(opts.resident === true ? { lifecycle: 'resident' } : {}),
|
|
71
79
|
});
|
|
72
80
|
return {
|
|
@@ -86,14 +94,24 @@ export function requestYield(nodeId, opts = {}) {
|
|
|
86
94
|
const node = getNode(nodeId);
|
|
87
95
|
if (node === null)
|
|
88
96
|
throw new Error(`unknown node: ${nodeId}`);
|
|
97
|
+
// A yield may also RESHAPE the node as it refreshes — change kind and/or raise
|
|
98
|
+
// model tier. promote() is idempotent (on an already-orchestrator node it just
|
|
99
|
+
// rewrites the launch spec), so it doubles as the apply-path for that reshape.
|
|
100
|
+
const reshaping = opts.kind !== undefined || opts.model !== undefined;
|
|
101
|
+
const wasBase = node.mode !== 'orchestrator';
|
|
89
102
|
let promoted = false;
|
|
90
|
-
if (
|
|
103
|
+
if (wasBase || reshaping) {
|
|
91
104
|
// A yield needs a ROADMAP to refresh against — i.e. orchestrator mode, not
|
|
92
105
|
// resident lifecycle. Ensure orchestrator (which seeds the roadmap + memory)
|
|
93
106
|
// WITHOUT forcing resident: a terminal/orchestrator yields fine, since the
|
|
94
107
|
// daemon's refresh-revive keys on intent='refresh', not lifecycle.
|
|
95
|
-
promote(nodeId,
|
|
96
|
-
|
|
108
|
+
promote(nodeId, {
|
|
109
|
+
...(opts.kind !== undefined ? { kind: opts.kind } : {}),
|
|
110
|
+
...(opts.model !== undefined ? { model: opts.model } : {}),
|
|
111
|
+
});
|
|
112
|
+
// "promoted" means a base node became an orchestrator — not a mere reshape
|
|
113
|
+
// of an already-orchestrator node.
|
|
114
|
+
promoted = wasBase;
|
|
97
115
|
}
|
|
98
116
|
// Mark the intent; the stophook enacts the shutdown, the daemon the revive.
|
|
99
117
|
transition(nodeId, 'yield');
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** Ask pi headlessly for a three-fragment recap of `conversation`, async. Invokes
|
|
2
|
+
* `onRecap` with the parsed fragment lines on success, or never (silent) on any
|
|
3
|
+
* failure — non-zero exit, timeout, empty/garbled output. Owns the subprocess
|
|
4
|
+
* mechanics — crucially it hands pi an immediate stdin EOF: `pi -p` reads stdin,
|
|
5
|
+
* and execFile's default stdin is an OPEN pipe that never closes, so without
|
|
6
|
+
* this pi blocks waiting for EOF and the call exits non-zero (the same gotcha
|
|
7
|
+
* naming.ts documents). */
|
|
8
|
+
export declare function generateRecap(conversation: string, onRecap: (lines: string[]) => void): void;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
// Inactivity recap — turn a dormant node's conversation into a three-fragment
|
|
2
|
+
// "where it left off" card (goal / doing-now / next) for the recap widget.
|
|
3
|
+
//
|
|
4
|
+
// One entry point: generateRecap — async (execFile, non-blocking), mirroring
|
|
5
|
+
// naming.ts's headless-`pi -p` pattern exactly. It runs Haiku over the literal
|
|
6
|
+
// back-and-forth (the caller concatenates user+assistant text) with a stripped-
|
|
7
|
+
// down pi invocation (no tools/session/context/extensions/skills), so it's fast
|
|
8
|
+
// and side-effect free and can never recurse into another spawn.
|
|
9
|
+
//
|
|
10
|
+
// Best-effort and silent on failure: a non-zero exit, timeout, empty or garbled
|
|
11
|
+
// output resolves to NO recap (the caller shows nothing). The recap is throwaway
|
|
12
|
+
// idle chrome — there is no local fallback, unlike naming, because a wrong or
|
|
13
|
+
// stale recap is worse than none.
|
|
14
|
+
//
|
|
15
|
+
// Plain TS-with-types — no imports from @earendil-works/* so it compiles inside
|
|
16
|
+
// crouter's own tsc build without a dep on the pi packages.
|
|
17
|
+
import { execFile } from 'node:child_process';
|
|
18
|
+
/** Wall-clock budget for the headless pi call before we give up (no recap). */
|
|
19
|
+
const RECAP_TIMEOUT_MS = 25_000;
|
|
20
|
+
/** Default recap model — Haiku. A recap is a one-shot summarization, so we pin
|
|
21
|
+
* the small/fast model rather than the node's heavyweight default. Override
|
|
22
|
+
* with CRTR_RECAP_MODEL (mirrors CRTR_NAME_MODEL). */
|
|
23
|
+
const DEFAULT_RECAP_MODEL = 'anthropic/claude-haiku-4-5';
|
|
24
|
+
const RECAP_SYSTEM_PROMPT = 'You write a terse "where we left off" recap of a coding-agent work session, ' +
|
|
25
|
+
'read at a glance by someone returning to a paused conversation. You are given ' +
|
|
26
|
+
'the literal back-and-forth between the user and the agent. Output EXACTLY three ' +
|
|
27
|
+
'lines, nothing else — no labels, no numbering, no bullets, no punctuation at the ' +
|
|
28
|
+
'end of a line, no prose:\n' +
|
|
29
|
+
' Line 1: the GOAL — what this session is ultimately trying to achieve.\n' +
|
|
30
|
+
' Line 2: DOING NOW — what was just happening / the active piece of work.\n' +
|
|
31
|
+
' Line 3: NEXT — the immediate next step.\n' +
|
|
32
|
+
'Each line is a short FRAGMENT, not a sentence (e.g. `wire up recap widget above editor`, ' +
|
|
33
|
+
'not `We are wiring up the recap widget.`). Keep each under ~60 characters. ' +
|
|
34
|
+
'If the session has barely started or you cannot tell, still give your best three ' +
|
|
35
|
+
'fragments from whatever text exists. Output JUST the three lines.';
|
|
36
|
+
/** Put the conversation FIRST in a delimited block, then the instruction, so the
|
|
37
|
+
* model reads the content before being told what to do. */
|
|
38
|
+
function recapUserPrompt(conversation) {
|
|
39
|
+
return `<conversation>\n${conversation}\n</conversation>\n\nWrite the three-line recap of the session above (goal / doing-now / next). Output JUST the three lines.`;
|
|
40
|
+
}
|
|
41
|
+
/** The pi argv for a headless recap request. Stripped down (no tools, session,
|
|
42
|
+
* context files, extensions, skills, templates, themes) so it's fast and
|
|
43
|
+
* side-effect free. Pinned to Haiku with thinking off. Override the model with
|
|
44
|
+
* CRTR_RECAP_MODEL. */
|
|
45
|
+
function recapArgs(conversation) {
|
|
46
|
+
const override = process.env['CRTR_RECAP_MODEL'];
|
|
47
|
+
const model = override !== undefined && override.trim() !== '' ? override.trim() : DEFAULT_RECAP_MODEL;
|
|
48
|
+
const argv = [
|
|
49
|
+
'-p',
|
|
50
|
+
'--no-session',
|
|
51
|
+
'--no-context-files',
|
|
52
|
+
'--no-extensions',
|
|
53
|
+
'--no-skills',
|
|
54
|
+
'--no-prompt-templates',
|
|
55
|
+
'--no-themes',
|
|
56
|
+
'--no-tools',
|
|
57
|
+
'--mode', 'text',
|
|
58
|
+
'--thinking', 'off',
|
|
59
|
+
'--model', model,
|
|
60
|
+
'--system-prompt', RECAP_SYSTEM_PROMPT,
|
|
61
|
+
recapUserPrompt(conversation),
|
|
62
|
+
];
|
|
63
|
+
return argv;
|
|
64
|
+
}
|
|
65
|
+
/** Parse the model's raw stdout into up to three short fragment lines. Strips any
|
|
66
|
+
* stray leading labels/bullets the model may have added despite instructions,
|
|
67
|
+
* drops empties, and hard-caps line length so a runaway line can't blow up the
|
|
68
|
+
* widget. Returns [] when nothing usable survives (→ no recap). */
|
|
69
|
+
function parseRecap(stdout) {
|
|
70
|
+
const LINE_CAP = 72;
|
|
71
|
+
const lines = stdout
|
|
72
|
+
.split('\n')
|
|
73
|
+
.map((l) => l.trim())
|
|
74
|
+
// Strip a leading `goal:` / `now:` / `next:` / `- ` / `1.` style prefix.
|
|
75
|
+
.map((l) => l.replace(/^(?:[-*•]\s*)?(?:\d+[.)]\s*)?(?:goal|now|doing(?:[\s-]now)?|next)\s*[:\-]\s*/i, '').trim())
|
|
76
|
+
.filter((l) => l !== '');
|
|
77
|
+
return lines.slice(0, 3).map((l) => (l.length > LINE_CAP ? l.slice(0, LINE_CAP) : l));
|
|
78
|
+
}
|
|
79
|
+
/** Ask pi headlessly for a three-fragment recap of `conversation`, async. Invokes
|
|
80
|
+
* `onRecap` with the parsed fragment lines on success, or never (silent) on any
|
|
81
|
+
* failure — non-zero exit, timeout, empty/garbled output. Owns the subprocess
|
|
82
|
+
* mechanics — crucially it hands pi an immediate stdin EOF: `pi -p` reads stdin,
|
|
83
|
+
* and execFile's default stdin is an OPEN pipe that never closes, so without
|
|
84
|
+
* this pi blocks waiting for EOF and the call exits non-zero (the same gotcha
|
|
85
|
+
* naming.ts documents). */
|
|
86
|
+
export function generateRecap(conversation, onRecap) {
|
|
87
|
+
const body = (conversation ?? '').trim();
|
|
88
|
+
if (body === '')
|
|
89
|
+
return;
|
|
90
|
+
try {
|
|
91
|
+
const child = execFile('pi', recapArgs(body), { encoding: 'utf8', timeout: RECAP_TIMEOUT_MS }, (err, stdout) => {
|
|
92
|
+
if (err || typeof stdout !== 'string')
|
|
93
|
+
return; // silent — no recap
|
|
94
|
+
const lines = parseRecap(stdout);
|
|
95
|
+
if (lines.length === 0)
|
|
96
|
+
return;
|
|
97
|
+
try {
|
|
98
|
+
onRecap(lines);
|
|
99
|
+
}
|
|
100
|
+
catch { /* best-effort */ }
|
|
101
|
+
});
|
|
102
|
+
child.stdin?.end(); // immediate EOF — see the doc above
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
// best-effort: no recap
|
|
106
|
+
}
|
|
107
|
+
}
|
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
//
|
|
6
6
|
// 1. Finalize — push the agent's last surfaced message as a `final` report so
|
|
7
7
|
// every subscriber/manager waiting on it is unblocked, and mark it done.
|
|
8
|
-
// 2. Close —
|
|
9
|
-
// 3. Recycle — boot a fresh resident root
|
|
8
|
+
// 2. Close — tear the agent's broker engine down (the pane is only a viewer).
|
|
9
|
+
// 3. Recycle — boot a fresh resident broker root the pane re-attaches to.
|
|
10
10
|
//
|
|
11
11
|
// NOT to be confused with `node demote` (flip-to-terminal IN PLACE, which keeps
|
|
12
12
|
// the agent focused and running): recycle ENDS this agent and boots a brand-new
|
|
@@ -17,14 +17,13 @@
|
|
|
17
17
|
// message) — falling back to a short note when it never reported.
|
|
18
18
|
import { readdirSync, readFileSync, statSync } from 'node:fs';
|
|
19
19
|
import { join } from 'node:path';
|
|
20
|
-
import { getNode, setPresence,
|
|
20
|
+
import { getNode, setPresence, setFocusOccupant, fullName } from '../canvas/index.js';
|
|
21
21
|
import { reportsDir } from '../canvas/paths.js';
|
|
22
22
|
import { pushFinal } from '../feed/feed.js';
|
|
23
|
-
import { spawnNode,
|
|
23
|
+
import { spawnNode, rootOfSpine } from './nodes.js';
|
|
24
24
|
import { buildLaunchSpec, buildPiArgv } from './launch.js';
|
|
25
|
-
import {
|
|
26
|
-
import {
|
|
27
|
-
import { hostFor } from './host.js';
|
|
25
|
+
import { focusOf, respawnPaneSync, setPaneOption, waitForBrokerViewSocket, viewerSplitEnv } from './placement.js';
|
|
26
|
+
import { headlessBrokerHost } from './host.js';
|
|
28
27
|
import { ensureDaemon } from '../../daemon/manage.js';
|
|
29
28
|
/** The agent's most recent surfaced message: the newest reports/*.md body with
|
|
30
29
|
* its YAML frontmatter stripped. Empty string when the node never reported. */
|
|
@@ -74,19 +73,15 @@ export async function recycleNode(nodeId, callerPane) {
|
|
|
74
73
|
finalized = true;
|
|
75
74
|
}
|
|
76
75
|
catch { /* recycle the pane even if the report failed */ }
|
|
77
|
-
//
|
|
78
|
-
//
|
|
79
|
-
// viewer, never the engine.
|
|
80
|
-
//
|
|
81
|
-
//
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
if (isBroker) {
|
|
85
|
-
try {
|
|
86
|
-
hostFor(meta).teardown(nodeId);
|
|
87
|
-
}
|
|
88
|
-
catch { /* best-effort */ }
|
|
76
|
+
// The node's pane is a VIEWER (`crtr attach`), not its engine: the engine is
|
|
77
|
+
// the detached broker process, so respawn-pane -k below would only kill the
|
|
78
|
+
// viewer, never the engine. Tear the broker PROCESS down so it exits and
|
|
79
|
+
// releases the sole .jsonl writer. Status is already flipped done by pushFinal
|
|
80
|
+
// above (crash-safe order: the daemon won't revive a done node).
|
|
81
|
+
try {
|
|
82
|
+
headlessBrokerHost.teardown(nodeId);
|
|
89
83
|
}
|
|
84
|
+
catch { /* best-effort */ }
|
|
90
85
|
// Capture M's focus viewport (if any) BEFORE nulling — the fresh root inherits
|
|
91
86
|
// it (the SAME focus row + pane). The demoted node no longer holds a pane: it is
|
|
92
87
|
// being reclaimed.
|
|
@@ -95,17 +90,13 @@ export async function recycleNode(nodeId, callerPane) {
|
|
|
95
90
|
setPresence(nodeId, { pane: null, window: null, tmux_session: null });
|
|
96
91
|
}
|
|
97
92
|
catch { /* best-effort */ }
|
|
98
|
-
// 2 + 3. Recycle — boot a fresh resident root for the SAME pane
|
|
99
|
-
//
|
|
100
|
-
// pane
|
|
101
|
-
// (broker-is-the-host — the viewer pane stays a viewer, never becomes an engine
|
|
102
|
-
// pane). Without preserving host_kind, recycling a broker node from its viewer
|
|
103
|
-
// would silently respawn the viewer into a tmux pi root.
|
|
93
|
+
// 2 + 3. Recycle — boot a fresh resident BROKER root for the SAME pane: the
|
|
94
|
+
// viewer pane re-attaches to the fresh broker (broker-is-the-host — the viewer
|
|
95
|
+
// pane stays a viewer, never becomes an engine pane).
|
|
104
96
|
try {
|
|
105
97
|
ensureDaemon();
|
|
106
98
|
}
|
|
107
99
|
catch { /* daemon is best-effort */ }
|
|
108
|
-
const loc = paneLocation(pane);
|
|
109
100
|
const { launch } = buildLaunchSpec('general', 'base', { lifecycle: 'resident', hasManager: false });
|
|
110
101
|
const root = spawnNode({
|
|
111
102
|
kind: 'general',
|
|
@@ -115,12 +106,7 @@ export async function recycleNode(nodeId, callerPane) {
|
|
|
115
106
|
name: 'general',
|
|
116
107
|
parent: null,
|
|
117
108
|
launch,
|
|
118
|
-
hostKind: isBroker ? 'broker' : 'tmux',
|
|
119
109
|
});
|
|
120
|
-
// REVIVE-HOME: a recycled root's durable revive target is the session
|
|
121
|
-
// of the pane it was recycled into (the one place home_session is rewritten
|
|
122
|
-
// after birth). Falls back to the backstage when the pane can't be located.
|
|
123
|
-
updateNode(root.node_id, { home_session: loc?.session ?? nodeSession() });
|
|
124
110
|
// Hand the viewport to the fresh root: reuse M's focus row over the SAME pane
|
|
125
111
|
// (respawn-pane -k below keeps the %id), so the user keeps watching this slot.
|
|
126
112
|
if (f !== null) {
|
|
@@ -131,33 +117,12 @@ export async function recycleNode(nodeId, callerPane) {
|
|
|
131
117
|
}
|
|
132
118
|
const fresh = getNode(root.node_id);
|
|
133
119
|
const inv = buildPiArgv(fresh);
|
|
134
|
-
//
|
|
135
|
-
//
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
inv.env = { ...inv.env, CRTR_ROOT_SESSION: nodeSession(), CRTR_SUBTREE: rootOfSpine(root.node_id) };
|
|
139
|
-
const ok = isBroker
|
|
140
|
-
? recycleBrokerViewer(fresh, pane, inv)
|
|
141
|
-
: recycleTmuxRoot(root.node_id, pane, {
|
|
142
|
-
command: piCommand(inv.argv),
|
|
143
|
-
env: { ...inv.env, [FRONT_DOOR_ENV]: '1' },
|
|
144
|
-
cwd: meta.cwd,
|
|
145
|
-
name: fullName(fresh),
|
|
146
|
-
});
|
|
120
|
+
// CRTR_SUBTREE groups the fresh root's subtree; FRONT_DOOR is set by the broker
|
|
121
|
+
// host itself, so it is not added here.
|
|
122
|
+
inv.env = { ...inv.env, CRTR_SUBTREE: rootOfSpine(root.node_id) };
|
|
123
|
+
const ok = recycleBrokerViewer(fresh, pane, inv);
|
|
147
124
|
return { recycled: ok, finalized, newRoot: root.node_id, delivered };
|
|
148
125
|
}
|
|
149
|
-
/** Recycle a TMUX root into `pane`: respawn-pane -k boots the fresh pi engine in
|
|
150
|
-
* place. Clears any stale `@crtr_node` viewer tag first — a prior `crtr attach`
|
|
151
|
-
* in this pane may have left one (tmux pane options survive respawn-pane), and
|
|
152
|
-
* since nodeInPane checks the tag BEFORE the window, a stale tag would shadow
|
|
153
|
-
* the real window→node lookup for the fresh tmux engine now in the pane. */
|
|
154
|
-
function recycleTmuxRoot(nodeId, pane, launch) {
|
|
155
|
-
try {
|
|
156
|
-
setPaneOption(pane, '@crtr_node', '');
|
|
157
|
-
}
|
|
158
|
-
catch { /* best-effort */ }
|
|
159
|
-
return recycleFocusPane(nodeId, pane, { ...launch, resuming: false });
|
|
160
|
-
}
|
|
161
126
|
/** Recycle a BROKER root into `pane`: the fresh root is broker-hosted, so its
|
|
162
127
|
* engine runs in a DETACHED broker, not the pane. Birth-launch that broker via
|
|
163
128
|
* the Host seam (mirrors spawnChild's birth path — the host records its pid),
|
|
@@ -167,13 +132,12 @@ function recycleTmuxRoot(nodeId, pane, launch) {
|
|
|
167
132
|
* pane was not respawned) when the broker never serves — the fresh root row
|
|
168
133
|
* still exists, broker-hosted, for the daemon to revive. */
|
|
169
134
|
function recycleBrokerViewer(fresh, pane, inv) {
|
|
170
|
-
|
|
135
|
+
headlessBrokerHost.launch(fresh.node_id, inv, { cwd: fresh.cwd, name: fullName(fresh), resuming: false });
|
|
171
136
|
if (!waitForBrokerViewSocket(fresh.node_id))
|
|
172
137
|
return false;
|
|
173
|
-
// Clear the finalized node's stale `@crtr_node` tag before respawn
|
|
174
|
-
//
|
|
175
|
-
//
|
|
176
|
-
// identifiers; no quoting needed.
|
|
138
|
+
// Clear the finalized node's stale `@crtr_node` tag before respawn so the tag
|
|
139
|
+
// never names a done node during the gap before the new `crtr attach` re-tags
|
|
140
|
+
// on connect. Node ids are shell-safe identifiers; no quoting needed.
|
|
177
141
|
try {
|
|
178
142
|
setPaneOption(pane, '@crtr_node', '');
|
|
179
143
|
}
|
|
@@ -1,56 +1,62 @@
|
|
|
1
|
+
import { headlessBrokerHost } from './host.js';
|
|
2
|
+
import { respawnPaneSync } from './placement.js';
|
|
1
3
|
/** Reap the descendant sub-DAG of `rootId`: mark each **canceled** (the user
|
|
2
4
|
* moved on — a clean teardown, NOT a fault) + clear intent FIRST, then kill its
|
|
3
5
|
* window (closes the daemon revive race). Edges are LEFT INTACT — descendants
|
|
4
6
|
* keep parent=rootId. No wipe. Returns the reaped ids.
|
|
5
7
|
*
|
|
6
8
|
* Why `canceled` (A5, human-confirmed 2026-06-06): an externally-reaped node —
|
|
7
|
-
* whether via `node close` OR a root reset
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* same `cancel` event the close cascade uses. Shared by relaunchRoot (option C)
|
|
13
|
-
* and resetRoot's in-place fallback, so both leave their descendants `canceled`. */
|
|
9
|
+
* whether via `node close` OR a root reset — did not finish its OWN work, so it
|
|
10
|
+
* unifies on `canceled`; `done` is reserved for finalize. Why marking is STILL
|
|
11
|
+
* explicit: an abrupt broker teardown fires NO clean `session_shutdown`, so the
|
|
12
|
+
* general quit→done rule does NOT auto-resolve a force-killed descendant — we
|
|
13
|
+
* mark it `canceled` here via the same `cancel` event the close cascade uses. */
|
|
14
14
|
export declare function reapDescendants(rootId: string): string[];
|
|
15
|
+
/** Injectable host/viewer seam, so the fast-tier test drives relaunchRoot's pure
|
|
16
|
+
* DB transitions without a real broker or tmux. Each field defaults to its
|
|
17
|
+
* production verb. */
|
|
18
|
+
export interface RelaunchDeps {
|
|
19
|
+
/** Boot the new node's detached broker engine. Default: headlessBrokerHost.launch. */
|
|
20
|
+
launchBroker?: typeof headlessBrokerHost.launch;
|
|
21
|
+
/** Wait for the new broker's view.sock to accept. Default: waitForBrokerViewSocket. */
|
|
22
|
+
waitForViewSocket?: (nodeId: string) => boolean;
|
|
23
|
+
/** Re-exec the viewer pane onto the new node. Default: respawnPaneSync. */
|
|
24
|
+
respawnViewer?: typeof respawnPaneSync;
|
|
25
|
+
/** Tear the old broker down. Default: headlessBrokerHost.teardown. */
|
|
26
|
+
teardownBroker?: typeof headlessBrokerHost.teardown;
|
|
27
|
+
}
|
|
28
|
+
export interface RelaunchRootResult {
|
|
29
|
+
/** The freshly-minted node now driving this pane. */
|
|
30
|
+
newNodeId: string;
|
|
31
|
+
}
|
|
32
|
+
/** Relaunch a ROOT on `/new`: park the old root `done` (kept as history) and
|
|
33
|
+
* mint a fresh node id + broker in the same pane/cwd, re-pointing the viewer at
|
|
34
|
+
* it. The new broker is booted FIRST and its pid confirmed BEFORE the old root
|
|
35
|
+
* is touched, so any pre-commit failure leaves the old root fully intact and
|
|
36
|
+
* live. Returns null when `oldId` is not a relaunchable root (unknown, a child,
|
|
37
|
+
* or already parked), or when the new broker failed to launch. */
|
|
38
|
+
export declare function relaunchRoot(oldId: string, deps?: RelaunchDeps): RelaunchRootResult | null;
|
|
15
39
|
export interface ResetRootResult {
|
|
16
|
-
/** Descendant node ids torn down
|
|
40
|
+
/** Descendant node ids torn down. Always empty — a child `/new` reaps nothing. */
|
|
17
41
|
reaped: string[];
|
|
18
|
-
/** Direct subscriptions dropped
|
|
42
|
+
/** Direct subscriptions dropped. Always empty — a child `/new` detaches nothing. */
|
|
19
43
|
detached: string[];
|
|
20
|
-
/**
|
|
44
|
+
/** Always false — a child `/new` is not a graph reset (roots route to relaunchRoot). */
|
|
21
45
|
reset: boolean;
|
|
22
46
|
}
|
|
23
|
-
/**
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
* refresh its session id so a later `--session <id>` wakes the right conversation. */
|
|
47
|
+
/** Refresh a non-root child's pi session id on `/new`, so a later
|
|
48
|
+
* `--session <id>` wakes the right conversation. A `/new` on a child is NOT a
|
|
49
|
+
* graph reset — a root's `/new` is handled by relaunchRoot, never here; a root
|
|
50
|
+
* that reaches this is a no-op. */
|
|
28
51
|
export declare function resetRoot(nodeId: string, newSessionId?: string, newSessionFile?: string | null): ResetRootResult;
|
|
29
|
-
|
|
30
|
-
export interface RelaunchDeps {
|
|
31
|
-
relaunchRootInPane?: (nodeId: string, pane: string) => void;
|
|
32
|
-
}
|
|
33
|
-
export type HandleNewSessionPath = 'relaunch' | 'reset-root' | 'reset-child' | 'noop';
|
|
52
|
+
export type HandleNewSessionPath = 'reset-child' | 'noop';
|
|
34
53
|
export interface HandleNewSessionResult {
|
|
35
54
|
path: HandleNewSessionPath;
|
|
36
|
-
newNodeId?: string;
|
|
37
55
|
}
|
|
38
|
-
/** The
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
|
|
42
|
-
* - root + no pane (no tmux) → resetRoot(nodeId, newSessionId) (in-place fallback)
|
|
43
|
-
* On a respawn-dispatch failure the live pi never died, so we degrade to the
|
|
44
|
-
* legacy in-place reset. */
|
|
45
|
-
export declare function handleNewSession(nodeId: string, newSessionId: string, pane: string | undefined, deps?: RelaunchDeps, newSessionFile?: string | null): HandleNewSessionResult;
|
|
46
|
-
/** Park the old root + create+launch a fresh root in `pane` (option C). All DB
|
|
47
|
-
* writes are synchronous and happen BEFORE the respawn (the respawn kills the
|
|
48
|
-
* caller). Returns the new node id, or null on a defensive guard (not a root /
|
|
49
|
-
* already parked). Throws only if the respawn dispatch fails — and self-rolls-
|
|
50
|
-
* back its writes first so the caller can degrade to resetRoot. */
|
|
51
|
-
export declare function relaunchRoot(oldId: string, pane: string, deps?: RelaunchDeps): {
|
|
52
|
-
newNodeId: string;
|
|
53
|
-
} | null;
|
|
56
|
+
/** The child-side `/new` entry the stophook calls (the root side goes to
|
|
57
|
+
* relaunchRoot directly). The broker already drove the engine-side new_session;
|
|
58
|
+
* this only refreshes the child's session id on the SAME node id. */
|
|
59
|
+
export declare function handleNewSession(nodeId: string, newSessionId: string, newSessionFile?: string | null): HandleNewSessionResult;
|
|
54
60
|
/** Resolve a cleanly-exiting node to `done`. Returns true iff it transitioned.
|
|
55
61
|
* Guard: only a real quit, and only a node still active|idle with no pending
|
|
56
62
|
* intent — so it never clobbers a node already routed by agent_end to done
|