@north-light/crouter 0.3.172 → 0.3.174
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/bin/runtime-selector.mjs +8 -1
- package/dist/api/__tests__/{client.test.js → serial/client.test.js} +2 -135
- package/dist/api/client.d.ts +12 -21
- package/dist/api/client.js +22 -31
- package/dist/api/dto/broker-ops.d.ts +158 -0
- package/dist/api/dto/broker-ops.js +6 -0
- package/dist/api/dto/crons.d.ts +6 -0
- package/dist/api/dto/human.d.ts +7 -1
- package/dist/api/dto/inbox.d.ts +1 -71
- package/dist/api/dto/inbox.js +1 -9
- package/dist/api/dto/nodes.d.ts +6 -7
- package/dist/api/dto/reviews.d.ts +1 -11
- package/dist/api/routes.d.ts +7 -4
- package/dist/api/routes.js +8 -5
- package/dist/build-root.js +3 -3
- package/dist/builtin-memory/04-base-worker.md +1 -4
- package/dist/builtin-memory/05-kinds/advisor/00-base.md +1 -5
- package/dist/builtin-memory/05-kinds/advisor/01-orchestrator.md +2 -7
- package/dist/builtin-memory/05-kinds/design/00-base.md +1 -6
- package/dist/builtin-memory/05-kinds/developer/00-base.md +1 -6
- package/dist/builtin-memory/05-kinds/explore/00-base.md +1 -4
- package/dist/builtin-memory/05-kinds/explore/01-orchestrator.md +1 -2
- package/dist/builtin-memory/05-kinds/general/00-base.md +1 -3
- package/dist/builtin-memory/05-kinds/plan/00-base.md +1 -6
- package/dist/builtin-memory/05-kinds/plan/reviewers/00-base.md +1 -2
- package/dist/builtin-memory/05-kinds/plan/reviewers/architecture-fit.md +1 -3
- package/dist/builtin-memory/05-kinds/plan/reviewers/code-smells.md +1 -3
- package/dist/builtin-memory/05-kinds/plan/reviewers/pattern-consistency.md +1 -3
- package/dist/builtin-memory/05-kinds/plan/reviewers/requirements-coverage.md +1 -3
- package/dist/builtin-memory/05-kinds/plan/reviewers/security.md +1 -4
- package/dist/builtin-memory/05-kinds/review/companion/00-base.md +2 -3
- package/dist/builtin-memory/05-kinds/spec/00-base.md +1 -2
- package/dist/builtin-memory/advisor/council.md +1 -6
- package/dist/builtin-memory/design.md +2 -7
- package/dist/builtin-memory/development.md +9 -14
- package/dist/builtin-memory/internal/marketplaces.md +2 -6
- package/dist/builtin-memory/internal/nodes-and-canvas.md +1 -1
- package/dist/builtin-memory/internal/plugins.md +2 -8
- package/dist/builtin-memory/internal/storage-tiers.md +1 -2
- package/dist/builtin-memory/testing.md +41 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/__tests__/{provider-rotation.test.ts → serial/provider-rotation.test.ts} +106 -177
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/claude-plugin-commands.ts +5 -15
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/frontmatter-rules/index.ts +1 -28
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/memory-slash-commands.ts +43 -88
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.js +55 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.ts +60 -0
- package/dist/cli.js +2 -2
- package/dist/clients/attach/__tests__/attach-remote-readonly.test.js +37 -131
- package/dist/clients/attach/__tests__/chat-view-snapshot-ordering.test.js +71 -152
- package/dist/clients/attach/__tests__/context-message.test.js +16 -174
- package/dist/clients/attach/__tests__/crtr-output.test.js +36 -2069
- package/dist/clients/attach/__tests__/diagram.test.js +2 -2
- package/dist/clients/attach/__tests__/edit-diff.test.js +0 -4
- package/dist/clients/attach/__tests__/file-review-focus.test.js +2 -1
- package/dist/clients/attach/__tests__/group-activity.test.js +40 -229
- package/dist/clients/attach/__tests__/oauth-dialog-lifecycle.test.js +26 -76
- package/dist/clients/attach/__tests__/prompt-preview.test.js +4 -70
- package/dist/clients/attach/__tests__/ref-autocomplete.test.js +11 -125
- package/dist/clients/attach/__tests__/titled-editor-preview.test.js +14 -205
- package/dist/clients/attach/command.d.ts +2 -1
- package/dist/clients/attach/command.js +81 -76
- package/dist/clients/attach/input/capabilities.d.ts +27 -0
- package/dist/clients/attach/input/capabilities.js +96 -0
- package/dist/clients/attach/input/controller.d.ts +20 -182
- package/dist/clients/attach/input/controller.js +128 -537
- package/dist/clients/attach/input/overlay-owner.d.ts +41 -0
- package/dist/clients/attach/input/overlay-owner.js +199 -0
- package/dist/clients/attach/overlays/file-review.d.ts +0 -4
- package/dist/clients/attach/overlays/file-review.js +13 -5
- package/dist/clients/attach/overlays/graph.js +2 -10
- package/dist/clients/attach/render/chat-view.d.ts +4 -3
- package/dist/clients/attach/render/chat-view.js +39 -33
- package/dist/clients/attach/render/group-activity.d.ts +1 -0
- package/dist/clients/attach/render/group-activity.js +20 -13
- package/dist/clients/attach/render/group-recap.js +12 -3
- package/dist/clients/attach/session/connection.js +9 -15
- package/dist/clients/attach/session/editor-inventory.d.ts +6 -5
- package/dist/clients/attach/session/editor-inventory.js +7 -8
- package/dist/clients/attach/session/file-links.d.ts +13 -0
- package/dist/clients/attach/session/file-links.js +107 -0
- package/dist/clients/attach/session/frame.d.ts +3 -0
- package/dist/clients/attach/session/frame.js +10 -1
- package/dist/clients/attach/session/frames.js +2 -3
- package/dist/clients/attach/session/input-wiring.d.ts +4 -1
- package/dist/clients/attach/session/input-wiring.js +15 -14
- package/dist/clients/attach/session/mouse.d.ts +6 -1
- package/dist/clients/attach/session/mouse.js +8 -5
- package/dist/clients/attach/session/profile-files.js +18 -12
- package/dist/clients/attach/session/reconnect.js +1 -1
- package/dist/clients/attach/session/state-sync.js +1 -2
- package/dist/clients/attach/session/surface-host.d.ts +3 -2
- package/dist/clients/attach/session/surface-host.js +4 -4
- package/dist/clients/attach/slash/dispatch.d.ts +8 -31
- package/dist/clients/attach/slash/dispatch.js +34 -81
- package/dist/clients/attach/viewer.js +820 -860
- package/dist/clients/conversation/projection.d.ts +79 -0
- package/dist/clients/conversation/projection.js +341 -0
- package/dist/clients/inbox/__tests__/serial/inbox-controller.test.js +159 -0
- package/dist/clients/inbox/__tests__/serial/mount-panel.test.js +151 -0
- package/dist/clients/inbox/controller.d.ts +0 -4
- package/dist/clients/inbox/controller.js +0 -2
- package/dist/clients/inbox/review/__tests__/review-core.test.js +4 -293
- package/dist/clients/inbox/review/__tests__/teardown-notice.test.js +100 -0
- package/dist/clients/inbox/review/comments-client.d.ts +3 -2
- package/dist/clients/inbox/review/comments-client.js +12 -12
- package/dist/clients/inbox/review/companion-pane.d.ts +30 -0
- package/dist/clients/inbox/review/companion-pane.js +86 -0
- package/dist/clients/inbox/review/document-surface.d.ts +182 -0
- package/dist/clients/inbox/review/{document-region.js → document-surface.js} +252 -48
- package/dist/clients/inbox/review/frame.js +5 -4
- package/dist/clients/inbox/review/launch.d.ts +8 -8
- package/dist/clients/inbox/review/launch.js +52 -92
- package/dist/clients/inbox/review/nvim.d.ts +2 -0
- package/dist/clients/inbox/review/nvim.js +14 -12
- package/dist/clients/inbox/review/review-client.d.ts +12 -8
- package/dist/clients/inbox/review/review-client.js +46 -35
- package/dist/clients/inbox/review-adapter.d.ts +3 -10
- package/dist/clients/inbox/review-adapter.js +27 -19
- package/dist/clients/inbox/surface.d.ts +0 -4
- package/dist/clients/inbox/surface.js +0 -2
- package/dist/clients/surfaces/host.d.ts +11 -3
- package/dist/commands/__tests__/api-client-cold-start-diagnostic.test.js +7 -34
- package/dist/commands/__tests__/human.test.js +11 -322
- package/dist/commands/api-client.d.ts +5 -5
- package/dist/commands/api-client.js +6 -85
- package/dist/commands/canvas-browse.js +3 -29
- package/dist/commands/canvas-config.js +1 -1
- package/dist/commands/canvas-use.js +3 -3
- package/dist/commands/canvas.js +1 -1
- package/dist/commands/cron.js +5 -1
- package/dist/commands/human/queue.d.ts +0 -4
- package/dist/commands/human/queue.js +7 -40
- package/dist/commands/memory/list.d.ts +14 -0
- package/dist/commands/memory/list.js +35 -31
- package/dist/commands/memory/read.d.ts +7 -0
- package/dist/commands/memory/read.js +14 -8
- package/dist/commands/node/bash.d.ts +1 -0
- package/dist/commands/node/bash.js +198 -0
- package/dist/commands/node/create.d.ts +23 -0
- package/dist/commands/node/create.js +207 -0
- package/dist/commands/node/inspect.d.ts +2 -0
- package/dist/commands/node/inspect.js +302 -0
- package/dist/commands/node/lifecycle.d.ts +4 -0
- package/dist/commands/node/lifecycle.js +415 -0
- package/dist/commands/node/message.d.ts +1 -0
- package/dist/commands/node/message.js +164 -0
- package/dist/commands/node/pyramid.d.ts +2 -0
- package/dist/commands/node/pyramid.js +79 -0
- package/dist/commands/node/subscription.d.ts +1 -0
- package/dist/commands/node/subscription.js +82 -0
- package/dist/commands/node/wait.d.ts +1 -0
- package/dist/commands/node/wait.js +159 -0
- package/dist/commands/node-lifecycle-revive.js +10 -57
- package/dist/commands/node.d.ts +0 -42
- package/dist/commands/node.js +11 -2065
- package/dist/commands/search.js +1 -1
- package/dist/commands/surface/node/cycle.d.ts +1 -0
- package/dist/commands/surface/node/cycle.js +83 -0
- package/dist/commands/surface/node/focus.d.ts +1 -0
- package/dist/commands/surface/node/focus.js +67 -0
- package/dist/commands/surface/node/id.d.ts +1 -0
- package/dist/commands/surface/node/id.js +38 -0
- package/dist/commands/surface/node/pin.d.ts +1 -0
- package/dist/commands/surface/node/pin.js +42 -0
- package/dist/commands/surface/node/placement.d.ts +46 -0
- package/dist/commands/surface/node/placement.js +124 -0
- package/dist/commands/surface-node.js +4 -1
- package/dist/commands/surface-reload.js +1 -2
- package/dist/commands/surface-tmux-spread.js +1 -1
- package/dist/commands/surface.js +5 -20
- package/dist/commands/sys/__tests__/setup-core.test.js +18 -271
- package/dist/commands/sys/config.js +6 -6
- package/dist/commands/sys/logs.js +1 -1
- package/dist/commands/sys/panels/broker-limits-panel.d.ts +17 -0
- package/dist/commands/sys/panels/broker-limits-panel.js +104 -0
- package/dist/commands/sys/panels/dependencies-panel.d.ts +14 -0
- package/dist/commands/sys/panels/dependencies-panel.js +80 -0
- package/dist/commands/sys/panels/keybindings-panel.d.ts +56 -0
- package/dist/commands/sys/panels/keybindings-panel.js +703 -0
- package/dist/commands/sys/panels/keys-panel.d.ts +16 -0
- package/dist/commands/sys/panels/keys-panel.js +60 -0
- package/dist/commands/sys/panels/models-panel.d.ts +77 -0
- package/dist/commands/sys/panels/models-panel.js +647 -0
- package/dist/commands/sys/panels/panel.d.ts +45 -0
- package/dist/commands/sys/panels/panel.js +137 -0
- package/dist/commands/sys/panels/plugins-panel.d.ts +16 -0
- package/dist/commands/sys/panels/plugins-panel.js +80 -0
- package/dist/commands/sys/panels/prefs-panel.d.ts +21 -0
- package/dist/commands/sys/panels/prefs-panel.js +85 -0
- package/dist/commands/sys/panels/provider-panel.d.ts +62 -0
- package/dist/commands/sys/panels/provider-panel.js +538 -0
- package/dist/commands/sys/settings-shell.d.ts +55 -0
- package/dist/commands/sys/settings-shell.js +400 -0
- package/dist/commands/sys/settings.d.ts +2 -0
- package/dist/commands/sys/settings.js +31 -0
- package/dist/commands/sys/setup-core.d.ts +3 -33
- package/dist/commands/sys/setup-core.js +27 -78
- package/dist/commands/sys/setup-settings-runner.d.ts +24 -0
- package/dist/commands/sys/setup-settings-runner.js +63 -0
- package/dist/commands/sys/setup-wizard.d.ts +26 -125
- package/dist/commands/sys/setup-wizard.js +209 -2473
- package/dist/commands/sys/setup.js +5 -7
- package/dist/commands/sys.js +3 -2
- package/dist/core/__tests__/broker-extension-canvas-db-boundary.test.js +50 -0
- package/dist/core/__tests__/broker-launch-candidates.test.js +20 -9
- package/dist/core/__tests__/broker-preflight.test.js +1 -1
- package/dist/core/__tests__/canvas-inbox-watcher-hold.test.js +108 -27
- package/dist/core/__tests__/canvas-inbox-watcher.test.js +14 -0
- package/dist/core/__tests__/canvas.test.js +2 -36
- package/dist/core/__tests__/close.test.js +14 -3
- package/dist/core/__tests__/context-intro.test.js +32 -143
- package/dist/core/__tests__/cron-broker-capacity.test.js +22 -3
- package/dist/core/__tests__/daemon-boot.test.js +2 -20
- package/dist/core/__tests__/daemon-wedge.test.js +1 -1
- package/dist/core/__tests__/dead-node-policy-table.test.js +1 -18
- package/dist/core/__tests__/fixtures/fake-engine.d.ts +1 -1
- package/dist/core/__tests__/fixtures/fake-engine.js +2 -2
- package/dist/core/__tests__/fixtures/fake-pi-host.js +2 -2
- package/dist/core/__tests__/focuses.test.js +4 -98
- package/dist/core/__tests__/helpers/broker-clients.d.ts +0 -3
- package/dist/core/__tests__/helpers/broker-clients.js +0 -14
- package/dist/core/__tests__/helpers/harness.d.ts +0 -8
- package/dist/core/__tests__/helpers/harness.js +7 -87
- package/dist/core/__tests__/helpers/viewer-panes.js +1 -1
- package/dist/core/__tests__/inline-memory-refs.test.js +5 -134
- package/dist/core/__tests__/kickoff.test.js +1 -1
- package/dist/core/__tests__/memory-resolver-precedence.test.js +29 -1
- package/dist/core/__tests__/migration.test.js +35 -48
- package/dist/core/__tests__/on-read-dedup-resume.test.js +22 -12
- package/dist/core/__tests__/passive-subscription.test.js +26 -49
- package/dist/core/__tests__/preview-registry-sync.test.js +1 -2
- package/dist/core/__tests__/prune.test.js +94 -1
- package/dist/core/__tests__/review-model-floor.test.js +0 -32
- package/dist/core/__tests__/seam/broker-attach-multiclient.test.js +255 -0
- package/dist/core/__tests__/{full → seam}/broker-attach-stream.test.js +39 -7
- package/dist/core/__tests__/{full → seam}/broker-crash-teardown.test.js +30 -29
- package/dist/core/__tests__/{full → seam}/broker-pane-resolution.test.js +54 -5
- package/dist/core/__tests__/{full → seam}/broker-provider-retry.test.js +134 -82
- package/dist/core/__tests__/{full → seam}/broker-whip-interrupt.test.js +15 -4
- package/dist/core/__tests__/{full/idle-release-settlement.test.js → seam/dormancy-release.test.js} +69 -17
- package/dist/core/__tests__/{full/yield-message-transaction.test.js → seam/yield-refresh-transaction.test.js} +31 -9
- package/dist/core/__tests__/secrets.test.js +1 -7
- package/dist/core/__tests__/{broker-fork-seam.test.js → serial/broker-fork-seam.test.js} +58 -7
- package/dist/core/__tests__/{broker-sdk-wiring.test.js → serial/broker-sdk-wiring.test.js} +18 -162
- package/dist/core/__tests__/{broker-snapshot-history.test.js → serial/broker-snapshot-history.test.js} +9 -9
- package/dist/core/__tests__/{command-plugins.test.js → serial/command-plugins.test.js} +105 -15
- package/dist/core/__tests__/{deferred-no-wake.test.js → serial/deferred-no-wake.test.js} +23 -20
- package/dist/core/__tests__/{flagship-lifecycle.test.js → serial/flagship-lifecycle.test.js} +7 -7
- package/dist/core/__tests__/{host-teardown-process-group.test.js → serial/host-teardown-process-group.test.js} +6 -6
- package/dist/core/__tests__/{human-deliver-e2e.test.js → serial/human-deliver-e2e.test.js} +12 -12
- package/dist/core/__tests__/{live-mutation.test.js → serial/live-mutation.test.js} +5 -5
- package/dist/core/__tests__/{refresh-stall-recycle.test.js → serial/refresh-stall-recycle.test.js} +5 -14
- package/dist/core/__tests__/{revive.test.js → serial/revive.test.js} +15 -100
- package/dist/core/__tests__/{spawn-root.test.js → serial/spawn-root.test.js} +32 -15
- package/dist/core/__tests__/serial/subscription-delivery.test.js +126 -0
- package/dist/core/__tests__/serial/tmux-surface.test.js +256 -0
- package/dist/core/__tests__/{worktree.test.js → serial/worktree.test.js} +15 -15
- package/dist/core/__tests__/session-model.test.js +0 -18
- package/dist/core/__tests__/spawn-worktree-id-conflict.test.js +9 -0
- package/dist/core/__tests__/watchdog-abort-arms-retry.test.js +50 -0
- package/dist/core/broker-client/__tests__/transport-relay.test.js +15 -16
- package/dist/core/broker-client/__tests__/transport-socket.test.js +28 -0
- package/dist/core/broker-client/client.d.ts +2 -2
- package/dist/core/broker-client/client.js +4 -7
- package/dist/core/broker-client/transport-relay.d.ts +13 -19
- package/dist/core/broker-client/transport-relay.js +19 -34
- package/dist/core/broker-client/transport-socket.d.ts +2 -2
- package/dist/core/broker-client/transport-socket.js +9 -2
- package/dist/core/broker-client/transport.d.ts +7 -3
- package/dist/core/broker-client/transport.js +4 -4
- package/dist/core/canvas/__tests__/attention.test.js +1 -18
- package/dist/core/canvas/__tests__/remote-canvas-source.test.js +7 -64
- package/dist/core/canvas/__tests__/remote-transport.test.js +2 -3
- package/dist/core/canvas/__tests__/render-remote.test.js +7 -52
- package/dist/core/canvas/browse/app.d.ts +2 -17
- package/dist/core/canvas/browse/app.js +16 -88
- package/dist/core/canvas/browse/model.d.ts +0 -4
- package/dist/core/canvas/browse/model.js +1 -12
- package/dist/core/canvas/browse/render.js +6 -3
- package/dist/core/canvas/crons.d.ts +8 -5
- package/dist/core/canvas/crons.js +7 -6
- package/dist/core/canvas/extensions.d.ts +7 -3
- package/dist/core/canvas/extensions.js +16 -4
- package/dist/core/canvas/nav-model.d.ts +0 -4
- package/dist/core/canvas/nav-model.js +2 -14
- package/dist/core/canvas/node-order.d.ts +3 -0
- package/dist/core/canvas/node-order.js +12 -0
- package/dist/core/canvas/remote-canvas-source.d.ts +3 -6
- package/dist/core/canvas/remote-canvas-source.js +8 -15
- package/dist/core/command.js +11 -4
- package/dist/core/config.js +3 -1
- package/dist/core/events/envelope.js +1 -1
- package/dist/core/events/read.js +7 -21
- package/dist/core/events/source.d.ts +0 -2
- package/dist/core/events/source.js +0 -16
- package/dist/core/events/types.d.ts +1 -1
- package/dist/core/fault-classifier.d.ts +1 -1
- package/dist/core/feed/passive.d.ts +0 -11
- package/dist/core/feed/passive.js +1 -62
- package/dist/core/human/__tests__/{inbox-core.test.js → serial/inbox-core.test.js} +6 -6
- package/dist/core/keybindings/__tests__/resolve.test.js +1 -96
- package/dist/core/keybindings/background-bash.js +3 -4
- package/dist/core/keybindings/catalog.js +1 -1
- package/dist/core/memory/inline-ref-grammar.js +3 -3
- package/dist/core/memory-resolver.d.ts +11 -25
- package/dist/core/memory-resolver.js +51 -33
- package/dist/core/model-routes.d.ts +15 -0
- package/dist/core/model-routes.js +12 -0
- package/dist/core/pool-credential-store.js +1 -1
- package/dist/core/preview-registry.js +8 -9
- package/dist/core/profiles/__tests__/root-profile.test.js +4 -14
- package/dist/core/review/realize.d.ts +0 -13
- package/dist/core/review/realize.js +0 -40
- package/dist/core/review/types.d.ts +1 -1
- package/dist/core/runtime/__tests__/engine-route.test.js +2 -2
- package/dist/core/runtime/bearings.js +1 -11
- package/dist/core/runtime/broker/client-registry.d.ts +33 -0
- package/dist/core/runtime/broker/client-registry.js +164 -0
- package/dist/core/runtime/broker/daemon-ops.d.ts +19 -0
- package/dist/core/runtime/broker/daemon-ops.js +49 -0
- package/dist/core/runtime/broker/event-projection.d.ts +42 -0
- package/dist/core/runtime/broker/event-projection.js +178 -0
- package/dist/core/runtime/broker/fault-retry.d.ts +39 -0
- package/dist/core/runtime/broker/fault-retry.js +277 -0
- package/dist/core/runtime/broker/frame-dispatch.d.ts +238 -0
- package/dist/core/runtime/broker/frame-dispatch.js +1537 -0
- package/dist/core/runtime/broker/inbox.d.ts +22 -0
- package/dist/core/runtime/broker/inbox.js +167 -0
- package/dist/core/runtime/broker/passive.d.ts +16 -0
- package/dist/core/runtime/broker/passive.js +44 -0
- package/dist/core/runtime/broker/read-ops.d.ts +23 -0
- package/dist/core/runtime/broker/read-ops.js +150 -0
- package/dist/core/runtime/broker/rebind.d.ts +74 -0
- package/dist/core/runtime/broker/rebind.js +211 -0
- package/dist/core/runtime/broker/tool-groups.d.ts +39 -0
- package/dist/core/runtime/broker/tool-groups.js +244 -0
- package/dist/core/runtime/broker-extension-render.d.ts +11 -0
- package/dist/core/runtime/broker-extension-render.js +181 -0
- package/dist/core/runtime/broker-persona-guidance.d.ts +13 -0
- package/dist/core/runtime/broker-persona-guidance.js +58 -0
- package/dist/core/runtime/broker-protocol.d.ts +1 -1
- package/dist/core/runtime/broker-protocol.js +1 -1
- package/dist/core/runtime/broker.d.ts +5 -196
- package/dist/core/runtime/broker.js +276 -3059
- package/dist/core/runtime/canvas-extensions.js +11 -2
- package/dist/core/runtime/fault.js +1 -1
- package/dist/core/runtime/model-selection.d.ts +9 -0
- package/dist/core/runtime/model-selection.js +12 -0
- package/dist/core/runtime/model-swap.d.ts +3 -3
- package/dist/core/runtime/model-swap.js +33 -25
- package/dist/core/runtime/placement-tmux.d.ts +3 -14
- package/dist/core/runtime/placement-tmux.js +11 -80
- package/dist/core/runtime/placement.d.ts +4 -2
- package/dist/core/runtime/placement.js +7 -12
- package/dist/core/runtime/promote.d.ts +14 -1
- package/dist/core/runtime/promote.js +1 -1
- package/dist/core/runtime/reset.d.ts +1 -1
- package/dist/core/runtime/roadmap.js +1 -1
- package/dist/core/runtime/spawn.d.ts +8 -0
- package/dist/core/runtime/spawn.js +36 -6
- package/dist/core/runtime/stop-guard.d.ts +4 -3
- package/dist/core/runtime/stop-guard.js +36 -18
- package/dist/core/runtime/stop-signals.d.ts +4 -1
- package/dist/core/runtime/stream-watchdog.js +4 -5
- package/dist/core/runtime/structured-output.d.ts +15 -2
- package/dist/core/runtime/structured-output.js +35 -12
- package/dist/core/runtime/tmux-bindings.d.ts +25 -0
- package/dist/core/runtime/tmux-bindings.js +682 -0
- package/dist/core/runtime/tmux-chrome.d.ts +2 -1
- package/dist/core/runtime/tmux-chrome.js +3 -2
- package/dist/core/runtime/{tmux.d.ts → tmux-driver.d.ts} +18 -26
- package/dist/core/runtime/tmux-driver.js +598 -0
- package/dist/core/runtime/view-socket.d.ts +14 -0
- package/dist/core/runtime/view-socket.js +83 -0
- package/dist/core/session-model/session-state.d.ts +1 -2
- package/dist/core/session-model/session-state.js +5 -8
- package/dist/core/spawn.d.ts +1 -1
- package/dist/core/spawn.js +2 -2
- package/dist/core/substrate/gate.d.ts +1 -1
- package/dist/core/substrate/on-read-pure.d.ts +7 -0
- package/dist/core/substrate/on-read-pure.js +272 -0
- package/dist/core/termrender/termrender.js +32 -2
- package/dist/core/user-settings.d.ts +23 -1
- package/dist/core/user-settings.js +18 -1
- package/dist/daemon/api/__tests__/node-model-validation.test.js +134 -0
- package/dist/daemon/api/__tests__/review-terminal-conflict.test.js +98 -0
- package/dist/daemon/api/__tests__/{full → seam}/api-server.test.js +6 -48
- package/dist/daemon/api/__tests__/{full → seam}/b10-attach-modelauth.test.js +17 -44
- package/dist/daemon/api/__tests__/{full/push-parity.test.js → seam/leaf-api-parity.test.js} +61 -42
- package/dist/daemon/api/bridge.js +40 -81
- package/dist/daemon/api/handlers/broker-ops.d.ts +2 -0
- package/dist/daemon/api/handlers/broker-ops.js +383 -0
- package/dist/daemon/api/handlers/crons.js +9 -4
- package/dist/daemon/api/handlers/files.js +6 -7
- package/dist/daemon/api/handlers/inbox.js +2 -340
- package/dist/daemon/api/handlers/nodes.d.ts +10 -1
- package/dist/daemon/api/handlers/nodes.js +74 -39
- package/dist/daemon/api/handlers/review-comments.js +5 -1
- package/dist/daemon/api/handlers/reviews.js +0 -19
- package/dist/daemon/api/map.js +25 -4
- package/dist/daemon/api/router.js +2 -3
- package/dist/daemon/api/server.js +5 -7
- package/dist/daemon/cron-run.d.ts +4 -0
- package/dist/daemon/cron-run.js +30 -13
- package/dist/daemon/crtrd.d.ts +3 -58
- package/dist/daemon/crtrd.js +28 -1244
- package/dist/daemon/manage.js +0 -1
- package/dist/daemon/reconcilers/broker-supervision.d.ts +50 -0
- package/dist/daemon/reconcilers/broker-supervision.js +549 -0
- package/dist/daemon/reconcilers/cron-lane.d.ts +10 -0
- package/dist/daemon/reconcilers/cron-lane.js +32 -0
- package/dist/daemon/reconcilers/dormant-inbox.d.ts +18 -0
- package/dist/daemon/reconcilers/dormant-inbox.js +143 -0
- package/dist/daemon/reconcilers/storage-maintenance.d.ts +22 -0
- package/dist/daemon/reconcilers/storage-maintenance.js +213 -0
- package/dist/daemon/review/finish.js +2 -5
- package/dist/pi-extensions/__tests__/canvas-context-intro.test.js +34 -53
- package/dist/pi-extensions/__tests__/canvas-recap.test.js +16 -113
- package/dist/pi-extensions/__tests__/canvas-stophook-agentend.test.js +72 -99
- package/dist/pi-extensions/__tests__/canvas-stophook-context-nudge.test.js +29 -12
- package/dist/pi-extensions/broker-local.d.ts +20 -0
- package/dist/pi-extensions/broker-local.js +89 -0
- package/dist/pi-extensions/canvas-context-intro.d.ts +3 -3
- package/dist/pi-extensions/canvas-context-intro.js +22 -11
- package/dist/pi-extensions/canvas-doc-substrate.js +17 -34
- package/dist/pi-extensions/canvas-goal-capture.js +7 -12
- package/dist/pi-extensions/canvas-inbox-watcher.js +124 -139
- package/dist/pi-extensions/canvas-passive-context.d.ts +3 -3
- package/dist/pi-extensions/canvas-passive-context.js +22 -18
- package/dist/pi-extensions/canvas-recap.d.ts +2 -2
- package/dist/pi-extensions/canvas-recap.js +48 -21
- package/dist/pi-extensions/canvas-review-boundary.js +10 -4
- package/dist/pi-extensions/canvas-stophook.d.ts +0 -5
- package/dist/pi-extensions/canvas-stophook.js +149 -431
- package/dist/pi-extensions/canvas-structured-output.js +52 -30
- package/dist/pi-extensions/envelope-merge.d.ts +13 -0
- package/dist/pi-extensions/envelope-merge.js +29 -0
- package/dist/shared/working-activity.d.ts +3 -2
- package/dist/shared/working-activity.js +3 -2
- package/dist/types.d.ts +6 -5
- package/dist/types.js +2 -2
- package/docs/compat/hearth-crtr-v1.md +4 -12
- package/docs/compat/hearth-crtr-v2.md +3 -11
- package/docs/compat/hearth-crtr-v3.md +4 -12
- package/docs/compat/hearth-crtr-v4.md +3 -11
- package/docs/compat/hearth-crtr-v5.md +3 -11
- package/docs/public-api.md +3 -7
- package/package.json +7 -49
- package/runtime.lock.json +2766 -14533
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/__tests__/claude-plugin-commands.test.ts +0 -49
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/__tests__/memory-slash-commands.test.ts +0 -194
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/__tests__/statusline.test.ts +0 -68
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/frontmatter-rules/test.ts +0 -119
- package/dist/clients/attach/__tests__/attach-chrome-remote.test.js +0 -439
- package/dist/clients/attach/__tests__/attach-keybindings.test.js +0 -170
- package/dist/clients/attach/__tests__/crtr-output-coverage.test.js +0 -57
- package/dist/clients/attach/__tests__/editor-frame-title.test.js +0 -19
- package/dist/clients/attach/__tests__/input-controller-extension-command.test.js +0 -32
- package/dist/clients/attach/__tests__/markdown-headings.test.js +0 -35
- package/dist/clients/attach/__tests__/session-identity-refresh.test.js +0 -32
- package/dist/clients/conversation/conversation.d.ts +0 -65
- package/dist/clients/conversation/conversation.js +0 -318
- package/dist/clients/conversation/frames.d.ts +0 -30
- package/dist/clients/conversation/frames.js +0 -52
- package/dist/clients/conversation/region.d.ts +0 -51
- package/dist/clients/conversation/region.js +0 -265
- package/dist/clients/inbox/__tests__/inbox-controller.test.js +0 -247
- package/dist/clients/inbox/__tests__/mount-panel.test.js +0 -776
- package/dist/clients/inbox/review/__tests__/remap.test.js +0 -196
- package/dist/clients/inbox/review/columns.d.ts +0 -22
- package/dist/clients/inbox/review/columns.js +0 -40
- package/dist/clients/inbox/review/composition.d.ts +0 -60
- package/dist/clients/inbox/review/composition.js +0 -278
- package/dist/clients/inbox/review/document-region.d.ts +0 -120
- package/dist/clients/surfaces/region.d.ts +0 -16
- package/dist/clients/web/__tests__/push-engine.test.js +0 -158
- package/dist/clients/web/__tests__/push-registry.test.d.ts +0 -1
- package/dist/clients/web/__tests__/push-registry.test.js +0 -177
- package/dist/clients/web/dev-server.d.ts +0 -7
- package/dist/clients/web/dev-server.js +0 -46
- package/dist/clients/web/events.d.ts +0 -19
- package/dist/clients/web/events.js +0 -163
- package/dist/clients/web/push-engine.d.ts +0 -44
- package/dist/clients/web/push-engine.js +0 -125
- package/dist/clients/web/push-registry.d.ts +0 -85
- package/dist/clients/web/push-registry.js +0 -373
- package/dist/clients/web/server.d.ts +0 -19
- package/dist/clients/web/server.js +0 -661
- package/dist/clients/web/web-client/shared/protocol.d.ts +0 -214
- package/dist/clients/web/web-client/shared/protocol.js +0 -8
- package/dist/clients/web/web-cmd.d.ts +0 -2
- package/dist/clients/web/web-cmd.js +0 -141
- package/dist/commands/__tests__/api-canvas-source.test.d.ts +0 -1
- package/dist/commands/__tests__/api-canvas-source.test.js +0 -37
- package/dist/commands/__tests__/canvas-config.test.d.ts +0 -1
- package/dist/commands/__tests__/canvas-config.test.js +0 -107
- package/dist/commands/__tests__/node-no-kickoff-flag.test.d.ts +0 -1
- package/dist/commands/__tests__/node-no-kickoff-flag.test.js +0 -73
- package/dist/commands/__tests__/node-worktree-flag.test.d.ts +0 -1
- package/dist/commands/__tests__/node-worktree-flag.test.js +0 -49
- package/dist/commands/__tests__/search-contents.test.d.ts +0 -1
- package/dist/commands/__tests__/search-contents.test.js +0 -52
- package/dist/commands/memory/__tests__/lint.test.d.ts +0 -1
- package/dist/commands/memory/__tests__/lint.test.js +0 -15
- package/dist/commands/sys/__tests__/config-broker-thresholds.test.d.ts +0 -1
- package/dist/commands/sys/__tests__/config-broker-thresholds.test.js +0 -95
- package/dist/commands/sys/__tests__/config-keybindings.test.d.ts +0 -1
- package/dist/commands/sys/__tests__/config-keybindings.test.js +0 -55
- package/dist/commands/sys/__tests__/helpers/setup-runtime.d.ts +0 -5
- package/dist/commands/sys/__tests__/helpers/setup-runtime.js +0 -19
- package/dist/commands/sys/__tests__/setup-front-door.test.d.ts +0 -1
- package/dist/commands/sys/__tests__/setup-front-door.test.js +0 -102
- package/dist/commands/sys/__tests__/setup-models.test.d.ts +0 -1
- package/dist/commands/sys/__tests__/setup-models.test.js +0 -205
- package/dist/commands/sys/__tests__/setup-providers-viewport.test.d.ts +0 -1
- package/dist/commands/sys/__tests__/setup-providers-viewport.test.js +0 -155
- package/dist/commands/sys/__tests__/sync-deps.test.d.ts +0 -1
- package/dist/commands/sys/__tests__/sync-deps.test.js +0 -179
- package/dist/commands/sys/__tests__/sync-import.test.d.ts +0 -1
- package/dist/commands/sys/__tests__/sync-import.test.js +0 -315
- package/dist/core/__tests__/base-worker-prompt.test.d.ts +0 -1
- package/dist/core/__tests__/base-worker-prompt.test.js +0 -57
- package/dist/core/__tests__/command-plugins-surfaces.test.d.ts +0 -1
- package/dist/core/__tests__/command-plugins-surfaces.test.js +0 -359
- package/dist/core/__tests__/connection-reconnect-resume.test.d.ts +0 -1
- package/dist/core/__tests__/connection-reconnect-resume.test.js +0 -36
- package/dist/core/__tests__/finalization-migration.test.d.ts +0 -1
- package/dist/core/__tests__/finalization-migration.test.js +0 -38
- package/dist/core/__tests__/fixtures/extra-extension.d.ts +0 -1
- package/dist/core/__tests__/fixtures/extra-extension.js +0 -3
- package/dist/core/__tests__/fixtures/spawn-proof-target.test.d.ts +0 -1
- package/dist/core/__tests__/fixtures/spawn-proof-target.test.js +0 -15
- package/dist/core/__tests__/fork.test.d.ts +0 -1
- package/dist/core/__tests__/fork.test.js +0 -108
- package/dist/core/__tests__/full/broker-attach-limits.test.d.ts +0 -1
- package/dist/core/__tests__/full/broker-attach-limits.test.js +0 -147
- package/dist/core/__tests__/full/broker-deliver-ack.test.d.ts +0 -1
- package/dist/core/__tests__/full/broker-deliver-ack.test.js +0 -73
- package/dist/core/__tests__/full/broker-dialogs.test.d.ts +0 -1
- package/dist/core/__tests__/full/broker-dialogs.test.js +0 -180
- package/dist/core/__tests__/full/broker-display-snapshot.test.d.ts +0 -1
- package/dist/core/__tests__/full/broker-display-snapshot.test.js +0 -75
- package/dist/core/__tests__/full/broker-dormant-wake.test.d.ts +0 -1
- package/dist/core/__tests__/full/broker-dormant-wake.test.js +0 -130
- package/dist/core/__tests__/full/broker-model-changed-broadcast.test.d.ts +0 -1
- package/dist/core/__tests__/full/broker-model-changed-broadcast.test.js +0 -57
- package/dist/core/__tests__/full/broker-navigate-tree-rewelcome.test.d.ts +0 -1
- package/dist/core/__tests__/full/broker-navigate-tree-rewelcome.test.js +0 -80
- package/dist/core/__tests__/full/cascade-close.test.d.ts +0 -1
- package/dist/core/__tests__/full/cascade-close.test.js +0 -240
- package/dist/core/__tests__/full/detach-focus.test.d.ts +0 -1
- package/dist/core/__tests__/full/detach-focus.test.js +0 -126
- package/dist/core/__tests__/full/idle-release-settlement.test.d.ts +0 -1
- package/dist/core/__tests__/full/issue-146-yield-spawn-focus.test.d.ts +0 -1
- package/dist/core/__tests__/full/issue-146-yield-spawn-focus.test.js +0 -107
- package/dist/core/__tests__/full/park-clock-release.test.d.ts +0 -1
- package/dist/core/__tests__/full/park-clock-release.test.js +0 -56
- package/dist/core/__tests__/full/yield-message-transaction.test.d.ts +0 -1
- package/dist/core/__tests__/memory-index-render.test.d.ts +0 -1
- package/dist/core/__tests__/memory-index-render.test.js +0 -60
- package/dist/core/__tests__/model-routes.test.d.ts +0 -1
- package/dist/core/__tests__/model-routes.test.js +0 -41
- package/dist/core/__tests__/on-read-identity.test.d.ts +0 -1
- package/dist/core/__tests__/on-read-identity.test.js +0 -61
- package/dist/core/__tests__/phase4-review-migration.test.d.ts +0 -1
- package/dist/core/__tests__/phase4-review-migration.test.js +0 -100
- package/dist/core/__tests__/prune-to-limit.test.d.ts +0 -1
- package/dist/core/__tests__/prune-to-limit.test.js +0 -126
- package/dist/core/__tests__/reset.test.d.ts +0 -1
- package/dist/core/__tests__/reset.test.js +0 -69
- package/dist/core/__tests__/spawn-no-kickoff.test.d.ts +0 -1
- package/dist/core/__tests__/spawn-no-kickoff.test.js +0 -115
- package/dist/core/__tests__/steer-note.test.d.ts +0 -1
- package/dist/core/__tests__/steer-note.test.js +0 -41
- package/dist/core/__tests__/subcommand-tier.test.d.ts +0 -1
- package/dist/core/__tests__/subcommand-tier.test.js +0 -99
- package/dist/core/__tests__/subscription-delivery.test.js +0 -211
- package/dist/core/__tests__/test-runner-cheap-sharding.test.d.ts +0 -1
- package/dist/core/__tests__/test-runner-cheap-sharding.test.js +0 -97
- package/dist/core/__tests__/tmux-surface.test.js +0 -484
- package/dist/core/__tests__/wake-bearings.test.d.ts +0 -1
- package/dist/core/__tests__/wake-bearings.test.js +0 -102
- package/dist/core/canvas/__tests__/remote-event-stream.test.d.ts +0 -1
- package/dist/core/canvas/__tests__/remote-event-stream.test.js +0 -146
- package/dist/core/canvas/__tests__/source-resolve.test.d.ts +0 -1
- package/dist/core/canvas/__tests__/source-resolve.test.js +0 -77
- package/dist/core/canvas/browse/__tests__/model.test.d.ts +0 -1
- package/dist/core/canvas/browse/__tests__/model.test.js +0 -290
- package/dist/core/canvas/browse/__tests__/rebuild-coalescer.test.d.ts +0 -1
- package/dist/core/canvas/browse/__tests__/rebuild-coalescer.test.js +0 -134
- package/dist/core/canvas/browse/__tests__/render.test.d.ts +0 -1
- package/dist/core/canvas/browse/__tests__/render.test.js +0 -111
- package/dist/core/canvas/browse/rebuild-coalescer.d.ts +0 -7
- package/dist/core/canvas/browse/rebuild-coalescer.js +0 -61
- package/dist/core/canvas/remote-event-stream.d.ts +0 -24
- package/dist/core/canvas/remote-event-stream.js +0 -94
- package/dist/core/feed/__tests__/coalesce-human.test.d.ts +0 -1
- package/dist/core/feed/__tests__/coalesce-human.test.js +0 -36
- package/dist/core/feed/__tests__/empty-node-guard.test.d.ts +0 -1
- package/dist/core/feed/__tests__/empty-node-guard.test.js +0 -45
- package/dist/core/host-exports/__tests__/export-prunes-boot-skill.test.d.ts +0 -1
- package/dist/core/host-exports/__tests__/export-prunes-boot-skill.test.js +0 -84
- package/dist/core/human/__tests__/visible-paths.test.d.ts +0 -1
- package/dist/core/human/__tests__/visible-paths.test.js +0 -28
- package/dist/core/keybindings/__tests__/inbox-affordance.test.d.ts +0 -1
- package/dist/core/keybindings/__tests__/inbox-affordance.test.js +0 -38
- package/dist/core/review/__tests__/project.test.d.ts +0 -1
- package/dist/core/review/__tests__/project.test.js +0 -71
- package/dist/core/runtime/__tests__/command-expansion.test.d.ts +0 -1
- package/dist/core/runtime/__tests__/command-expansion.test.js +0 -25
- package/dist/core/runtime/__tests__/session-visibility.test.d.ts +0 -1
- package/dist/core/runtime/__tests__/session-visibility.test.js +0 -119
- package/dist/core/runtime/__tests__/spawn-at-given-id.test.d.ts +0 -1
- package/dist/core/runtime/__tests__/spawn-at-given-id.test.js +0 -34
- package/dist/core/runtime/tmux.js +0 -1314
- package/dist/daemon/api/__tests__/full/push-parity.test.d.ts +0 -1
- package/dist/daemon/api/__tests__/full/worktree-parity.test.d.ts +0 -1
- package/dist/daemon/api/__tests__/full/worktree-parity.test.js +0 -160
- package/dist/daemon/api/__tests__/inbox.test.d.ts +0 -1
- package/dist/daemon/api/__tests__/inbox.test.js +0 -489
- package/dist/web-client/apple-touch-icon.png +0 -0
- package/dist/web-client/assets/fragment-mono-latin-400-normal-BYwT3kSJ.woff +0 -0
- package/dist/web-client/assets/fragment-mono-latin-400-normal-yxdJ5AmL.woff2 +0 -0
- package/dist/web-client/assets/fragment-mono-latin-ext-400-normal-BbKYyvR9.woff2 +0 -0
- package/dist/web-client/assets/fragment-mono-latin-ext-400-normal-CT4YFKeK.woff +0 -0
- package/dist/web-client/assets/index-CCPaLeW7.css +0 -2
- package/dist/web-client/assets/index-kyOWsnZK.js +0 -86
- package/dist/web-client/assets/martian-mono-cyrillic-wght-normal-B84CD5C_.woff2 +0 -0
- package/dist/web-client/assets/martian-mono-latin-ext-wght-normal-DlL6xMw5.woff2 +0 -0
- package/dist/web-client/assets/martian-mono-latin-wght-normal-5W32yIyr.woff2 +0 -0
- package/dist/web-client/assets/workbox-window.prod.es5-Bd17z0YL.js +0 -2
- package/dist/web-client/icon-192.png +0 -0
- package/dist/web-client/icon-512.png +0 -0
- package/dist/web-client/icon-maskable-512.png +0 -0
- package/dist/web-client/index.html +0 -17
- package/dist/web-client/manifest.webmanifest +0 -1
- package/dist/web-client/sw.js +0 -1
- /package/dist/api/__tests__/{client.test.d.ts → serial/client.test.d.ts} +0 -0
- /package/dist/clients/inbox/__tests__/{inbox-controller.test.d.ts → serial/inbox-controller.test.d.ts} +0 -0
- /package/dist/clients/inbox/__tests__/{mount-panel.test.d.ts → serial/mount-panel.test.d.ts} +0 -0
- /package/dist/clients/{attach/__tests__/attach-chrome-remote.test.d.ts → inbox/review/__tests__/teardown-notice.test.d.ts} +0 -0
- /package/dist/{clients/attach/__tests__/attach-keybindings.test.d.ts → core/__tests__/broker-extension-canvas-db-boundary.test.d.ts} +0 -0
- /package/dist/{clients/attach/__tests__/crtr-output-coverage.test.d.ts → core/__tests__/seam/broker-attach-multiclient.test.d.ts} +0 -0
- /package/dist/core/__tests__/{full → seam}/broker-attach-stream.test.d.ts +0 -0
- /package/dist/core/__tests__/{full → seam}/broker-crash-teardown.test.d.ts +0 -0
- /package/dist/core/__tests__/{full → seam}/broker-pane-resolution.test.d.ts +0 -0
- /package/dist/core/__tests__/{full → seam}/broker-provider-retry.test.d.ts +0 -0
- /package/dist/core/__tests__/{full → seam}/broker-whip-interrupt.test.d.ts +0 -0
- /package/dist/{clients/attach/__tests__/editor-frame-title.test.d.ts → core/__tests__/seam/dormancy-release.test.d.ts} +0 -0
- /package/dist/{clients/attach/__tests__/input-controller-extension-command.test.d.ts → core/__tests__/seam/yield-refresh-transaction.test.d.ts} +0 -0
- /package/dist/core/__tests__/{broker-fork-seam.test.d.ts → serial/broker-fork-seam.test.d.ts} +0 -0
- /package/dist/core/__tests__/{broker-sdk-wiring.test.d.ts → serial/broker-sdk-wiring.test.d.ts} +0 -0
- /package/dist/core/__tests__/{broker-snapshot-history.test.d.ts → serial/broker-snapshot-history.test.d.ts} +0 -0
- /package/dist/core/__tests__/{command-plugins.test.d.ts → serial/command-plugins.test.d.ts} +0 -0
- /package/dist/core/__tests__/{deferred-no-wake.test.d.ts → serial/deferred-no-wake.test.d.ts} +0 -0
- /package/dist/core/__tests__/{flagship-lifecycle.test.d.ts → serial/flagship-lifecycle.test.d.ts} +0 -0
- /package/dist/core/__tests__/{host-teardown-process-group.test.d.ts → serial/host-teardown-process-group.test.d.ts} +0 -0
- /package/dist/core/__tests__/{human-deliver-e2e.test.d.ts → serial/human-deliver-e2e.test.d.ts} +0 -0
- /package/dist/core/__tests__/{live-mutation.test.d.ts → serial/live-mutation.test.d.ts} +0 -0
- /package/dist/core/__tests__/{refresh-stall-recycle.test.d.ts → serial/refresh-stall-recycle.test.d.ts} +0 -0
- /package/dist/core/__tests__/{revive.test.d.ts → serial/revive.test.d.ts} +0 -0
- /package/dist/core/__tests__/{spawn-root.test.d.ts → serial/spawn-root.test.d.ts} +0 -0
- /package/dist/core/__tests__/{subscription-delivery.test.d.ts → serial/subscription-delivery.test.d.ts} +0 -0
- /package/dist/core/__tests__/{tmux-surface.test.d.ts → serial/tmux-surface.test.d.ts} +0 -0
- /package/dist/core/__tests__/{worktree.test.d.ts → serial/worktree.test.d.ts} +0 -0
- /package/dist/{clients/attach/__tests__/markdown-headings.test.d.ts → core/__tests__/watchdog-abort-arms-retry.test.d.ts} +0 -0
- /package/dist/{clients/attach/__tests__/session-identity-refresh.test.d.ts → core/broker-client/__tests__/transport-socket.test.d.ts} +0 -0
- /package/dist/core/human/__tests__/{inbox-core.test.d.ts → serial/inbox-core.test.d.ts} +0 -0
- /package/dist/{clients/inbox/review/__tests__/remap.test.d.ts → daemon/api/__tests__/node-model-validation.test.d.ts} +0 -0
- /package/dist/{clients/surfaces/region.js → daemon/api/__tests__/review-terminal-conflict.test.d.ts} +0 -0
- /package/dist/daemon/api/__tests__/{full → seam}/api-server.test.d.ts +0 -0
- /package/dist/daemon/api/__tests__/{full → seam}/b10-attach-modelauth.test.d.ts +0 -0
- /package/dist/{clients/web/__tests__/push-engine.test.d.ts → daemon/api/__tests__/seam/leaf-api-parity.test.d.ts} +0 -0
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
// Run with: node --import tsx/esm --test src/core/__tests__/full/broker-model-changed-broadcast.test.ts
|
|
2
|
-
//
|
|
3
|
-
// FULL TIER (real-boot-bound): tmux-free, but it boots a REAL broker process,
|
|
4
|
-
// so it lives in full/ (CI), not the fast local loop.
|
|
5
|
-
//
|
|
6
|
-
// BUG-REGRESSION (real, observed 2026-06-11 in `crtr surface attach`): switching the
|
|
7
|
-
// model (/model <provider/id> or the picker) visibly did nothing — the viewer's
|
|
8
|
-
// status bar kept showing the OLD model until some unrelated event happened to
|
|
9
|
-
// arrive.
|
|
10
|
-
//
|
|
11
|
-
// 3-PART HEADER:
|
|
12
|
-
// (1) BUG IT LOCKS — pi emits no AgentSessionEvent for a model switch, and the
|
|
13
|
-
// broker's `set_model`/`cycle_model` handlers replied with only a bare ack
|
|
14
|
-
// to the REQUESTING client. The new model reached no viewer at all: the
|
|
15
|
-
// broker now broadcasts a `model_changed` frame (mirroring
|
|
16
|
-
// snapshot.state.model) to every client after the engine accepts the switch.
|
|
17
|
-
// (2) WHY BROKER/SOCKET-LEVEL, NOT PANE — the regression is pure frame-plumbing
|
|
18
|
-
// on view.sock: a controller `set_model` in, an ack + `model_changed`
|
|
19
|
-
// fan-out. No tmux pane or TUI is involved, so the lock holds headlessly
|
|
20
|
-
// (createHeadlessHarness + the fake engine, whose registry stub resolves
|
|
21
|
-
// any `provider/id` and whose setModel stores what it is handed).
|
|
22
|
-
// (3) HOW IT FAILS ON REGRESSION — pre-fix, NO `model_changed` frame ever
|
|
23
|
-
// arrives at either the controller or the observer (both waits time out);
|
|
24
|
-
// the ack alone still passing would not satisfy the broadcast asserts.
|
|
25
|
-
import { test, before, after, afterEach } from 'node:test';
|
|
26
|
-
import assert from 'node:assert/strict';
|
|
27
|
-
import { createHeadlessHarness } from '../helpers/harness.js';
|
|
28
|
-
import { createAttachKit } from '../helpers/broker-clients.js';
|
|
29
|
-
let h;
|
|
30
|
-
let id;
|
|
31
|
-
const kit = createAttachKit(() => h);
|
|
32
|
-
const { attachUntil } = kit;
|
|
33
|
-
before(async () => {
|
|
34
|
-
h = await createHeadlessHarness({ sessionPrefix: 'crtr-brkmodel' });
|
|
35
|
-
const root = h.spawnRoot('model-changed-broadcast suite root');
|
|
36
|
-
id = await h.spawnHeadlessChild(root, 'headless worker — model_changed broadcast gate');
|
|
37
|
-
});
|
|
38
|
-
after(async () => {
|
|
39
|
-
if (h !== undefined)
|
|
40
|
-
await h.dispose();
|
|
41
|
-
});
|
|
42
|
-
afterEach(() => {
|
|
43
|
-
kit.closeAll();
|
|
44
|
-
});
|
|
45
|
-
test('set_model acks the requester and broadcasts model_changed to every viewer', async () => {
|
|
46
|
-
const c = await attachUntil(id, 'controller', 'model-ctrl', (a) => a.welcome.role === 'controller', 'model-ctrl admitted controller');
|
|
47
|
-
const o = await attachUntil(id, 'observer', 'model-obs', (a) => a.welcome.role === 'observer', 'model-obs admitted observer');
|
|
48
|
-
c.send({ type: 'set_model', model: 'anthropic/fake-fable' });
|
|
49
|
-
const ack = await c.waitFrame((f) => f.type === 'ack' && f.for === 'set_model', 'set_model ack');
|
|
50
|
-
assert.ok(ack.type === 'ack' && ack.ok, 'set_model acked ok');
|
|
51
|
-
// BOTH the requester and the observer hear the switch. Pre-fix: no
|
|
52
|
-
// model_changed frame exists, so neither wait ever resolves.
|
|
53
|
-
const cm = await c.waitFrame((f) => f.type === 'model_changed', 'controller receives model_changed');
|
|
54
|
-
assert.ok(cm.type === 'model_changed' && cm.model?.id === 'fake-fable', 'controller sees the new model id');
|
|
55
|
-
const om = await o.waitFrame((f) => f.type === 'model_changed', 'observer receives model_changed');
|
|
56
|
-
assert.ok(om.type === 'model_changed' && om.model?.id === 'fake-fable', 'observer sees the new model id');
|
|
57
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
// Run with: node --import tsx/esm --test src/core/__tests__/full/broker-navigate-tree-rewelcome.test.ts
|
|
2
|
-
//
|
|
3
|
-
// FULL TIER (real-boot-bound): tmux-free, but it boots a REAL broker process,
|
|
4
|
-
// so it lives in full/ (CI), not the fast local loop.
|
|
5
|
-
//
|
|
6
|
-
// BUG-REGRESSION (real, observed 2026-06-11 in `crtr surface attach`): double-Esc (or
|
|
7
|
-
// /tree) opened the session-tree picker, but SELECTING an entry visibly did
|
|
8
|
-
// nothing — the viewer stayed on the old transcript instead of traveling back
|
|
9
|
-
// to the chosen point in time.
|
|
10
|
-
//
|
|
11
|
-
// 3-PART HEADER:
|
|
12
|
-
// (1) BUG IT LOCKS — the broker's `navigate_tree` handler called
|
|
13
|
-
// session.navigateTree() (which rewinds IN-PLACE: same session file, new
|
|
14
|
-
// leaf, NO relayed AgentSessionEvent) and then only acked. Unlike the
|
|
15
|
-
// session-replacing ops (new_session/switch_session/fork → runReplacement
|
|
16
|
-
// → reWelcomeAll), it never re-snapshotted the viewers, so every attached
|
|
17
|
-
// client kept rendering the abandoned branch. The navigated-to user
|
|
18
|
-
// message's `editorText` (pi parity: the tree navigator restores it to the
|
|
19
|
-
// editor) was dropped on the floor too.
|
|
20
|
-
// (2) WHY BROKER/SOCKET-LEVEL, NOT PANE — the regression is pure frame-plumbing
|
|
21
|
-
// on view.sock: a controller `navigate_tree` in, a re-`welcome` fan-out +
|
|
22
|
-
// ack.detail out. No tmux pane or TUI is involved, so the lock holds
|
|
23
|
-
// headlessly (createHeadlessHarness + the fake engine, whose navigateTree
|
|
24
|
-
// pops the last accrued turn and returns `rewound-to:<targetId>`).
|
|
25
|
-
// (3) HOW IT FAILS ON REGRESSION — pre-fix, NO second welcome ever arrives
|
|
26
|
-
// (the re-welcome waits time out) and the navigate_tree ack carries no
|
|
27
|
-
// detail; the rewound-history assert (the turn token gone from the new
|
|
28
|
-
// snapshot) also goes red if the re-welcome serves a stale snapshot.
|
|
29
|
-
import { test, before, after, afterEach } from 'node:test';
|
|
30
|
-
import assert from 'node:assert/strict';
|
|
31
|
-
import { createHeadlessHarness } from '../helpers/harness.js';
|
|
32
|
-
import { createAttachKit, frameHas, tok } from '../helpers/broker-clients.js';
|
|
33
|
-
let h;
|
|
34
|
-
let id;
|
|
35
|
-
const kit = createAttachKit(() => h);
|
|
36
|
-
const { attachUntil } = kit;
|
|
37
|
-
before(async () => {
|
|
38
|
-
h = await createHeadlessHarness({ sessionPrefix: 'crtr-brknav' });
|
|
39
|
-
const root = h.spawnRoot('navigate-tree-rewelcome suite root');
|
|
40
|
-
id = await h.spawnHeadlessChild(root, 'headless worker — navigate-tree rewelcome gate');
|
|
41
|
-
});
|
|
42
|
-
after(async () => {
|
|
43
|
-
if (h !== undefined)
|
|
44
|
-
await h.dispose();
|
|
45
|
-
});
|
|
46
|
-
afterEach(() => {
|
|
47
|
-
kit.closeAll();
|
|
48
|
-
});
|
|
49
|
-
const welcomes = (frames) => frames.filter((f) => f.type === 'welcome');
|
|
50
|
-
test('navigate_tree re-welcomes every viewer onto the rewound transcript and acks the editor text', async () => {
|
|
51
|
-
const c = await attachUntil(id, 'controller', 'nav-ctrl', (a) => a.welcome.role === 'controller', 'nav-ctrl admitted controller');
|
|
52
|
-
// Accrue one observable turn so the rewind has something to drop.
|
|
53
|
-
const token = tok('NAV-TURN');
|
|
54
|
-
c.send({ type: 'prompt', text: token });
|
|
55
|
-
await c.waitFrame((f) => f.type === 'agent_end' && frameHas(f, token), 'turn relayed before navigate');
|
|
56
|
-
// The observer attaches AFTER the turn so its first welcome deterministically
|
|
57
|
-
// holds the token (the pre-navigate baseline) — same accrual trick as G3.
|
|
58
|
-
const o = await attachUntil(id, 'observer', 'nav-obs', (a) => frameHas(a.welcome, token), 'observer welcome holds the pre-navigate turn');
|
|
59
|
-
c.send({ type: 'navigate_tree', targetId: 'entry-x' });
|
|
60
|
-
// The ack carries the navigated-to user message's text in detail (the viewer
|
|
61
|
-
// restores it to the editor). Pre-fix: ack had no detail.
|
|
62
|
-
const ack = await c.waitFrame((f) => f.type === 'ack' && f.for === 'navigate_tree', 'navigate_tree ack');
|
|
63
|
-
assert.ok(ack.type === 'ack' && ack.ok, 'navigate_tree acked ok');
|
|
64
|
-
assert.equal(ack.type === 'ack' ? ack.detail : undefined, 'rewound-to:entry-x', 'ack.detail carries the rewound-to editor text');
|
|
65
|
-
// BOTH viewers get re-welcomed onto the rewound history. Pre-fix: no second
|
|
66
|
-
// welcome ever arrives (navigate_tree only acked).
|
|
67
|
-
await h.waitFor(() => (welcomes(c.frames).length >= 2 ? true : null), {
|
|
68
|
-
label: 'controller re-welcomed after navigate_tree',
|
|
69
|
-
});
|
|
70
|
-
await h.waitFor(() => (welcomes(o.frames).length >= 2 ? true : null), {
|
|
71
|
-
label: 'observer re-welcomed after navigate_tree',
|
|
72
|
-
});
|
|
73
|
-
// The re-welcome serves the REWOUND transcript: the fake's navigateTree popped
|
|
74
|
-
// the last accrued turn, so the token present in the observer's first welcome
|
|
75
|
-
// must be gone from its second.
|
|
76
|
-
const [first, second] = welcomes(o.frames);
|
|
77
|
-
assert.ok(frameHas(first, token), 'pre-navigate welcome holds the turn');
|
|
78
|
-
assert.ok(!frameHas(second, token), 're-welcome serves the rewound transcript (turn dropped)');
|
|
79
|
-
assert.equal(second.snapshot.messages.length, first.snapshot.messages.length - 2, 're-welcome history is exactly one turn shorter (a turn = user + assistant = 2 tree messages)');
|
|
80
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,240 +0,0 @@
|
|
|
1
|
-
// Run with: node --import tsx/esm --test src/core/__tests__/cascade-close.test.ts
|
|
2
|
-
//
|
|
3
|
-
// CASCADE CLOSE + exclusive-subtree ownership — a FAITHFUL integration test of
|
|
4
|
-
// `crtr node lifecycle close` on a MIDDLE node, driven through the REAL CLI against a REAL
|
|
5
|
-
// isolated tmux session with REAL fake-pi vehicles in REAL panes, asserting off
|
|
6
|
-
// the canvas data layer and checked against the state-model ORACLE
|
|
7
|
-
// (state-model.md §4 `node lifecycle close`, §5 cascade-close ownership, invariant 3,
|
|
8
|
-
// ambiguity A5).
|
|
9
|
-
//
|
|
10
|
-
// WHY this exists alongside the unit `close.test.ts`: that test exercises
|
|
11
|
-
// `closeNode()` in-process against the data layer with FABRICATED pane strings
|
|
12
|
-
// (`pane:'%x'`) — it proves the closing-set fixpoint and the status flip, but it
|
|
13
|
-
// never kills a real tmux pane, never boots a real vehicle, and never closes a
|
|
14
|
-
// MIDDLE node with a live sideways-sibling subtree. This test fills exactly that
|
|
15
|
-
// gap: it builds a real tree, closes the middle, and proves the reap is EXACTLY
|
|
16
|
-
// the closed node's own subtree — nothing above (the ancestor) or sideways (a
|
|
17
|
-
// sibling subtree) is touched, and the real broker engines actually die.
|
|
18
|
-
//
|
|
19
|
-
// VIEWER MODEL (a09b71f): a managed child boots as a detached headless BROKER
|
|
20
|
-
// with NO viewer pane on spawn (a viewer is opened on demand via `surface node focus`).
|
|
21
|
-
// So "the node is up" is broker-engine liveness — its recorded `pi_pid` is alive
|
|
22
|
-
// — NOT pane presence. close tears that broker engine down (headlessBrokerHost
|
|
23
|
-
// .teardown over view.sock), so we assert pid liveness, not panes.
|
|
24
|
-
//
|
|
25
|
-
// The tree (covers BOTH required shapes in one topology):
|
|
26
|
-
//
|
|
27
|
-
// A (resident root, in-process)
|
|
28
|
-
// ├── B ◄── CLOSE TARGET (the middle node)
|
|
29
|
-
// │ ├── C
|
|
30
|
-
// │ │ └── E depth : A→B→C→E (deep chain)
|
|
31
|
-
// │ └── D breadth: B has two children {C, D}
|
|
32
|
-
// └── S sideways sibling subtree — MUST survive
|
|
33
|
-
// └── G
|
|
34
|
-
//
|
|
35
|
-
// close(B) ⇒ exclusive subtree {B,C,D,E} canceled; A,S,G untouched.
|
|
36
|
-
//
|
|
37
|
-
// CRITICAL DELIVERABLE (ambiguity A5): the EXACT terminal status a cascade-
|
|
38
|
-
// closed descendant receives under `node lifecycle close`. With the fixtures made
|
|
39
|
-
// non-empty below: status === 'canceled', intent === null (cleared) — for the
|
|
40
|
-
// cascade ROOT and EVERY descendant alike (`transition(id,'cancel')`,
|
|
41
|
-
// close.ts → lifecycle.ts cancel row: status='canceled', intent=null, from '*').
|
|
42
|
-
// This differs from the ancestor-RESET path (`reapDescendants` → `reap` → 'done')
|
|
43
|
-
// — same act, different terminal status: A5's open question. We assert the close
|
|
44
|
-
// side and report the confirmed fact; we do NOT change it.
|
|
45
|
-
//
|
|
46
|
-
// FLAG vs the task brief: the brief expected "subscription+parent edges removed"
|
|
47
|
-
// on close. CURRENT behavior + the ORACLE (§4: "Nothing is deleted: pi sessions +
|
|
48
|
-
// edges persist → revivable") + the CLI help ("their pi sessions and canvas edges
|
|
49
|
-
// persist for a later revive") all say edges PERSIST. This test asserts the
|
|
50
|
-
// CURRENT (persist) behavior and the report flags the contradiction; production
|
|
51
|
-
// is NOT changed.
|
|
52
|
-
import { test } from 'node:test';
|
|
53
|
-
import assert from 'node:assert/strict';
|
|
54
|
-
import { spawnSync } from 'node:child_process';
|
|
55
|
-
import { mkdirSync, writeFileSync } from 'node:fs';
|
|
56
|
-
import { join } from 'node:path';
|
|
57
|
-
import { createHarness, hasTmux, TMUX_TIMEOUT_MS } from '../helpers/harness.js';
|
|
58
|
-
import { isPidAlive } from '../../canvas/pid.js';
|
|
59
|
-
function sessionExists(session) {
|
|
60
|
-
return (spawnSync('tmux', ['has-session', '-t', session], {
|
|
61
|
-
stdio: 'ignore',
|
|
62
|
-
timeout: TMUX_TIMEOUT_MS,
|
|
63
|
-
}).status === 0);
|
|
64
|
-
}
|
|
65
|
-
function seedAssistantSession(sessionFile) {
|
|
66
|
-
mkdirSync(join(sessionFile, '..'), { recursive: true });
|
|
67
|
-
writeFileSync(sessionFile, JSON.stringify({ type: 'message', message: { role: 'assistant', content: [{ type: 'text', text: 'hi' }] } }) + '\n');
|
|
68
|
-
}
|
|
69
|
-
test('cascade close: middle-node lifecycle close cancels EXACTLY its subtree, ancestor + sideways untouched, edges persist', { skip: !hasTmux() ? 'tmux unavailable' : false, timeout: 180_000 }, async () => {
|
|
70
|
-
const h = await createHarness({ sessionPrefix: 'crtr-cascade' });
|
|
71
|
-
try {
|
|
72
|
-
// ===================================================================
|
|
73
|
-
// BUILD — the real tree. A is the in-process resident root (no pane);
|
|
74
|
-
// B,C,D,E,S,G are real managed children, each a real fake-pi in a real
|
|
75
|
-
// backstage pane (spawnChild awaits each boot). Every `node new` seeds the
|
|
76
|
-
// spine edge parent→child (active) + the spawned_by/parent provenance.
|
|
77
|
-
// ===================================================================
|
|
78
|
-
const A = h.spawnRoot('cascade-close root');
|
|
79
|
-
const B = await h.spawnChild(A, 'middle node — the close target', { kind: 'developer' });
|
|
80
|
-
const C = await h.spawnChild(B, 'B child one');
|
|
81
|
-
const E = await h.spawnChild(C, 'deep leaf under C'); // depth: A→B→C→E
|
|
82
|
-
const D = await h.spawnChild(B, 'B child two'); // breadth: B has {C, D}
|
|
83
|
-
const S = await h.spawnChild(A, 'sideways sibling of B'); // sideways subtree
|
|
84
|
-
const G = await h.spawnChild(S, 'child of the sideways sibling');
|
|
85
|
-
const subtree = [B, C, D, E]; // B's exclusive subtree (the expected cancel set)
|
|
86
|
-
const sideways = [S, G]; // a sibling subtree — must be wholly untouched
|
|
87
|
-
// Make the close-path fixtures NON-EMPTY so close exercises cancel+notice
|
|
88
|
-
// semantics instead of the new reap-empty path.
|
|
89
|
-
for (const id of subtree) {
|
|
90
|
-
const sessionFile = h.node(id).pi_session_file;
|
|
91
|
-
assert.ok(sessionFile !== null && sessionFile !== undefined, `${id} has a session file`);
|
|
92
|
-
seedAssistantSession(sessionFile);
|
|
93
|
-
}
|
|
94
|
-
// Pre-close sanity: every node live + present, spine wired as drawn.
|
|
95
|
-
{
|
|
96
|
-
for (const id of [B, C, D, E, S, G]) {
|
|
97
|
-
assert.ok(h.status(id) === 'active' || h.status(id) === 'idle', `${id} live before close`);
|
|
98
|
-
const pid = h.node(id).pi_pid;
|
|
99
|
-
assert.ok(pid != null && isPidAlive(pid), `${id} broker engine alive before close`);
|
|
100
|
-
}
|
|
101
|
-
assert.ok(h.status(A) === 'active' || h.status(A) === 'idle', 'A (root) live before close');
|
|
102
|
-
// Spine: A→{B,S}, B→{C,D}, C→{E}, S→{G} (all active spawn-seed edges).
|
|
103
|
-
const subIds = (n) => h.subscriptions(n).map((s) => s.node_id).sort();
|
|
104
|
-
assert.deepEqual(subIds(A), [B, S].sort(), 'A subscribes_to B and S');
|
|
105
|
-
assert.deepEqual(subIds(B), [C, D].sort(), 'B subscribes_to C and D');
|
|
106
|
-
assert.deepEqual(subIds(C), [E], 'C subscribes_to E');
|
|
107
|
-
assert.deepEqual(subIds(S), [G], 'S subscribes_to G');
|
|
108
|
-
// provenance edges (spawned_by / parent)
|
|
109
|
-
for (const [child, parent] of [[B, A], [C, B], [E, C], [D, B], [S, A], [G, S]]) {
|
|
110
|
-
assert.equal(h.node(child).parent, parent, `${child}.parent = ${parent}`);
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
// Make A's inbox NON-EMPTY before the close so "ancestor inbox intact" is a
|
|
114
|
-
// non-vacuous assertion: B pushes a routine update up its spine → A (B's
|
|
115
|
-
// sole active subscriber). A is the in-process root with no live watcher,
|
|
116
|
-
// so the pointer simply accumulates and must survive the close untouched.
|
|
117
|
-
{
|
|
118
|
-
const res = h.cli(B, ['push', 'update', 'progress from B before close']);
|
|
119
|
-
assert.equal(res.code, 0, `B push update exit 0\n${res.stderr}`);
|
|
120
|
-
}
|
|
121
|
-
const aInboxBefore = h.inbox(A);
|
|
122
|
-
assert.ok(aInboxBefore.some((e) => e.from === B && e.kind === 'update'), "A's inbox holds B's pre-close update (non-vacuous 'intact' baseline)");
|
|
123
|
-
// ===================================================================
|
|
124
|
-
// CLOSE the MIDDLE node B, through the REAL CLI (`crtr node lifecycle close --node B`,
|
|
125
|
-
// run AS the root A). closeNode is synchronous in the subprocess: by the
|
|
126
|
-
// time it returns, rows are flipped and panes are killed.
|
|
127
|
-
// ===================================================================
|
|
128
|
-
const closeRes = h.cli(A, ['node', 'lifecycle', 'close', '--node', B]);
|
|
129
|
-
assert.equal(closeRes.code, 0, `node lifecycle close exit 0\n${closeRes.stderr}`);
|
|
130
|
-
// The CLI's own rendered report (plain markdown): cascade root B, exactly
|
|
131
|
-
// 4 closed, 0 spared (no spared clause is emitted when none were spared).
|
|
132
|
-
assert.match(closeRes.stdout, new RegExp(`^Closed ${B} and its exclusive subtree — 4 node\\(s\\) closed\\.`), `close report names B as root, count=4, spared=0\n${closeRes.stdout}`);
|
|
133
|
-
// ===================================================================
|
|
134
|
-
// ASSERT 1 — the A5 DELIVERABLE: the EXACT terminal status of every
|
|
135
|
-
// cascade-closed node. With the fixtures now non-empty, close exercises
|
|
136
|
-
// cancel+notice semantics and the rows remain present as canceled husks.
|
|
137
|
-
// ===================================================================
|
|
138
|
-
for (const id of subtree) {
|
|
139
|
-
const n = h.node(id);
|
|
140
|
-
assert.equal(n.status, 'canceled', `${id} terminal status === 'canceled' (cancel event)`);
|
|
141
|
-
assert.strictEqual(n.intent ?? null, null, `${id} intent cleared to null on cancel`);
|
|
142
|
-
}
|
|
143
|
-
// Pin the exact field tuple once more, explicitly, for the human decision:
|
|
144
|
-
// a cascade-closed descendant under `node lifecycle close` reads (canceled, null) —
|
|
145
|
-
// NOT (done, done) and NOT (done, null). This is the confirmed A5 fact.
|
|
146
|
-
{
|
|
147
|
-
const e = h.node(E); // the deepest descendant
|
|
148
|
-
assert.deepEqual({ status: e.status, intent: e.intent ?? null }, { status: 'canceled', intent: null }, "deepest closed descendant E: (status,intent) === ('canceled', null)");
|
|
149
|
-
}
|
|
150
|
-
// ===================================================================
|
|
151
|
-
// ASSERT 2 — broker ENGINE torn down for the ENTIRE subtree (the real
|
|
152
|
-
// "node is up" invariant now: a closed node owns no live broker process).
|
|
153
|
-
// close → headlessBrokerHost.teardown shut each broker down over view.sock.
|
|
154
|
-
// ===================================================================
|
|
155
|
-
for (const id of subtree) {
|
|
156
|
-
await h.waitFor(() => {
|
|
157
|
-
const pid = h.node(id)?.pi_pid ?? null;
|
|
158
|
-
return pid === null || !isPidAlive(pid);
|
|
159
|
-
}, { label: `${id} broker engine torn down by close` });
|
|
160
|
-
const pid = h.node(id)?.pi_pid ?? null;
|
|
161
|
-
assert.ok(pid === null || !isPidAlive(pid), `${id} broker engine destroyed by close`);
|
|
162
|
-
}
|
|
163
|
-
// ===================================================================
|
|
164
|
-
// ASSERT 3 — EXCLUSIVE-SUBTREE OWNERSHIP: nothing ABOVE (A) and nothing
|
|
165
|
-
// SIDEWAYS (S, G) was reaped. close(B) canceled EXACTLY B's own subtree.
|
|
166
|
-
// ===================================================================
|
|
167
|
-
// Ancestor A — lifecycle untouched (still the live resident root), but A is
|
|
168
|
-
// the SURVIVING manager of the close-root B, so the wake doctrine fix WAKES
|
|
169
|
-
// it: a "child closed" notice is fanned to a manager OUTSIDE the closing set
|
|
170
|
-
// (D-1 — previously A heard nothing and a dormant A could hang forever).
|
|
171
|
-
{
|
|
172
|
-
const a = h.node(A);
|
|
173
|
-
assert.equal(a.status, 'active', 'A (ancestor) still active — untouched by the cascade');
|
|
174
|
-
assert.equal(a.lifecycle, 'resident', 'A still resident');
|
|
175
|
-
assert.equal(a.intent ?? null, null, 'A intent untouched');
|
|
176
|
-
// A's PRIOR entries are preserved; exactly ONE new child-closed entry
|
|
177
|
-
// from the closed child B is appended (the doctrine wake).
|
|
178
|
-
const aInbox = h.inbox(A);
|
|
179
|
-
assert.deepEqual(aInbox.slice(0, aInboxBefore.length), aInboxBefore, "A's prior inbox entries are preserved across the close");
|
|
180
|
-
const added = aInbox.slice(aInboxBefore.length);
|
|
181
|
-
assert.equal(added.length, 1, 'exactly one new entry appended to the surviving manager A');
|
|
182
|
-
assert.equal(added[0].from, B, 'the new entry is from the closed child B');
|
|
183
|
-
assert.match(added[0].label, /closed/i, 'the new entry tells A its child B was closed');
|
|
184
|
-
}
|
|
185
|
-
// Sideways subtree S→G — wholly alive: status active AND broker engine alive.
|
|
186
|
-
for (const id of sideways) {
|
|
187
|
-
assert.equal(h.status(id), 'active', `${id} (sideways) still active — not canceled`);
|
|
188
|
-
const pid = h.node(id).pi_pid;
|
|
189
|
-
assert.ok(pid != null && isPidAlive(pid), `${id} (sideways) broker engine still alive`);
|
|
190
|
-
}
|
|
191
|
-
// The strong "EXACTLY its own subtree" closure: every node in the graph is
|
|
192
|
-
// either in B's subtree (canceled) or untouched (active) — no over-reach.
|
|
193
|
-
{
|
|
194
|
-
const reaped = new Set(subtree);
|
|
195
|
-
for (const id of [A, B, C, D, E, S, G]) {
|
|
196
|
-
const want = reaped.has(id) ? 'canceled' : 'active';
|
|
197
|
-
assert.equal(h.status(id), want, `${id} status === '${want}' (no over-/under-reach)`);
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
// ===================================================================
|
|
201
|
-
// ASSERT 4 — EDGES PERSIST (CURRENT behavior + ORACLE §4). close is a pause,
|
|
202
|
-
// not a delete: a closed node keeps its spine + provenance edges so it can
|
|
203
|
-
// be revived. (FLAGGED in the report: the task brief expected "edges
|
|
204
|
-
// removed" — that contradicts current behavior; we assert persistence.)
|
|
205
|
-
// ===================================================================
|
|
206
|
-
{
|
|
207
|
-
const subIds = (n) => h.subscriptions(n).map((s) => s.node_id).sort();
|
|
208
|
-
// Ancestor's spine edge to the closed middle node survives.
|
|
209
|
-
assert.ok(h.subscriptions(A).some((s) => s.node_id === B && s.active), 'A→B subscription edge PERSISTS after close (revivable)');
|
|
210
|
-
// Intra-subtree spine edges survive too.
|
|
211
|
-
assert.deepEqual(subIds(B), [C, D].sort(), 'B→{C,D} edges persist');
|
|
212
|
-
assert.deepEqual(subIds(C), [E], 'C→E edge persists');
|
|
213
|
-
// Provenance (spawned_by / parent) survives.
|
|
214
|
-
for (const [child, parent] of [[B, A], [C, B], [E, C], [D, B]]) {
|
|
215
|
-
assert.equal(h.node(child).parent, parent, `${child}.parent = ${parent} persists`);
|
|
216
|
-
}
|
|
217
|
-
// Sideways edges obviously untouched.
|
|
218
|
-
assert.deepEqual(subIds(S), [G], 'S→G edge untouched');
|
|
219
|
-
}
|
|
220
|
-
// ===================================================================
|
|
221
|
-
// ASSERT 5 — each closed node got its cancellation notice (the resume
|
|
222
|
-
// breadcrumb), appended AFTER its watcher died (close.ts step 3). The root
|
|
223
|
-
// B reads "CLOSED by the user"; descendants read "CANCELED — an ancestor…".
|
|
224
|
-
// ===================================================================
|
|
225
|
-
{
|
|
226
|
-
const bNotice = h.inbox(B).at(-1);
|
|
227
|
-
assert.equal(bNotice.from, null, "B's cancel notice is a system message");
|
|
228
|
-
assert.match(bNotice.label, /CLOSED by the user/, 'B (cascade root) reads the CLOSED notice');
|
|
229
|
-
assert.equal(bNotice.data?.['cascade_root'], B, "B notice records the cascade root");
|
|
230
|
-
const eNotice = h.inbox(E).at(-1);
|
|
231
|
-
assert.match(eNotice.label, /CANCELED/, 'E (descendant) reads the CANCELED notice');
|
|
232
|
-
assert.equal(eNotice.data?.['cascade_root'], B, "E notice records B as the cascade root");
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
finally {
|
|
236
|
-
const session = h.session;
|
|
237
|
-
await h.dispose();
|
|
238
|
-
assert.equal(sessionExists(session), false, 'isolated session killed — no stray');
|
|
239
|
-
}
|
|
240
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
// Run with: node --import tsx/esm --test src/core/__tests__/full/detach-focus.test.ts
|
|
2
|
-
//
|
|
3
|
-
// `crtr node demote --detach` on a node with a live viewer (Alt+C → D).
|
|
4
|
-
//
|
|
5
|
-
// BROKER-CUT ADAPTATION (insights/runtime/broker-is-the-host, 2026-06-10): every node is a
|
|
6
|
-
// detached headless broker. After a09b71f a managed child opens NO viewer on
|
|
7
|
-
// spawn — a viewer is opened on demand via `surface node focus`, registering
|
|
8
|
-
// its `crtr surface attach` VIEWER pane in the focuses table. The engine is NOT in a pane, so the
|
|
9
|
-
// pre-cut "relocate the still-running pi pane to the backstage" behavior —
|
|
10
|
-
// detachToBackground's engine break-pane/release path, and its isGenerating()
|
|
11
|
-
// gate that released a non-generating node to dormant — is DELETED. The Bug-1
|
|
12
|
-
// non-generating-release test that locked that gate is deleted with it (the
|
|
13
|
-
// behavior no longer exists; nothing to invent coverage for).
|
|
14
|
-
//
|
|
15
|
-
// What SURVIVES and is locked here: `node demote --detach` flips the node
|
|
16
|
-
// terminal IN PLACE and CLOSES its viewer pane + focus row, leaving the broker
|
|
17
|
-
// ENGINE running untouched (reconnectable by a later `focus`). This drives the
|
|
18
|
-
// REAL verb (subprocess, AS the node) — the actual Alt+C → D menu path — against
|
|
19
|
-
// a live broker node genuinely focused in a viewer pane, and proves:
|
|
20
|
-
// (a) lifecycle flips terminal in place,
|
|
21
|
-
// (b) the broker engine keeps running (pi_pid alive, unchanged — NOT killed),
|
|
22
|
-
// (c) the viewer pane is closed + its focus row dropped (no orphaned/phantom
|
|
23
|
-
// viewport row — Invariant P / F5).
|
|
24
|
-
import { test } from 'node:test';
|
|
25
|
-
import assert from 'node:assert/strict';
|
|
26
|
-
import { spawnSync } from 'node:child_process';
|
|
27
|
-
import { mkdirSync, writeFileSync } from 'node:fs';
|
|
28
|
-
import { join } from 'node:path';
|
|
29
|
-
import { createHarness, hasTmux, TMUX_TIMEOUT_MS } from '../helpers/harness.js';
|
|
30
|
-
import { paneTag, taggedViewerPanes, waitForOneTaggedViewer } from '../helpers/viewer-panes.js';
|
|
31
|
-
import { getNode } from '../../canvas/canvas.js';
|
|
32
|
-
import { closeDb } from '../../canvas/db.js';
|
|
33
|
-
import { isPidAlive } from '../../canvas/pid.js';
|
|
34
|
-
const SKIP = !hasTmux() ? 'tmux unavailable' : false;
|
|
35
|
-
function sessionExists(session) {
|
|
36
|
-
return (spawnSync('tmux', ['has-session', '-t', session], {
|
|
37
|
-
stdio: 'ignore',
|
|
38
|
-
timeout: TMUX_TIMEOUT_MS,
|
|
39
|
-
}).status === 0);
|
|
40
|
-
}
|
|
41
|
-
function paneExistsReal(pane) {
|
|
42
|
-
return ((spawnSync('tmux', ['display-message', '-p', '-t', pane, '#{pane_id}'], {
|
|
43
|
-
encoding: 'utf8',
|
|
44
|
-
timeout: TMUX_TIMEOUT_MS,
|
|
45
|
-
}).stdout ?? '').trim() === pane);
|
|
46
|
-
}
|
|
47
|
-
// P1 moved the `surface node focus` viewer registry off the `focuses` DB table (the CLI
|
|
48
|
-
// can no longer write canvas.db) onto the tmux `@crtr_node` pane tag a
|
|
49
|
-
// `crtr surface attach` viewer self-sets on connect. These helpers read that
|
|
50
|
-
// pane-tag registry — the ground truth for "which pane is a node's viewer".
|
|
51
|
-
// `paneTag` / `taggedViewerPanes` / `waitForOneTaggedViewer` live in
|
|
52
|
-
// helpers/viewer-panes.ts, shared with the other full-tier viewer tests.
|
|
53
|
-
// Split a throwaway pane in the harness session; return its %id. The caller pane
|
|
54
|
-
// `surface node focus` opens the viewer beside (a09b71f: spawn no longer auto-opens one).
|
|
55
|
-
// Write an assistant message into a node's pi session so it is NOT an empty
|
|
56
|
-
// shell — reapIfEmpty (0515e8d) tears output-less nodes down on detach, which
|
|
57
|
-
// would defeat the "broker survives" contract this test locks.
|
|
58
|
-
function seedAssistantSession(sessionFile) {
|
|
59
|
-
mkdirSync(join(sessionFile, '..'), { recursive: true });
|
|
60
|
-
writeFileSync(sessionFile, JSON.stringify({ type: 'message', message: { role: 'assistant', content: [{ type: 'text', text: 'hi' }] } }) + '\n');
|
|
61
|
-
}
|
|
62
|
-
function makePane(session) {
|
|
63
|
-
const r = spawnSync('tmux', ['split-window', '-d', '-t', session, '-P', '-F', '#{pane_id}', 'sleep 100000'], { encoding: 'utf8', timeout: TMUX_TIMEOUT_MS });
|
|
64
|
-
const pane = (r.stdout ?? '').trim();
|
|
65
|
-
assert.ok(pane.startsWith('%'), `expected a %pane_id, got "${pane}" (stderr: ${r.stderr})`);
|
|
66
|
-
return pane;
|
|
67
|
-
}
|
|
68
|
-
// ===========================================================================
|
|
69
|
-
// `crtr node demote --detach` on a node with a live viewer (Alt+C → D).
|
|
70
|
-
// ===========================================================================
|
|
71
|
-
test('node demote --detach: flips terminal in place, CLOSES the viewer pane + focus row, broker engine keeps running', { skip: SKIP, timeout: 120_000 }, async () => {
|
|
72
|
-
const h = await createHarness({ sessionPrefix: 'crtr-detach-focus' });
|
|
73
|
-
try {
|
|
74
|
-
// A resident root + a live terminal child B. spawnChild launches B's broker
|
|
75
|
-
// but opens NO viewer (a09b71f) — so B has no focus row yet.
|
|
76
|
-
const A = h.spawnRoot('resident root');
|
|
77
|
-
const B = await h.spawnChild(A, 'do the work', { kind: 'developer' });
|
|
78
|
-
const b0 = h.node(B);
|
|
79
|
-
assert.equal(b0.lifecycle, 'terminal', 'B born terminal');
|
|
80
|
-
assert.equal(b0.status, 'active', 'B active after boot');
|
|
81
|
-
const brokerPid = b0.pi_pid;
|
|
82
|
-
assert.ok(brokerPid != null && isPidAlive(brokerPid), 'B broker engine alive before detach');
|
|
83
|
-
// Make B NON-EMPTY (it produced an assistant message) so `--detach`
|
|
84
|
-
// exercises the "close the viewer, broker survives" contract and NOT the
|
|
85
|
-
// reap-empty path (0515e8d), which would tear an output-less shell down.
|
|
86
|
-
assert.ok(b0.pi_session_file != null, 'B has a session file');
|
|
87
|
-
seedAssistantSession(b0.pi_session_file);
|
|
88
|
-
// Put B genuinely "on screen": `surface node focus` opens its one `crtr surface attach`
|
|
89
|
-
// VIEWER pane beside a caller pane in the harness session — the on-demand
|
|
90
|
-
// viewer the detach then tears down.
|
|
91
|
-
const caller = makePane(h.session);
|
|
92
|
-
const focusRes = h.cli(B, ['surface', 'node', 'focus', B, '--pane', caller]);
|
|
93
|
-
assert.equal(focusRes.code, 0, `surface node focus B exit 0\n${focusRes.stderr}`);
|
|
94
|
-
// The viewer pane is the node's on-screen presence, registered by the
|
|
95
|
-
// `@crtr_node` pane tag the attach client self-sets on connect (P1: the CLI
|
|
96
|
-
// no longer writes the focuses DB table) — NOT a node-row pane (a broker
|
|
97
|
-
// carries null placement). Wait for the tag so the real registry is live.
|
|
98
|
-
const viewerPane = await waitForOneTaggedViewer(h.session, B);
|
|
99
|
-
assert.equal(paneExistsReal(viewerPane), true, 'B viewer pane is live on screen');
|
|
100
|
-
// --- Drive the REAL verb on the focused node (the Alt+C → D menu path). ---
|
|
101
|
-
const res = h.cli(B, ['node', 'lifecycle', 'demote', '--node', B, '--pane', viewerPane, '--detach']);
|
|
102
|
-
assert.equal(res.code, 0, `node demote --detach exit 0\n${res.stderr}`);
|
|
103
|
-
assert.match(res.stdout, /viewer closed \(broker still running off-screen\)/, `the viewer was closed\n${res.stdout}`);
|
|
104
|
-
closeDb();
|
|
105
|
-
const b = getNode(B);
|
|
106
|
-
// (a) lifecycle flipped to terminal IN PLACE (it was already terminal; the
|
|
107
|
-
// demote is idempotent on lifecycle — the point is it does not end B).
|
|
108
|
-
assert.equal(b.lifecycle, 'terminal', '(a) B lifecycle=terminal after the flip');
|
|
109
|
-
assert.equal(b.status, 'active', '(a) detach does NOT end the node — B stays active');
|
|
110
|
-
// (b) the broker ENGINE keeps running — detach closes only the viewer, never
|
|
111
|
-
// the engine (the one-host invariant: the engine was never in a pane).
|
|
112
|
-
assert.equal(b.pi_pid, brokerPid, "(b) B's broker pid is UNCHANGED (engine not killed/respawned)");
|
|
113
|
-
assert.equal(isPidAlive(brokerPid), true, '(b) B broker engine still alive off-screen');
|
|
114
|
-
// (c) the viewer pane is CLOSED and its focus row dropped — no orphaned /
|
|
115
|
-
// phantom viewport (A3 hazard / Invariant P).
|
|
116
|
-
await h.waitForPaneGone(B);
|
|
117
|
-
assert.equal(paneExistsReal(viewerPane), false, '(c) B viewer pane closed');
|
|
118
|
-
assert.deepEqual(taggedViewerPanes(h.session, B), [], '(c) B no longer occupies any viewer (untagged — Invariant P)');
|
|
119
|
-
assert.equal(paneTag(viewerPane), '', '(c) NO phantom @crtr_node tag resolves on the closed viewer %id');
|
|
120
|
-
}
|
|
121
|
-
finally {
|
|
122
|
-
const session = h.session;
|
|
123
|
-
await h.dispose();
|
|
124
|
-
assert.equal(sessionExists(session), false, 'isolated session killed — no stray');
|
|
125
|
-
}
|
|
126
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
// Run with: CRTR_MAX_LIVE_BROKERS=1000 node --import tsx/esm --test src/core/__tests__/full/issue-146-yield-spawn-focus.test.ts
|
|
2
|
-
//
|
|
3
|
-
// Issue #146 composed regression: a parent yields while a child launch is in flight,
|
|
4
|
-
// its first cycling broker dies before session_start, and real `surface node focus`
|
|
5
|
-
// then requests a strict resume. The locked revive arbiter must keep the durable refresh
|
|
6
|
-
// authoritative, retry as a fresh cycle, and commit its intent/note only after the
|
|
7
|
-
// retry reaches session_start.
|
|
8
|
-
import { test } from 'node:test';
|
|
9
|
-
import assert from 'node:assert/strict';
|
|
10
|
-
import { spawnSync } from 'node:child_process';
|
|
11
|
-
import { existsSync } from 'node:fs';
|
|
12
|
-
import { createHarness, hasTmux, TMUX_TIMEOUT_MS, } from '../helpers/harness.js';
|
|
13
|
-
import { isPidAlive } from '../../canvas/pid.js';
|
|
14
|
-
import { updateNode } from '../../canvas/canvas.js';
|
|
15
|
-
import { readYieldMessage, yieldMessagePath } from '../../runtime/kickoff.js';
|
|
16
|
-
import { FAIL_BEFORE_SESSION_START_ONCE } from '../fixtures/fake-engine.js';
|
|
17
|
-
const SKIP = !hasTmux() ? 'tmux unavailable' : false;
|
|
18
|
-
function makeCallerPane(session) {
|
|
19
|
-
const result = spawnSync('tmux', ['split-window', '-d', '-t', session, '-P', '-F', '#{pane_id}', 'sleep 100000'], { encoding: 'utf8', timeout: TMUX_TIMEOUT_MS });
|
|
20
|
-
const pane = (result.stdout ?? '').trim();
|
|
21
|
-
assert.ok(pane.startsWith('%'), `expected a tmux pane id, got "${pane}" (stderr: ${result.stderr})`);
|
|
22
|
-
return pane;
|
|
23
|
-
}
|
|
24
|
-
function outputField(stdout, name) {
|
|
25
|
-
return stdout.match(new RegExp(`^- ${name}:\\s*(.*)$`, 'm'))?.[1]?.trim();
|
|
26
|
-
}
|
|
27
|
-
test('yield + concurrent child spawn + failed cycle + focus preserves fresh-refresh authority', { skip: SKIP, timeout: 180_000 }, async () => {
|
|
28
|
-
const h = await createHarness({ sessionPrefix: 'crtr-issue146' });
|
|
29
|
-
try {
|
|
30
|
-
const root = h.spawnRoot('issue 146 acting root');
|
|
31
|
-
const parent = await h.spawnHeadlessChild(root, 'issue 146 orchestrator parent', {
|
|
32
|
-
kind: 'developer',
|
|
33
|
-
mode: 'orchestrator',
|
|
34
|
-
});
|
|
35
|
-
// Keep this test-only orchestrator resident so the fake engine's automatic
|
|
36
|
-
// kickoff turn cannot legitimately idle-release it after session_start; the
|
|
37
|
-
// assertions below can then observe the confirmation commit itself.
|
|
38
|
-
updateNode(parent, { lifecycle: 'resident' });
|
|
39
|
-
const initial = h.node(parent);
|
|
40
|
-
const oldPid = initial.pi_pid;
|
|
41
|
-
const baseBoots = h.bootCount(parent);
|
|
42
|
-
const baseCycles = initial.cycles ?? 0;
|
|
43
|
-
assert.ok(initial.pi_session_file != null && existsSync(initial.pi_session_file), 'parent booted with a real session file');
|
|
44
|
-
assert.equal(isPidAlive(oldPid), true, 'parent broker is alive before yielding');
|
|
45
|
-
// spawnHeadlessChild drives real `node new` synchronously, then yields while
|
|
46
|
-
// awaiting the child broker boot. Start it without awaiting so parent yield
|
|
47
|
-
// overlaps that boot exactly as the reported issue did.
|
|
48
|
-
const childBoot = h.spawnHeadlessChild(parent, 'issue 146 concurrent child');
|
|
49
|
-
const note = `Issue #146 ${FAIL_BEFORE_SESSION_START_ONCE} retain this yield handoff`;
|
|
50
|
-
const yielded = h.cli(parent, ['node', 'yield', note]);
|
|
51
|
-
assert.equal(yielded.code, 0, `node yield should succeed\n--stderr--\n${yielded.stderr}`);
|
|
52
|
-
assert.equal(h.node(parent)?.intent, 'refresh', 'yield durably records refresh intent');
|
|
53
|
-
const child = await childBoot;
|
|
54
|
-
assert.ok(h.subscriptions(parent).some((entry) => entry.node_id === child && entry.active), 'parent remains actively subscribed to the concurrently spawned child');
|
|
55
|
-
// End the old engine turn through the real stophook. Its ChildProcess exit
|
|
56
|
-
// automatically enqueues policy row 3 (refresh → respawn-fresh); no
|
|
57
|
-
// liveness tick or grace is involved. The short-lived-exit throttle may
|
|
58
|
-
// defer the replacement briefly, so observe the new pid rather than a
|
|
59
|
-
// fixed clock.
|
|
60
|
-
await h.stop(parent);
|
|
61
|
-
await h.waitFor(() => !isPidAlive(oldPid), { label: 'yielded parent broker exited' });
|
|
62
|
-
assert.equal(h.node(parent)?.intent, 'refresh', 'refresh intent survives the old broker exit');
|
|
63
|
-
const failedCyclePid = await h.waitFor(() => {
|
|
64
|
-
const pid = h.node(parent)?.pi_pid;
|
|
65
|
-
return pid != null && pid !== oldPid ? pid : null;
|
|
66
|
-
}, { label: 'exit-event refresh launch recorded its broker pid', timeoutMs: 30_000 });
|
|
67
|
-
await h.waitFor(() => !isPidAlive(failedCyclePid), {
|
|
68
|
-
label: 'one-shot cycling broker died before session_start',
|
|
69
|
-
});
|
|
70
|
-
// Capture before focus but assert afterward. This keeps the competing real
|
|
71
|
-
// focus path non-vacuous even if one of these durable preconditions regresses.
|
|
72
|
-
const preFocus = {
|
|
73
|
-
cycles: h.node(parent)?.cycles,
|
|
74
|
-
intent: h.node(parent)?.intent ?? null,
|
|
75
|
-
cyclePending: h.node(parent)?.cycle_pending,
|
|
76
|
-
note: readYieldMessage(parent),
|
|
77
|
-
noteExists: existsSync(yieldMessagePath(parent)),
|
|
78
|
-
boots: h.bootCount(parent),
|
|
79
|
-
};
|
|
80
|
-
const callerPane = makeCallerPane(h.session);
|
|
81
|
-
const focused = h.cli(root, ['surface', 'node', 'focus', parent, '--pane', callerPane]);
|
|
82
|
-
const confirmed = await h.awaitBoot(parent, { minCount: baseBoots + 1, timeoutMs: 120_000 });
|
|
83
|
-
const final = h.node(parent);
|
|
84
|
-
assert.equal(focused.code, 0, `surface node focus should succeed\n--stderr--\n${focused.stderr}`);
|
|
85
|
-
assert.equal(outputField(focused.stdout, 'revived'), 'true', 'real focus drives the production resume=true revive entrypoint');
|
|
86
|
-
assert.equal(preFocus.boots, baseBoots, 'failed cycling launch never reached session_start');
|
|
87
|
-
assert.equal(preFocus.cycles, baseCycles + 1, 'first actual refresh launch increments cycles exactly once');
|
|
88
|
-
assert.equal(preFocus.intent, 'refresh', 'refresh intent survives the pre-session_start failure');
|
|
89
|
-
assert.equal(preFocus.cyclePending, true, 'failed cycling launch remains pending before confirmation');
|
|
90
|
-
assert.equal(preFocus.note?.trim(), note, 'failed launch leaves the complete yield handoff durable');
|
|
91
|
-
assert.equal(preFocus.noteExists, true, 'yield handoff file remains present before confirmation');
|
|
92
|
-
assert.equal(confirmed.resuming, false, 'focus cannot reopen the old session while refresh is pending');
|
|
93
|
-
assert.ok(confirmed.prompt !== null && confirmed.prompt.includes(note), 'successful cycling retry receives the original yield note');
|
|
94
|
-
assert.equal(final.cycles, baseCycles + 2, 'focus retry increments from the locked latest cycle exactly once');
|
|
95
|
-
assert.equal(final.cycle_pending, false, 'confirmed session_start clears the pending-cycle marker');
|
|
96
|
-
assert.equal(final.intent ?? null, null, 'confirmed session_start commits the refresh intent');
|
|
97
|
-
assert.equal(readYieldMessage(parent), null, 'confirmed session_start clears the one-shot yield handoff');
|
|
98
|
-
assert.equal(existsSync(yieldMessagePath(parent)), false, 'yield handoff file is gone only after confirmation');
|
|
99
|
-
const childState = h.node(child);
|
|
100
|
-
assert.equal(childState.status, 'active', 'concurrent child remains booted');
|
|
101
|
-
assert.ok(childState.pi_pid != null && isPidAlive(childState.pi_pid), 'concurrent child broker remains alive');
|
|
102
|
-
assert.ok(h.subscriptions(parent).some((entry) => entry.node_id === child && entry.active), 'parent-child subscription survives the parent refresh');
|
|
103
|
-
}
|
|
104
|
-
finally {
|
|
105
|
-
await h.dispose();
|
|
106
|
-
}
|
|
107
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|