@north-light/crouter 0.3.173 → 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} +27 -179
- 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 +7 -1
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.ts +9 -1
- 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,147 +0,0 @@
|
|
|
1
|
-
// Run with: node --import tsx/esm --test src/core/__tests__/full/broker-attach-limits.test.ts
|
|
2
|
-
//
|
|
3
|
-
// FULL TIER (real-boot-bound): tmux-free, but it boots a REAL broker process
|
|
4
|
-
// (~5s pi-SDK load), so it lives in full/ (CI), not the fast local loop.
|
|
5
|
-
//
|
|
6
|
-
// T8 — the `crtr surface attach` acceptance gate for G4/G7/G8: multi-writer
|
|
7
|
-
// admission, decoder overflow isolation, and backpressure shedding.
|
|
8
|
-
//
|
|
9
|
-
// 3-PART HEADER (headless):
|
|
10
|
-
// (1) CONTRACT — every client that hellos as `controller` is welcomed writable,
|
|
11
|
-
// simultaneously and independently; each writable client may submit, and
|
|
12
|
-
// every connected client (both writers plus a read-only observer) receives
|
|
13
|
-
// the merged stream of both submissions, while a client that hellos as
|
|
14
|
-
// `observer` is rejected with error{read_only} when it tries to drive (G4).
|
|
15
|
-
// An oversized client line is capped and dropped with frame_overflow while
|
|
16
|
-
// the broker and other clients continue operating (G7). A stalled
|
|
17
|
-
// non-reading viewer is shed at the 32 MiB backpressure HWM while the
|
|
18
|
-
// broker and fast viewers remain unaffected (G8).
|
|
19
|
-
// (2) WHY BROKER/SOCKET-LEVEL, NOT PANE/WINDOW — role admission, decoder limits,
|
|
20
|
-
// and the backpressure HWM are broker-process and view.sock contracts. They
|
|
21
|
-
// are exercised over a pure Unix socket using the production ViewSocketClient
|
|
22
|
-
// and raw node:net peers, with a real broker process and no tmux pane or
|
|
23
|
-
// window.
|
|
24
|
-
// (3) HOW THE HEADLESS DRIVE ASSERTS THE CONTRACT — the real socket responses
|
|
25
|
-
// provide the G4 welcome roles, per-writer relay frames and the read-only
|
|
26
|
-
// rejection, the G7 frame-overflow drop and broker survival, and the G8
|
|
27
|
-
// HWM-shed log line and broker survival.
|
|
28
|
-
//
|
|
29
|
-
// One shared broker is booted in before() and reused across all three gates. There
|
|
30
|
-
// is no writer slot to hand off, so every gate simply attaches at the role it
|
|
31
|
-
// wants.
|
|
32
|
-
import { test, before, after, afterEach } from 'node:test';
|
|
33
|
-
import assert from 'node:assert/strict';
|
|
34
|
-
import { createHeadlessHarness } from '../helpers/harness.js';
|
|
35
|
-
import { isPidAlive } from '../../canvas/pid.js';
|
|
36
|
-
import { createAttachKit, delay, tok, frameHas, brokerLogText, } from '../helpers/broker-clients.js';
|
|
37
|
-
let h;
|
|
38
|
-
let id; // ONE shared broker, reused across G4/G7/G8 (1 real boot, not 3)
|
|
39
|
-
const kit = createAttachKit(() => h);
|
|
40
|
-
const { attach, connectRaw } = kit;
|
|
41
|
-
before(async () => {
|
|
42
|
-
h = await createHeadlessHarness({ sessionPrefix: 'crtr-brklim' });
|
|
43
|
-
const root = h.spawnRoot('broker-attach-limits suite root');
|
|
44
|
-
id = await h.spawnHeadlessChild(root, 'headless worker — attach-limits gates');
|
|
45
|
-
});
|
|
46
|
-
after(async () => {
|
|
47
|
-
if (h !== undefined)
|
|
48
|
-
await h.dispose();
|
|
49
|
-
});
|
|
50
|
-
afterEach(() => {
|
|
51
|
-
kit.closeAll();
|
|
52
|
-
});
|
|
53
|
-
const brokerPid = () => h.node(id).pi_pid;
|
|
54
|
-
// ---------------------------------------------------------------------------
|
|
55
|
-
// G4 — multi-writer admission + read-only gating. Guards: two simultaneous
|
|
56
|
-
// `controller` hellos are BOTH welcomed writable, each one's own submission
|
|
57
|
-
// reaches the engine, and every connected client sees BOTH turns; an explicit
|
|
58
|
-
// observer that tries to drive is rejected with error{read_only}.
|
|
59
|
-
// Failure mode: a singleton writer slot demoting the second client, a writer
|
|
60
|
-
// whose prompt is silently dropped, fan-out that misses a viewer, or a
|
|
61
|
-
// read-only client that can drive the engine.
|
|
62
|
-
// ---------------------------------------------------------------------------
|
|
63
|
-
test('G4 — two simultaneous clients are both welcomed controller, each submits, and both see both turns; an observer drive → error{read_only}', async () => {
|
|
64
|
-
const [w1, w2] = await Promise.all([
|
|
65
|
-
attach(id, 'controller', 'g4-writer-1'),
|
|
66
|
-
attach(id, 'controller', 'g4-writer-2'),
|
|
67
|
-
]);
|
|
68
|
-
assert.equal(w1.welcome.role, 'controller', 'first client is welcomed writable');
|
|
69
|
-
assert.equal(w2.welcome.role, 'controller', 'second SIMULTANEOUS client is ALSO welcomed writable (no singleton slot)');
|
|
70
|
-
const observer = await attach(id, 'observer', 'g4-observer');
|
|
71
|
-
assert.equal(observer.welcome.role, 'observer', 'an explicit observer hello stays read-only');
|
|
72
|
-
// A read-only client may not drive the engine — the role is per-client and
|
|
73
|
-
// fixed by its own hello, so this rejection is independent of who else is
|
|
74
|
-
// attached.
|
|
75
|
-
observer.send({ type: 'prompt', text: 'a read-only client must not drive' });
|
|
76
|
-
const err = await observer.waitFrame((f) => f.type === 'error', 'G4 observer prompt rejected');
|
|
77
|
-
assert.equal(err.code, 'read_only', 'G4: observer prompt → error{read_only}');
|
|
78
|
-
// Each writer submits its OWN token. Submissions are sequenced (a prompt sent
|
|
79
|
-
// mid-stream routes as a steer and produces no second turn), so each turn is
|
|
80
|
-
// driven to its terminal agent_end before the next writer submits.
|
|
81
|
-
const tokenA = tok('G4-WRITER-1');
|
|
82
|
-
w1.send({ type: 'prompt', text: tokenA });
|
|
83
|
-
await w1.waitFrame((f) => f.type === 'agent_end' && frameHas(f, tokenA), 'G4 writer 1 saw its own turn');
|
|
84
|
-
const tokenB = tok('G4-WRITER-2');
|
|
85
|
-
w2.send({ type: 'prompt', text: tokenB });
|
|
86
|
-
await w2.waitFrame((f) => f.type === 'agent_end' && frameHas(f, tokenB), 'G4 writer 2 saw its own turn');
|
|
87
|
-
// The merged stream: EVERY connected client — both writers and the read-only
|
|
88
|
-
// observer — receives BOTH writers' turns.
|
|
89
|
-
await w2.waitFrame((f) => f.type === 'agent_end' && frameHas(f, tokenA), 'G4 writer 2 ALSO received writer 1 turn');
|
|
90
|
-
await w1.waitFrame((f) => f.type === 'agent_end' && frameHas(f, tokenB), 'G4 writer 1 ALSO received writer 2 turn');
|
|
91
|
-
await observer.waitFrame((f) => f.type === 'agent_end' && frameHas(f, tokenA), 'G4 observer received writer 1 turn');
|
|
92
|
-
await observer.waitFrame((f) => f.type === 'agent_end' && frameHas(f, tokenB), 'G4 observer received writer 2 turn');
|
|
93
|
-
});
|
|
94
|
-
// ---------------------------------------------------------------------------
|
|
95
|
-
// G7 — decoder overflow (guards C5 OOM). A client line over BROKER_READ_CAPS is
|
|
96
|
-
// cap-and-dropped; the broker survives and other clients are unaffected. Failure
|
|
97
|
-
// mode: an unbounded decoder buffer growing the broker to OOM.
|
|
98
|
-
// ---------------------------------------------------------------------------
|
|
99
|
-
test('G7 — an oversized client line is dropped (frame_overflow), the broker survives, other clients unaffected', { timeout: 30_000 }, async () => {
|
|
100
|
-
const pid = brokerPid();
|
|
101
|
-
const boots = h.bootCount(id);
|
|
102
|
-
const survivor = await attach(id, 'observer', 'g7-survivor');
|
|
103
|
-
// 26 MiB with NO newline > BROKER_READ_CAPS.maxLineBytes (24 MiB) → the bounded
|
|
104
|
-
// FrameDecoder throws FrameOverflowError; the broker drops the peer.
|
|
105
|
-
const bad = await connectRaw(id, { read: true });
|
|
106
|
-
bad.writeRaw(Buffer.alloc(26 * 1024 * 1024, 0x78));
|
|
107
|
-
await bad.waitClosed('G7 oversized peer dropped by the broker');
|
|
108
|
-
await h.waitFor(() => /frame overflow/.test(brokerLogText(h, id)) || null, { label: 'G7 broker logged the frame-overflow drop' });
|
|
109
|
-
// The broker survives and the other client is unaffected: a fresh turn relays.
|
|
110
|
-
const token = tok('G7-AFTER');
|
|
111
|
-
h.fakeCmd(id, { cmd: 'stream', text: token });
|
|
112
|
-
await survivor.waitFrame((f) => f.type === 'agent_end' && frameHas(f, token), 'G7 survivor still receives live frames');
|
|
113
|
-
assert.equal(isPidAlive(pid), true, 'G7: the broker survived the overflow');
|
|
114
|
-
assert.equal(brokerPid(), pid, 'G7: broker pid unchanged');
|
|
115
|
-
assert.equal(h.bootCount(id), boots, 'G7: no reboot');
|
|
116
|
-
});
|
|
117
|
-
// ---------------------------------------------------------------------------
|
|
118
|
-
// G8 — backpressure leak (guards M1). A stalled (non-reading) viewer is shed at
|
|
119
|
-
// the HWM (32 MiB byte cap) while the broker + other viewers are unaffected.
|
|
120
|
-
// Failure mode: an indefinitely-growing per-viewer queue (broker OOM) or a slow
|
|
121
|
-
// viewer back-pressuring the shared engine.
|
|
122
|
-
// ---------------------------------------------------------------------------
|
|
123
|
-
test('G8 — a stalled viewer is dropped at the backpressure HWM; the broker + fast viewers are unaffected', { timeout: 30_000 }, async () => {
|
|
124
|
-
const pid = brokerPid();
|
|
125
|
-
const fast = await attach(id, 'observer', 'g8-fast'); // reads normally
|
|
126
|
-
// A helloed viewer that NEVER reads (paused socket). It must be in the broadcast
|
|
127
|
-
// set before the flood; hello, then a short beat for the broker to process it.
|
|
128
|
-
const stalled = await connectRaw(id, { read: false });
|
|
129
|
-
stalled.send({ type: 'hello', role: 'observer', client_id: 'g8-stalled' });
|
|
130
|
-
await delay(400);
|
|
131
|
-
// A fast event stream: ~60 MiB across 240 message_update frames. The stalled
|
|
132
|
-
// viewer's per-viewer backlog crosses the 32 MiB byte cap → dropped; the fast
|
|
133
|
-
// viewer drains between frames (per-update yield) and survives.
|
|
134
|
-
//
|
|
135
|
-
// The DROP SIGNAL is the broker's own log line, NOT the stalled socket's 'close':
|
|
136
|
-
// a PAUSED node socket does not surface the peer FIN/close until it is resumed,
|
|
137
|
-
// so the broker-side `backpressure high-water mark exceeded` line is the
|
|
138
|
-
// deterministic, race-free proof that the slow viewer was shed at the HWM.
|
|
139
|
-
const token = tok('G8-FLOOD');
|
|
140
|
-
h.fakeCmd(id, { cmd: 'stream', text: token, updates: 240, padBytes: 256 * 1024, tool: false });
|
|
141
|
-
await h.waitFor(() => /backpressure high-water mark exceeded/.test(brokerLogText(h, id)) || null, { label: 'G8 broker shed the stalled viewer at the HWM', timeoutMs: 30_000 });
|
|
142
|
-
// The fast viewer drained the WHOLE stream (agent_end is the terminal frame) —
|
|
143
|
-
// proving only the stalled viewer was shed, while the fast one was unaffected.
|
|
144
|
-
await fast.waitFrame((f) => f.type === 'agent_end' && frameHas(f, token), 'G8 fast viewer received the whole stream', 30_000);
|
|
145
|
-
assert.equal(isPidAlive(pid), true, 'G8: the broker survived the slow-viewer flood');
|
|
146
|
-
assert.equal(brokerPid(), pid, 'G8: broker pid unchanged (the engine was not back-pressured into a restart)');
|
|
147
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
// Run with: node --import tsx/esm --test src/core/__tests__/full/broker-deliver-ack.test.ts
|
|
2
|
-
//
|
|
3
|
-
// Regression for the interactive `deliver` ack (broker.ts `case 'deliver'`):
|
|
4
|
-
// the ack must report the ENGINE CALL's real outcome, not the fact that a call
|
|
5
|
-
// was routed. A `session.prompt()` that REJECTS outright — the shape a broker
|
|
6
|
-
// whose model resolved but whose provider has no installed credential produces
|
|
7
|
-
// ("No API key found for anthropic") — used to still ack ok:true, so crtrd
|
|
8
|
-
// returned `delivered:true, delivered_via:engine` for a message the engine had
|
|
9
|
-
// refused, and the one-shot client closed before the error frame arrived: the
|
|
10
|
-
// message vanished with no trace. Now the deliver ack races acceptance (the
|
|
11
|
-
// engine's own agent_start) against rejection, acks ok:false on rejection, and
|
|
12
|
-
// records `broker.prompt.deliver_failed` in the node's job/log.jsonl.
|
|
13
|
-
import { test, before, after, afterEach } from 'node:test';
|
|
14
|
-
import assert from 'node:assert/strict';
|
|
15
|
-
import { readFileSync } from 'node:fs';
|
|
16
|
-
import { join } from 'node:path';
|
|
17
|
-
import { createHeadlessHarness } from '../helpers/harness.js';
|
|
18
|
-
import { createAttachKit, brokerLogText } from '../helpers/broker-clients.js';
|
|
19
|
-
import { REJECT_PROMPT_CALL } from '../fixtures/fake-engine.js';
|
|
20
|
-
let h;
|
|
21
|
-
const kit = createAttachKit(() => h);
|
|
22
|
-
// Fired lifecycle hooks land one line each in fake-pi.events.jsonl.
|
|
23
|
-
function eventCount(id, name) {
|
|
24
|
-
try {
|
|
25
|
-
return readFileSync(join(h.home, 'nodes', id, 'fake-pi.events.jsonl'), 'utf8')
|
|
26
|
-
.split('\n')
|
|
27
|
-
.filter((l) => {
|
|
28
|
-
try {
|
|
29
|
-
return JSON.parse(l).event === name;
|
|
30
|
-
}
|
|
31
|
-
catch {
|
|
32
|
-
return false;
|
|
33
|
-
}
|
|
34
|
-
}).length;
|
|
35
|
-
}
|
|
36
|
-
catch {
|
|
37
|
-
return 0;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
before(async () => {
|
|
41
|
-
h = await createHeadlessHarness({ sessionPrefix: 'crtr-deliver-ack' });
|
|
42
|
-
});
|
|
43
|
-
after(async () => {
|
|
44
|
-
if (h !== undefined)
|
|
45
|
-
await h.dispose();
|
|
46
|
-
});
|
|
47
|
-
afterEach(() => {
|
|
48
|
-
kit.closeAll();
|
|
49
|
-
});
|
|
50
|
-
test('a deliver whose prompt rejects acks ok:false and records deliver_failed; a succeeding deliver still acks ok:true via prompt', { timeout: 30_000 }, async () => {
|
|
51
|
-
const parent = h.spawnRoot('deliver ack parent');
|
|
52
|
-
const child = await h.spawnHeadlessChild(parent, 'deliver ack child');
|
|
53
|
-
// Let the kickoff turn fully settle so both delivers route as `prompt`
|
|
54
|
-
// (idle), never `steer` — the steer route legitimately acks at routing time.
|
|
55
|
-
await h.waitFor(() => (eventCount(child, 'agent_end') >= 1 ? true : null), {
|
|
56
|
-
label: 'kickoff turn settled',
|
|
57
|
-
});
|
|
58
|
-
const ctrl = await kit.attach(child, 'controller', 'deliver-ack-test');
|
|
59
|
-
// FAILURE: the engine refuses the call itself. Before the fix this acked
|
|
60
|
-
// ok:true and the rejection left no trace in the node's log.
|
|
61
|
-
ctrl.send({ type: 'deliver', id: 'd-fail', text: `do a thing ${REJECT_PROMPT_CALL}` });
|
|
62
|
-
const failAck = await ctrl.waitFrame((f) => f.type === 'ack' && f.for === 'deliver' && f.id === 'd-fail', 'rejected deliver ack');
|
|
63
|
-
assert.equal(failAck.type === 'ack' && failAck.ok, false, 'a rejected prompt must not ack delivered:true');
|
|
64
|
-
assert.match((failAck.type === 'ack' ? failAck.detail : undefined) ?? '', /No API key found/, 'the ack detail carries the engine rejection');
|
|
65
|
-
await h.waitFor(() => (brokerLogText(h, child).includes('broker.prompt.deliver_failed') ? true : null), { label: 'broker.prompt.deliver_failed recorded in job/log.jsonl' });
|
|
66
|
-
// POSITIVE CONTROL: an ordinary deliver still acks ok:true from acceptance
|
|
67
|
-
// (the engine's agent_start), detail naming the prompt route.
|
|
68
|
-
ctrl.send({ type: 'deliver', id: 'd-ok', text: 'an ordinary interactive message' });
|
|
69
|
-
const okAck = await ctrl.waitFrame((f) => f.type === 'ack' && f.for === 'deliver' && f.id === 'd-ok', 'accepted deliver ack');
|
|
70
|
-
assert.equal(okAck.type === 'ack' && okAck.ok, true, 'an accepted prompt acks delivered:true');
|
|
71
|
-
assert.equal(okAck.type === 'ack' ? okAck.detail : undefined, 'prompt');
|
|
72
|
-
ctrl.close();
|
|
73
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,180 +0,0 @@
|
|
|
1
|
-
// Run with: node --import tsx/esm --test src/core/__tests__/full/broker-dialogs.test.ts
|
|
2
|
-
//
|
|
3
|
-
// FULL TIER (real-boot-bound): tmux-free, but it boots a REAL broker process
|
|
4
|
-
// (~5s pi-SDK load), so it lives in full/ (CI), not the fast local loop.
|
|
5
|
-
//
|
|
6
|
-
// Broker dialog handling under MULTI-WRITER attachments — the T8 attach gates
|
|
7
|
-
// G5/G5b/G6 cover fan-out + first-response settlement, mid-dialog attach replay,
|
|
8
|
-
// and attended-dialog timeout behavior.
|
|
9
|
-
//
|
|
10
|
-
// 3-PART HEADER (headless):
|
|
11
|
-
// (1) CONTRACT — every client whose `hello` claimed the writable role is fanned a
|
|
12
|
-
// blocking dialog as extension_ui_request; the FIRST extension_ui_response
|
|
13
|
-
// settles it with that answer (not the default), every fanned client receives
|
|
14
|
-
// the correlated extension_ui_dismiss, and a later peer response for the same
|
|
15
|
-
// id is a silent no-op (G5). A dialog stays pending through a peer's detach and
|
|
16
|
-
// is handed to any writable client attaching mid-dialog via
|
|
17
|
-
// welcome.pending_dialog; observers never receive an answerable dialog (G5b).
|
|
18
|
-
// An attended dialog nobody answers resolves on the short per-dialog timeout
|
|
19
|
-
// with the default answer and a correlated dismiss to EVERY writable peer (G6).
|
|
20
|
-
// (2) WHY BROKER/SOCKET-LEVEL, NOT PANE/WINDOW — the dialog round-trip is an async
|
|
21
|
-
// promise inside makeBrokerUiContext, fanned out and answered over view.sock to
|
|
22
|
-
// the production ViewSocketClient. The real broker process provides the
|
|
23
|
-
// uiContext and timeout machinery without a tmux pane, window, or pi-session
|
|
24
|
-
// read.
|
|
25
|
-
// (3) HOW THE HEADLESS DRIVE ASSERTS THE CONTRACT — the fake engine raises real
|
|
26
|
-
// confirm() dialogs through the broker, and the tests assert on the frames of
|
|
27
|
-
// several concurrently attached clients plus the value and latency recorded in
|
|
28
|
-
// fake-pi.dialog.jsonl.
|
|
29
|
-
//
|
|
30
|
-
// One shared broker is booted in before() and reused across all three gates. Because
|
|
31
|
-
// fake-pi.dialog.jsonl is append-only across the shared broker, each gate snapshots
|
|
32
|
-
// the count before it drives (`base`) and asserts on its newly appended entry. Role
|
|
33
|
-
// is fixed by `hello` and never reassigned, so every writable attach is a plain
|
|
34
|
-
// attach — there is no control handoff to wait out.
|
|
35
|
-
import { test, before, after, afterEach } from 'node:test';
|
|
36
|
-
import assert from 'node:assert/strict';
|
|
37
|
-
import { createHeadlessHarness } from '../helpers/harness.js';
|
|
38
|
-
import { isPidAlive } from '../../canvas/pid.js';
|
|
39
|
-
import { createAttachKit } from '../helpers/broker-clients.js';
|
|
40
|
-
let h;
|
|
41
|
-
let id; // ONE shared broker, reused across G5/G5b/G6 (1 real boot, not 3)
|
|
42
|
-
const kit = createAttachKit(() => h);
|
|
43
|
-
const { attach, attachUntil } = kit;
|
|
44
|
-
// Attach a writable client. Every `hello` claiming `controller` is admitted
|
|
45
|
-
// writable — attaching a peer never demotes an already-attached one.
|
|
46
|
-
const writer = async (cid) => {
|
|
47
|
-
const a = await attach(id, 'controller', cid);
|
|
48
|
-
assert.equal(a.welcome.role, 'controller', `${cid}: admitted writable, not demoted by an existing peer`);
|
|
49
|
-
return a;
|
|
50
|
-
};
|
|
51
|
-
const observer = async (cid) => {
|
|
52
|
-
const a = await attach(id, 'observer', cid);
|
|
53
|
-
assert.equal(a.welcome.role, 'observer', `${cid}: an observer hello stays read-only`);
|
|
54
|
-
return a;
|
|
55
|
-
};
|
|
56
|
-
// The broker handles one client's frames in order, so an `ack` for a get_commands
|
|
57
|
-
// sent AFTER some other frame proves that earlier frame was already processed.
|
|
58
|
-
// Used to make "a late peer answer changed nothing" a deterministic assertion
|
|
59
|
-
// instead of a sleep.
|
|
60
|
-
const barrier = async (c, label) => {
|
|
61
|
-
c.send({ type: 'get_commands' });
|
|
62
|
-
await c.waitFrame((f) => f.type === 'ack' && f.for === 'get_commands', label);
|
|
63
|
-
};
|
|
64
|
-
const isRequest = (f) => f.type === 'extension_ui_request';
|
|
65
|
-
const dismissFor = (reqId) => (f) => f.type === 'extension_ui_dismiss' && f.id === reqId;
|
|
66
|
-
// dialog.jsonl is append-only across the shared broker — snapshot the count, then
|
|
67
|
-
// wait for AT LEAST `want` new entries and return the full (cumulative) array.
|
|
68
|
-
const dialogCount = () => h.dialogResults(id).length;
|
|
69
|
-
const awaitDialogs = (atLeast, label) => h.waitFor(() => (h.dialogResults(id).length >= atLeast ? h.dialogResults(id) : null), { label, timeoutMs: 15_000 });
|
|
70
|
-
before(async () => {
|
|
71
|
-
h = await createHeadlessHarness({ sessionPrefix: 'crtr-brkdlg' });
|
|
72
|
-
const root = h.spawnRoot('broker-dialogs suite root');
|
|
73
|
-
id = await h.spawnHeadlessChild(root, 'headless worker — dialog gates');
|
|
74
|
-
});
|
|
75
|
-
after(async () => {
|
|
76
|
-
if (h !== undefined)
|
|
77
|
-
await h.dispose();
|
|
78
|
-
});
|
|
79
|
-
afterEach(() => {
|
|
80
|
-
kit.closeAll();
|
|
81
|
-
});
|
|
82
|
-
const brokerPid = () => h.node(id).pi_pid;
|
|
83
|
-
// ---------------------------------------------------------------------------
|
|
84
|
-
// G5 — fan-out + first-response settlement. Guards: ONE blocking dialog reaches
|
|
85
|
-
// EVERY writable client (never a single owner), the first answer unblocks the
|
|
86
|
-
// engine with ITS value (not the default), every fanned client gets the correlated
|
|
87
|
-
// extension_ui_dismiss, and a peer answering afterwards is a no-op. Failure modes:
|
|
88
|
-
// a dialog only one viewer can see (the others sit blind), peers left holding an
|
|
89
|
-
// overlay nothing can answer, or a late peer answer re-settling a dead dialog.
|
|
90
|
-
// ---------------------------------------------------------------------------
|
|
91
|
-
test('G5 — one dialog fans out to both writable clients, the first response settles it, both are dismissed, and a late peer response is a no-op', async () => {
|
|
92
|
-
const base = dialogCount();
|
|
93
|
-
const a = await writer('g5-A');
|
|
94
|
-
const b = await writer('g5-B');
|
|
95
|
-
const obs = await observer('g5-obs'); // must never be fanned an answerable dialog
|
|
96
|
-
h.fakeCmd(id, { cmd: 'dialog', timeout: 20_000 }); // generous: a writable client answers first
|
|
97
|
-
const reqA = await a.waitFrame(isRequest, 'G5 dialog fanned out to writable A');
|
|
98
|
-
const reqB = await b.waitFrame(isRequest, 'G5 dialog fanned out to writable B');
|
|
99
|
-
const reqId = reqA.id;
|
|
100
|
-
assert.equal(reqB.id, reqId, 'G5: both writable clients were fanned the SAME dialog id, not two dialogs');
|
|
101
|
-
assert.equal(reqA.method, 'confirm', 'G5: the fanned dialog is the confirm() the engine raised');
|
|
102
|
-
// A answers first — the engine must proceed with A's true, not the false default.
|
|
103
|
-
a.send({ type: 'extension_ui_response', id: reqId, confirmed: true });
|
|
104
|
-
await a.waitFrame(dismissFor(reqId), 'G5 answerer A receives the correlated dismiss');
|
|
105
|
-
await b.waitFrame(dismissFor(reqId), 'G5 peer B receives the correlated dismiss for the dialog it never answered');
|
|
106
|
-
const results = await awaitDialogs(base + 1, 'G5 dialog settled by the first response');
|
|
107
|
-
assert.equal(results[base].resolved, true, 'G5: the engine proceeded with the first answer (true), not the default (false)');
|
|
108
|
-
// The observer was attached the whole time: it saw the broadcast dismiss but was
|
|
109
|
-
// never handed the answerable request.
|
|
110
|
-
await obs.waitFrame(dismissFor(reqId), 'G5 observer sees the broadcast dismiss (ordering barrier)');
|
|
111
|
-
assert.equal(obs.frames.filter(isRequest).length, 0, 'G5: an observer is never fanned an answerable dialog');
|
|
112
|
-
assert.equal(obs.welcome.pending_dialog, null, 'G5: an observer welcome never carries a pending dialog');
|
|
113
|
-
// B answers the already-settled dialog. The broker deleted the entry on the first
|
|
114
|
-
// response, so this finds nothing and is a silent no-op: no second engine
|
|
115
|
-
// resolution, and the recorded answer stays A's.
|
|
116
|
-
b.send({ type: 'extension_ui_response', id: reqId, confirmed: false });
|
|
117
|
-
await barrier(b, 'G5 broker processed B late response (ordered ack)');
|
|
118
|
-
const settled = h.dialogResults(id);
|
|
119
|
-
assert.equal(settled.length, base + 1, 'G5: the late peer response resolved nothing — no second dialog entry');
|
|
120
|
-
assert.equal(settled[base].resolved, true, "G5: the late peer response did not overwrite the first answerer's value");
|
|
121
|
-
assert.equal(isPidAlive(brokerPid()), true, 'G5: the late no-op response did not fault the broker');
|
|
122
|
-
});
|
|
123
|
-
// ---------------------------------------------------------------------------
|
|
124
|
-
// G5b (mid-dialog attach) — Guards: a pending dialog survives a writable peer's
|
|
125
|
-
// detach (M2) and is handed to a writable client that attaches MID-dialog via
|
|
126
|
-
// welcome.pending_dialog, which makes it a full peer in the race to answer. An
|
|
127
|
-
// observer attaching mid-dialog gets nothing answerable. Failure modes: a pending
|
|
128
|
-
// dialog lost when the raising viewer detaches, a late-joining writable viewer
|
|
129
|
-
// blind to an in-flight dialog, or an observer handed one it cannot answer.
|
|
130
|
-
// ---------------------------------------------------------------------------
|
|
131
|
-
test('G5b — a writable client attaching MID-dialog receives the pending dialog; an observer does not', async () => {
|
|
132
|
-
const base = dialogCount();
|
|
133
|
-
const a = await writer('g5b-A');
|
|
134
|
-
h.fakeCmd(id, { cmd: 'dialog', timeout: 30_000 }); // stays pending long enough for the late attach
|
|
135
|
-
const reqA = await a.waitFrame(isRequest, 'G5b dialog fanned out to writable A');
|
|
136
|
-
const reqId = reqA.id;
|
|
137
|
-
a.send({ type: 'bye' });
|
|
138
|
-
a.close(); // M2: a writable peer detaching does NOT cancel the pending dialog
|
|
139
|
-
// An observer attaching mid-dialog is never handed it.
|
|
140
|
-
const obs = await observer('g5b-obs');
|
|
141
|
-
assert.equal(obs.welcome.pending_dialog, null, 'G5b: an observer attaching mid-dialog gets no pending dialog');
|
|
142
|
-
// A writable client attaching mid-dialog IS handed it (retry covers the beat
|
|
143
|
-
// between the raise and this attach) and can settle it.
|
|
144
|
-
const b = await attachUntil(id, 'controller', 'g5b-B', (x) => x.welcome.role === 'controller' && x.welcome.pending_dialog != null, 'G5b writable B attaches mid-dialog and is handed the pending dialog');
|
|
145
|
-
assert.equal(b.welcome.pending_dialog.id, reqId, 'G5b: welcome.pending_dialog is the same dialog raised while A was attached');
|
|
146
|
-
assert.equal(b.welcome.pending_dialog.method, 'confirm', 'G5b: the pending dialog is the confirm()');
|
|
147
|
-
b.send({ type: 'extension_ui_response', id: reqId, confirmed: true });
|
|
148
|
-
const results = await awaitDialogs(base + 1, 'G5b dialog settled by the mid-dialog joiner');
|
|
149
|
-
assert.equal(results[base].resolved, true, 'G5b: the mid-dialog joiner answered and the engine proceeded');
|
|
150
|
-
await obs.waitFrame(dismissFor(reqId), 'G5b dismiss broadcast follows the settlement (ordering barrier)');
|
|
151
|
-
assert.equal(obs.frames.filter(isRequest).length, 0, 'G5b: the observer was never fanned the dialog it saw dismissed');
|
|
152
|
-
});
|
|
153
|
-
// ---------------------------------------------------------------------------
|
|
154
|
-
// G6 — anti-deadlock. An ATTENDED dialog NO writable client answers resolves on a
|
|
155
|
-
// SHORT per-dialog broker timeout, and every fanned peer is dismissed by id.
|
|
156
|
-
// Guards: the engine never hangs on a dialog whose viewers all stay silent.
|
|
157
|
-
// Failure mode: a forever-blocked turn, or overlays left up on every viewer.
|
|
158
|
-
// ---------------------------------------------------------------------------
|
|
159
|
-
test('G6 — an attended dialog no writable client answers resolves on the broker timeout and dismisses every peer', async () => {
|
|
160
|
-
const pid = brokerPid();
|
|
161
|
-
const base = dialogCount();
|
|
162
|
-
// Two writable clients attached but silent → the broker resolves on the SHORT
|
|
163
|
-
// explicit per-dialog timeout (800ms), never the 120s default. On timeout it
|
|
164
|
-
// broadcasts a correlated `extension_ui_dismiss` keyed to the dialog's id, so
|
|
165
|
-
// EVERY peer's overlay (none has an independent timer) is torn down by id.
|
|
166
|
-
const a = await writer('g6-A');
|
|
167
|
-
const b = await writer('g6-B');
|
|
168
|
-
h.fakeCmd(id, { cmd: 'dialog', timeout: 800 });
|
|
169
|
-
const reqA = await a.waitFrame(isRequest, 'G6 dialog fanned out to writable A'); // received, deliberately NOT answered
|
|
170
|
-
const reqB = await b.waitFrame(isRequest, 'G6 dialog fanned out to writable B'); // received, deliberately NOT answered
|
|
171
|
-
const reqId = reqA.id;
|
|
172
|
-
assert.equal(reqB.id, reqId, 'G6: both silent peers hold the SAME dialog id');
|
|
173
|
-
const dismissA = await a.waitFrame(dismissFor(reqId), 'G6 broker emits a correlated dismiss to A on timeout');
|
|
174
|
-
await b.waitFrame(dismissFor(reqId), 'G6 broker emits the same correlated dismiss to peer B');
|
|
175
|
-
assert.equal(dismissA.id, reqId, 'G6: the dismiss frame carries the timed-out dialog id, not another');
|
|
176
|
-
const results = await awaitDialogs(base + 1, 'G6 attended dialog resolved on timeout');
|
|
177
|
-
assert.equal(results[base].resolved, false, 'G6: a dialog no writable client answered resolves to the default (deny)');
|
|
178
|
-
assert.ok(results[base].ms >= 600 && results[base].ms < 5000, `G6: resolved on the ~800ms per-dialog timeout, not instantly and not the 120s default — got ${results[base].ms}ms`);
|
|
179
|
-
assert.equal(isPidAlive(pid), true, 'G6: the engine made forward progress (still alive)');
|
|
180
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
// Run with: node --import tsx/esm --test src/core/__tests__/full/broker-display-snapshot.test.ts
|
|
2
|
-
//
|
|
3
|
-
// FULL TIER (real-boot-bound): tmux-free, but it boots a REAL broker process
|
|
4
|
-
// (~5s pi-SDK load), so it lives in full/ (CI), not the fast local loop.
|
|
5
|
-
//
|
|
6
|
-
// 3-PART HEADER (headless):
|
|
7
|
-
// (1) CONTRACT — catch-up is ONE atomic frame. `ctx.ui.setStatus/setWidget/
|
|
8
|
-
// setTitle` are LEVELS with no pi getter, so the broker is their only holder;
|
|
9
|
-
// it ships that held state as `welcome.snapshot.display` and sends NO
|
|
10
|
-
// `display_*` frames after the welcome. A late joiner therefore renders
|
|
11
|
-
// complete chrome on its FIRST paint.
|
|
12
|
-
// (2) WHY BROKER/SOCKET-LEVEL, NOT PANE/WINDOW — the retention lives in the real
|
|
13
|
-
// broker process (displayStatuses/displayWidgets/displayTitle, painted through
|
|
14
|
-
// the real makeBrokerUiContext relay) and the catch-up shape is a wire fact on
|
|
15
|
-
// view.sock. No tmux pane, window, or pi-session read is involved.
|
|
16
|
-
// (3) HOW THE HEADLESS DRIVE ASSERTS THE CONTRACT — the fake engine paints through
|
|
17
|
-
// the broker's REAL uiContext with NO viewer attached (so nothing is observed
|
|
18
|
-
// live and only retention can carry it), then a viewer attaches and we assert
|
|
19
|
-
// on its welcome payload and on the ABSENCE of any post-welcome display frame.
|
|
20
|
-
//
|
|
21
|
-
// This is the regression guard for the pre-2026-07-24 shape, where `sendWelcome`
|
|
22
|
-
// re-emitted N synthetic `display_*` edge frames after the snapshot: catch-up was
|
|
23
|
-
// non-atomic, the viewer had to clear-and-rebuild (painting blank chrome in the
|
|
24
|
-
// gap), and `applySnapshot(welcome) === fold(reduce, events)` was false by
|
|
25
|
-
// construction. Deleting the replay without adding `snapshot.display` would drop
|
|
26
|
-
// the chrome entirely; adding `snapshot.display` without deleting the replay would
|
|
27
|
-
// leave catch-up non-atomic. Both halves fail this test.
|
|
28
|
-
import { test, before, after, afterEach } from 'node:test';
|
|
29
|
-
import assert from 'node:assert/strict';
|
|
30
|
-
import { createHeadlessHarness } from '../helpers/harness.js';
|
|
31
|
-
import { createAttachKit, delay } from '../helpers/broker-clients.js';
|
|
32
|
-
let h;
|
|
33
|
-
let id;
|
|
34
|
-
const kit = createAttachKit(() => h);
|
|
35
|
-
before(async () => {
|
|
36
|
-
h = await createHeadlessHarness({ sessionPrefix: 'crtr-brkdisp' });
|
|
37
|
-
const root = h.spawnRoot('broker-display-snapshot suite root');
|
|
38
|
-
id = await h.spawnHeadlessChild(root, 'headless worker — display catch-up');
|
|
39
|
-
});
|
|
40
|
-
after(async () => {
|
|
41
|
-
if (h !== undefined)
|
|
42
|
-
await h.dispose();
|
|
43
|
-
});
|
|
44
|
-
afterEach(() => {
|
|
45
|
-
kit.closeAll();
|
|
46
|
-
});
|
|
47
|
-
/** The three display METHODS of pi's uniform `extension_ui_request` envelope. */
|
|
48
|
-
const DISPLAY_METHODS = new Set(['setStatus', 'setWidget', 'setTitle']);
|
|
49
|
-
const isDisplayFrame = (f) => f.type === 'extension_ui_request' && f.method !== undefined && DISPLAY_METHODS.has(f.method);
|
|
50
|
-
test('retained extension display state rides IN welcome.snapshot.display — and no display edge follows', async () => {
|
|
51
|
-
// Paint with ZERO viewers attached: the only path from here to a viewer is the
|
|
52
|
-
// broker's retained last-value, so nothing about this test can pass by luck of
|
|
53
|
-
// having observed the live edge.
|
|
54
|
-
h.fakeCmd(id, { cmd: 'display', text: 'crtr-brief', reason: 'painted while detached' });
|
|
55
|
-
const a = await kit.attachUntil(id, 'observer', 'disp-late-joiner', (at) => at.welcome.snapshot.display?.statuses['crtr-brief'] !== undefined, 'welcome.snapshot.display carries the retained status');
|
|
56
|
-
const display = a.welcome.snapshot.display;
|
|
57
|
-
assert.equal(display.statuses['crtr-brief'], 'painted while detached', 'setStatus level survived in the snapshot');
|
|
58
|
-
assert.deepEqual(display.widgets['crtr-brief'], { lines: ['painted while detached'], placement: 'aboveEditor' }, 'setWidget level survived in the snapshot, placement included');
|
|
59
|
-
assert.equal(display.title, 'painted while detached', 'setTitle level survived in the snapshot');
|
|
60
|
-
// Atomicity: the welcome is COMPLETE. Give the broker a generous beat to emit a
|
|
61
|
-
// replay it must not emit, then assert nothing display-shaped arrived at all.
|
|
62
|
-
await delay(500);
|
|
63
|
-
assert.deepEqual(a.frames.filter((f) => isDisplayFrame(f)).map((f) => f.method), [], 'catch-up is the welcome alone — no synthetic display edges replayed after it');
|
|
64
|
-
// A LIVE paint still arrives as an edge frame: the snapshot replaces the replay,
|
|
65
|
-
// not the ongoing relay.
|
|
66
|
-
h.fakeCmd(id, { cmd: 'display', text: 'crtr-live', reason: 'painted while attached' });
|
|
67
|
-
const live = (await a.waitFrame((f) => f.type === 'extension_ui_request' && f.statusKey === 'crtr-live', 'a live setStatus still relays as an extension_ui_request edge'));
|
|
68
|
-
assert.equal(live.method, 'setStatus');
|
|
69
|
-
assert.equal(live.statusText, 'painted while attached');
|
|
70
|
-
// And a viewer attaching AFTER that sees the union of both keys in one frame.
|
|
71
|
-
const b = await kit.attachUntil(id, 'observer', 'disp-second-joiner', (at) => at.welcome.snapshot.display?.statuses['crtr-live'] !== undefined, 'the second welcome carries both retained keys');
|
|
72
|
-
const bDisplay = b.welcome.snapshot.display;
|
|
73
|
-
assert.equal(bDisplay.statuses['crtr-brief'], 'painted while detached');
|
|
74
|
-
assert.equal(bDisplay.statuses['crtr-live'], 'painted while attached');
|
|
75
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
// Run with: node --import tsx/esm --test src/core/__tests__/full/broker-dormant-wake.test.ts
|
|
2
|
-
//
|
|
3
|
-
// Full-tier model-less broker coverage: a real model-less boot receives auth and
|
|
4
|
-
// re-drives launch through the broker's login path.
|
|
5
|
-
import { test, before, after, afterEach } from 'node:test';
|
|
6
|
-
import assert from 'node:assert/strict';
|
|
7
|
-
import { join } from 'node:path';
|
|
8
|
-
import { readFileSync, writeFileSync, rmSync } from 'node:fs';
|
|
9
|
-
import { createHarness } from '../helpers/harness.js';
|
|
10
|
-
import { createAttachKit } from '../helpers/broker-clients.js';
|
|
11
|
-
let h;
|
|
12
|
-
const kit = createAttachKit(() => h);
|
|
13
|
-
const { attachUntil } = kit;
|
|
14
|
-
before(async () => {
|
|
15
|
-
h = await createHarness({ headless: true, sessionPrefix: 'crtr-brkdorm' });
|
|
16
|
-
});
|
|
17
|
-
after(async () => {
|
|
18
|
-
if (h !== undefined)
|
|
19
|
-
await h.dispose();
|
|
20
|
-
});
|
|
21
|
-
afterEach(() => {
|
|
22
|
-
kit.closeAll();
|
|
23
|
-
});
|
|
24
|
-
// The zero-auth test seam: while <CRTR_HOME>/fake-pi.no-auth exists, the fake
|
|
25
|
-
// engine's modelRegistry reports a GENUINE zero-auth boot (nothing registered,
|
|
26
|
-
// nothing authenticated). HOME-global (not per-node-dir) is deliberate — the
|
|
27
|
-
// test arms it BEFORE spawning (race-free vs the broker's boot-time registry
|
|
28
|
-
// read), and DELETING it mid-test flips auth ON, which a reload_auth
|
|
29
|
-
// modelRegistry.refresh() re-reads live. See fake-engine.ts createAgentSessionServices.
|
|
30
|
-
const noAuthSentinel = () => join(h.home, 'fake-pi.no-auth');
|
|
31
|
-
// The node's recorded model (fake-pi.model.json, written by the fake's
|
|
32
|
-
// recordModel) — `null` for a model-less boot. A disk read, so it survives the
|
|
33
|
-
// broker exiting after its kickoff turn idle-releases.
|
|
34
|
-
function model(id) {
|
|
35
|
-
return JSON.parse(readFileSync(join(h.home, 'nodes', id, 'fake-pi.model.json'), 'utf8'));
|
|
36
|
-
}
|
|
37
|
-
// Every fired lifecycle event lands in fake-pi.events.jsonl. A kickoff turn is a
|
|
38
|
-
// session.prompt → emitTurn, which fires one 'agent_start'; counting them proves
|
|
39
|
-
// whether the deferred kickoff ran. Also a disk read (survives broker exit).
|
|
40
|
-
function agentStartCount(id) {
|
|
41
|
-
try {
|
|
42
|
-
return readFileSync(join(h.home, 'nodes', id, 'fake-pi.events.jsonl'), 'utf8')
|
|
43
|
-
.split('\n')
|
|
44
|
-
.filter((l) => {
|
|
45
|
-
try {
|
|
46
|
-
return JSON.parse(l).event === 'agent_start';
|
|
47
|
-
}
|
|
48
|
-
catch {
|
|
49
|
-
return false;
|
|
50
|
-
}
|
|
51
|
-
}).length;
|
|
52
|
-
}
|
|
53
|
-
catch {
|
|
54
|
-
return 0;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
// ===========================================================================
|
|
58
|
-
// REAL-BOOT (tsx source broker, fake engine). Tier-3 model-less launch + the
|
|
59
|
-
// reload_auth re-drive that resolves a model once auth arrives. These lock the
|
|
60
|
-
// two broker.ts launch-model fixes:
|
|
61
|
-
// 0b (unknown-stub detection) — the real SDK gives a model-less session an
|
|
62
|
-
// unknown-stub model (never `undefined`); sessionHasNoModel() must treat it
|
|
63
|
-
// as no-model so the kickoff DEFERS instead of prompting a keyless engine.
|
|
64
|
-
// 0a (self-healing model-less registry) — the construction-time mask that
|
|
65
|
-
// suppresses the SDK's own findInitialModel MUST reveal() the instant
|
|
66
|
-
// construction returns, or list_models/cycle_model stay broken forever for
|
|
67
|
-
// a model-less-booted node even after a /login resolves a model.
|
|
68
|
-
// ===========================================================================
|
|
69
|
-
// login/reload re-drive. Two proofs, ordered to dodge the kickoff-shutdown race:
|
|
70
|
-
// (0a self-heal, list_models) — the construction-time mask reveal()s the SAME
|
|
71
|
-
// retained proxy the instant construction returns, so getAvailable() passes
|
|
72
|
-
// through LIVE. We prove it by flipping auth ON and querying list_models
|
|
73
|
-
// BEFORE any reload_auth: the broker is still model-less-idle (no turn has
|
|
74
|
-
// run, so it hasn't idle-released) and definitely alive. With the persistent
|
|
75
|
-
// mask (reveal() removed) getAvailable()→[] forever, so availableIds stays []
|
|
76
|
-
// even after the flip — the ONLY assertion here that discriminates the bug.
|
|
77
|
-
// (re-drive) — reload_auth then re-runs the SAME launch policy against the
|
|
78
|
-
// now-authenticated registry: a model resolves and the deferred kickoff
|
|
79
|
-
// fires. Those are disk reads (fake-pi.model.json / .events.jsonl), so they
|
|
80
|
-
// hold even after the kickoff turn ends and the broker idle-releases — no
|
|
81
|
-
// dependence on the socket surviving.
|
|
82
|
-
//
|
|
83
|
-
// MODEL CHOICE — the child is pinned to `fake/fake-model`, a NON-managed provider
|
|
84
|
-
// and this is deliberate. The
|
|
85
|
-
// zero-auth sentinel gates the fake registry's find/getAll/getAvailable AND its
|
|
86
|
-
// hasConfiguredAuth, so removing it is a genuine, LIVE auth-on flip for a
|
|
87
|
-
// non-managed model: resolveLaunchModel authenticates a non-managed candidate off
|
|
88
|
-
// hasConfiguredAuth(), which the sentinel controls. A MANAGED pin (anthropic)
|
|
89
|
-
// instead authenticates off subscription-pool OCCUPANCY (readSubscriptionPool),
|
|
90
|
-
// which the fake registry cannot express and which the test process cannot seed —
|
|
91
|
-
// the pool file is `homedir()/.pi/agent/...` frozen at import, and the test
|
|
92
|
-
// process keeps the REAL HOME while the broker runs under the harness's tmpHome,
|
|
93
|
-
// so a seed would land in the wrong file (and pollute real user state). The
|
|
94
|
-
// re-drive mechanism under test (reload_auth re-runs resolveLaunchModel → adopts
|
|
95
|
-
// the model → fires the deferred kickoff) is provider-agnostic; the managed
|
|
96
|
-
// subscription-pool auth path is out of this test's scope (covered by
|
|
97
|
-
// broker-launch-candidates / broker-sdk-wiring). fake/fake-model is a faithful
|
|
98
|
-
// analog: a node pinned to model X boots before X's auth exists, then X's auth
|
|
99
|
-
// arrives and the re-drive resolves X.
|
|
100
|
-
test('login re-drive → list_models self-heals (0a) and reload_auth resolves a model + fires the deferred kickoff', async () => {
|
|
101
|
-
writeFileSync(noAuthSentinel(), '1');
|
|
102
|
-
try {
|
|
103
|
-
const parent = h.spawnRoot('login re-drive parent');
|
|
104
|
-
const child = await h.spawnHeadlessChild(parent, 'login re-drive', { model: 'fake/fake-model' });
|
|
105
|
-
assert.equal(model(child), null, 'boots model-less under zero-auth');
|
|
106
|
-
assert.equal(agentStartCount(child), 0, 'kickoff deferred at boot');
|
|
107
|
-
const c = await attachUntil(child, 'controller', 'redrive-ctrl', (a) => a.welcome.role === 'controller', 'redrive controller admitted');
|
|
108
|
-
// A read-op reply is a correlated `data` frame the client swallows into
|
|
109
|
-
// request()'s by-id resolver (NEVER a generic 'frame'), so we MUST use
|
|
110
|
-
// client.request(), not send()+waitFrame.
|
|
111
|
-
// Baseline: under zero-auth the registry reports nothing available.
|
|
112
|
-
const lm0 = await c.client.request({ type: 'list_models' });
|
|
113
|
-
assert.ok(lm0.kind === 'list_models' && lm0.availableIds.length === 0, 'zero-auth: no models available');
|
|
114
|
-
// FLIP AUTH ON, then re-query while the broker is still alive (no turn has run
|
|
115
|
-
// yet). getAvailable() flows through the revealed construction proxy →
|
|
116
|
-
// NON-empty. With the mask never revealed it would still be [].
|
|
117
|
-
rmSync(noAuthSentinel(), { force: true });
|
|
118
|
-
const lm1 = await c.client.request({ type: 'list_models' });
|
|
119
|
-
assert.ok(lm1.kind === 'list_models' && lm1.availableIds.length > 0, 'auth on: list_models reports an available model (0a self-heal — the construction mask revealed)');
|
|
120
|
-
// reload_auth re-drives the launch policy → resolves a model and fires the
|
|
121
|
-
// deferred kickoff. Disk reads, so they survive the broker idle-releasing
|
|
122
|
-
// once that kickoff turn ends.
|
|
123
|
-
c.send({ type: 'reload_auth' });
|
|
124
|
-
await h.waitFor(() => model(child) !== null, { label: 're-drive selected a model' });
|
|
125
|
-
await h.waitFor(() => agentStartCount(child) >= 1, { label: 'deferred kickoff fired after re-drive' });
|
|
126
|
-
}
|
|
127
|
-
finally {
|
|
128
|
-
rmSync(noAuthSentinel(), { force: true });
|
|
129
|
-
}
|
|
130
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|