@north-light/crouter 0.3.173 → 0.3.175
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/memory/write.js +13 -12
- 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,489 +0,0 @@
|
|
|
1
|
-
// Run with: node --import tsx/esm --test src/daemon/api/__tests__/inbox.test.ts
|
|
2
|
-
//
|
|
3
|
-
// Integration coverage for crtrd's `/v1/human/inbox` routes
|
|
4
|
-
// (inbox-contract.md §A, `handlers/inbox.ts`). Exercises the full leaf → typed
|
|
5
|
-
// `CrtrClient` → in-process `createApiServer()` → handler → ticket store —
|
|
6
|
-
// never a mock client or pre-parsed handler call. Tickets live directly under
|
|
7
|
-
// the derived `ticketsRoot()` and use the same public store APIs as production.
|
|
8
|
-
// A raw hand-written `deck.json` is used only for states that submission cannot
|
|
9
|
-
// produce: an unresolved `bodyPath`, a malformed stored deck, or a raced final.
|
|
10
|
-
import { test, describe, before, after, beforeEach } from 'node:test';
|
|
11
|
-
import assert from 'node:assert/strict';
|
|
12
|
-
import { spawn } from 'node:child_process';
|
|
13
|
-
import { mkdtempSync, mkdirSync, rmSync, writeFileSync, readFileSync, existsSync, realpathSync, } from 'node:fs';
|
|
14
|
-
import { tmpdir } from 'node:os';
|
|
15
|
-
import { join } from 'node:path';
|
|
16
|
-
import { createHash } from 'node:crypto';
|
|
17
|
-
import { claimTicket, releaseClaim } from '../../../core/human/claim.js';
|
|
18
|
-
import { deckPath, responsePath } from '../../../core/human/convention.js';
|
|
19
|
-
import { notifyDeck } from '../../../core/human/deck-factories.js';
|
|
20
|
-
import { ticketsRoot } from '../../../core/human/root.js';
|
|
21
|
-
import { submitDeck, submitReview } from '../../../core/human/tickets.js';
|
|
22
|
-
import { createApiServer } from '../server.js';
|
|
23
|
-
import { apiSocketPath } from '../../../core/canvas/paths.js';
|
|
24
|
-
import { CrtrClient, ApiError } from '../../../api/index.js';
|
|
25
|
-
const TICKET_ID_PATTERN = /^[a-f0-9]{64}$/;
|
|
26
|
-
// ---------------------------------------------------------------------------
|
|
27
|
-
// Harness — one server for the whole file; a fresh derived tickets root per
|
|
28
|
-
// test.
|
|
29
|
-
// ---------------------------------------------------------------------------
|
|
30
|
-
let crtrHome;
|
|
31
|
-
let priorCrtrHome;
|
|
32
|
-
let server;
|
|
33
|
-
let client;
|
|
34
|
-
async function waitForSocket(path) {
|
|
35
|
-
for (let i = 0; i < 200; i++) {
|
|
36
|
-
if (existsSync(path))
|
|
37
|
-
return;
|
|
38
|
-
await new Promise((r) => setTimeout(r, 25));
|
|
39
|
-
}
|
|
40
|
-
throw new Error(`api socket never bound at ${path}`);
|
|
41
|
-
}
|
|
42
|
-
before(async () => {
|
|
43
|
-
priorCrtrHome = process.env['CRTR_HOME'];
|
|
44
|
-
crtrHome = mkdtempSync(join(tmpdir(), 'crtr-inbox-home-'));
|
|
45
|
-
process.env['CRTR_HOME'] = crtrHome;
|
|
46
|
-
server = createApiServer();
|
|
47
|
-
await waitForSocket(apiSocketPath());
|
|
48
|
-
client = new CrtrClient({ socketPath: apiSocketPath(), autostart: false });
|
|
49
|
-
});
|
|
50
|
-
after(async () => {
|
|
51
|
-
await server?.close();
|
|
52
|
-
rmSync(crtrHome, { recursive: true, force: true });
|
|
53
|
-
if (priorCrtrHome !== undefined)
|
|
54
|
-
process.env['CRTR_HOME'] = priorCrtrHome;
|
|
55
|
-
else
|
|
56
|
-
delete process.env['CRTR_HOME'];
|
|
57
|
-
});
|
|
58
|
-
beforeEach(() => {
|
|
59
|
-
rmSync(ticketsRoot(), { recursive: true, force: true });
|
|
60
|
-
mkdirSync(ticketsRoot(), { recursive: true, mode: 0o700 });
|
|
61
|
-
});
|
|
62
|
-
// ---------------------------------------------------------------------------
|
|
63
|
-
// Fixture helpers
|
|
64
|
-
// ---------------------------------------------------------------------------
|
|
65
|
-
function freshRoot(..._unused) {
|
|
66
|
-
mkdirSync(ticketsRoot(), { recursive: true, mode: 0o700 });
|
|
67
|
-
return realpathSync(ticketsRoot());
|
|
68
|
-
}
|
|
69
|
-
function deckJson(blockedSince, extra = {}) {
|
|
70
|
-
return {
|
|
71
|
-
title: 'Ship it?',
|
|
72
|
-
source: { blockedSince },
|
|
73
|
-
interactions: [{ id: 'q', title: 'Ship it?', subtitle: 'Approve shipping now so the release can proceed.', options: [{ id: 'yes', label: 'Yes' }, { id: 'no', label: 'No' }] }],
|
|
74
|
-
...extra,
|
|
75
|
-
};
|
|
76
|
-
}
|
|
77
|
-
/** Create a real pending deck ticket through the public submission API — the
|
|
78
|
-
* normal fixture path for any test that just needs a valid, answerable
|
|
79
|
-
* ticket on disk. */
|
|
80
|
-
function submitTestDeck(root, id, blockedSince, extra = {}) {
|
|
81
|
-
return submitDeck({ dir: join(root, id), deck: deckJson(blockedSince, extra) }).dir;
|
|
82
|
-
}
|
|
83
|
-
/** Create a real pending review ticket through the public submission API. */
|
|
84
|
-
function submitTestReview(root, id, blockedSince) {
|
|
85
|
-
const srcDir = mkdtempSync(join(tmpdir(), 'crtr-inbox-review-src-'));
|
|
86
|
-
const file = join(srcDir, 'plan.md');
|
|
87
|
-
writeFileSync(file, '# Plan\n\nDo the thing.\n');
|
|
88
|
-
return submitReview({ dir: join(root, id), review: { title: 'Review the plan', subtitle: 'Review the plan now so implementation can begin with confidence.', source: {}, file, blockedSince } }).dir;
|
|
89
|
-
}
|
|
90
|
-
/** RAW fixture writer — bypasses `submitDeck`'s own submit-time validation
|
|
91
|
-
* and body-path resolution entirely. Used ONLY to construct on-disk states
|
|
92
|
-
* a real submitter cannot produce: an unresolved `bodyPath`, a tampered
|
|
93
|
-
* stored deck, or an adversarial root-replacement target. */
|
|
94
|
-
function writeRawDeckTicket(root, id, deck) {
|
|
95
|
-
const dir = join(root, id);
|
|
96
|
-
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
97
|
-
writeFileSync(deckPath(dir), JSON.stringify(deck));
|
|
98
|
-
return dir;
|
|
99
|
-
}
|
|
100
|
-
function ticketIdFor(root, basename) {
|
|
101
|
-
return createHash('sha256').update(`${root}\0${basename}`, 'utf8').digest('hex');
|
|
102
|
-
}
|
|
103
|
-
async function expectApiError(promise, status, code) {
|
|
104
|
-
try {
|
|
105
|
-
await promise;
|
|
106
|
-
}
|
|
107
|
-
catch (err) {
|
|
108
|
-
assert.ok(err instanceof ApiError, `expected ApiError, got ${String(err)}`);
|
|
109
|
-
assert.equal(err.status, status, `status: ${err.message}`);
|
|
110
|
-
assert.equal(err.code, code, `code: ${err.message}`);
|
|
111
|
-
return err;
|
|
112
|
-
}
|
|
113
|
-
throw new Error('expected the promise to reject');
|
|
114
|
-
}
|
|
115
|
-
// ---------------------------------------------------------------------------
|
|
116
|
-
// Wire-shape assertions — a closed allowlist per DTO plus a recursive
|
|
117
|
-
// forbidden-content walk (host paths, claim/dir/file/output/bodyPath keys).
|
|
118
|
-
// ---------------------------------------------------------------------------
|
|
119
|
-
function assertKeys(obj, allowed, label) {
|
|
120
|
-
for (const key of Object.keys(obj)) {
|
|
121
|
-
assert.ok(allowed.includes(key), `unexpected field "${key}" in ${label}: ${JSON.stringify(obj)}`);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
function assertSourceShape(source) {
|
|
125
|
-
assert.equal(typeof source, 'object');
|
|
126
|
-
assertKeys(source, ['sessionName', 'askedBy', 'blockedSince', 'nodeId'], 'DeckSourceDTO');
|
|
127
|
-
}
|
|
128
|
-
function assertTicketSummaryShape(ticket) {
|
|
129
|
-
assert.match(ticket.ticket_id, TICKET_ID_PATTERN);
|
|
130
|
-
assert.ok(ticket.kind === 'deck' || ticket.kind === 'review');
|
|
131
|
-
const allowed = ticket.kind === 'deck'
|
|
132
|
-
? ['ticket_id', 'kind', 'title', 'subtitle', 'blocked_since', 'source', 'interaction_kind']
|
|
133
|
-
: ['ticket_id', 'kind', 'title', 'subtitle', 'blocked_since', 'source'];
|
|
134
|
-
assertKeys(ticket, allowed, `InboxTicketSummaryDTO(${ticket.kind})`);
|
|
135
|
-
assertSourceShape(ticket.source);
|
|
136
|
-
}
|
|
137
|
-
function assertInboxListShape(body) {
|
|
138
|
-
assertKeys(body, ['tickets'], 'InboxListDTO');
|
|
139
|
-
for (const ticket of body.tickets)
|
|
140
|
-
assertTicketSummaryShape(ticket);
|
|
141
|
-
}
|
|
142
|
-
function assertInteractionShape(interaction) {
|
|
143
|
-
assertKeys(interaction, ['id', 'title', 'subtitle', 'body', 'options', 'multiSelect', 'allowFreetext', 'freetextLabel', 'kind', 'preAnswered'], 'InteractionDTO');
|
|
144
|
-
for (const option of interaction.options) {
|
|
145
|
-
assertKeys(option, ['id', 'label', 'description'], 'InteractionOptionDTO');
|
|
146
|
-
}
|
|
147
|
-
if (interaction.preAnswered !== undefined) {
|
|
148
|
-
assertKeys(interaction.preAnswered, ['selectedOptionId', 'selectedOptionIds', 'freetext', 'label'], 'InteractionPreAnswerDTO');
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
function assertDeckShape(deck) {
|
|
152
|
-
assertKeys(deck, ['title', 'source', 'interactions'], 'DeckDTO');
|
|
153
|
-
if (deck.source !== undefined)
|
|
154
|
-
assertSourceShape(deck.source);
|
|
155
|
-
for (const interaction of deck.interactions)
|
|
156
|
-
assertInteractionShape(interaction);
|
|
157
|
-
}
|
|
158
|
-
function assertInboxDeckShape(body) {
|
|
159
|
-
assertKeys(body, ['ticket_id', 'kind', 'deck'], 'InboxDeckDTO');
|
|
160
|
-
assert.equal(body.kind, 'deck');
|
|
161
|
-
assert.match(body.ticket_id, TICKET_ID_PATTERN);
|
|
162
|
-
assertDeckShape(body.deck);
|
|
163
|
-
}
|
|
164
|
-
function assertDeckResultShape(result) {
|
|
165
|
-
assertKeys(result, ['schema', 'kind', 'responses', 'summary', 'completedAt'], 'DeckTicketResultDTO');
|
|
166
|
-
assert.equal(result.schema, 'humanloop.response/v2');
|
|
167
|
-
assert.equal(result.kind, 'deck');
|
|
168
|
-
for (const response of result.responses) {
|
|
169
|
-
assertKeys(response, ['id', 'selectedOptionId', 'selectedOptionIds', 'freetext', 'optionComments'], 'InteractionResponseDTO');
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
function assertCanceledResultShape(result) {
|
|
173
|
-
assertKeys(result, ['schema', 'kind', 'canceledAt', 'reason', 'actor'], 'CanceledTicketResultDTO');
|
|
174
|
-
assert.equal(result.schema, 'humanloop.cancel/v1');
|
|
175
|
-
assert.equal(result.kind, 'canceled');
|
|
176
|
-
}
|
|
177
|
-
const FORBIDDEN_KEYS = new Set(['dir', 'file', 'output', 'claim', 'bodyPath']);
|
|
178
|
-
/** Recursively walk a parsed JSON value, failing on any forbidden key name or
|
|
179
|
-
* any string value containing one of the given forbidden substrings (host
|
|
180
|
-
* paths, in practice). Used against full success AND error bodies. */
|
|
181
|
-
function assertNoForbiddenContent(value, forbidden, path = '$') {
|
|
182
|
-
if (Array.isArray(value)) {
|
|
183
|
-
value.forEach((item, i) => assertNoForbiddenContent(item, forbidden, `${path}[${i}]`));
|
|
184
|
-
return;
|
|
185
|
-
}
|
|
186
|
-
if (value !== null && typeof value === 'object') {
|
|
187
|
-
for (const [key, val] of Object.entries(value)) {
|
|
188
|
-
assert.ok(!FORBIDDEN_KEYS.has(key), `forbidden key "${key}" present at ${path}.${key}`);
|
|
189
|
-
assertNoForbiddenContent(val, forbidden, `${path}.${key}`);
|
|
190
|
-
}
|
|
191
|
-
return;
|
|
192
|
-
}
|
|
193
|
-
if (typeof value === 'string') {
|
|
194
|
-
for (const needle of forbidden) {
|
|
195
|
-
assert.ok(!value.includes(needle), `forbidden content "${needle}" leaked at ${path}: ${JSON.stringify(value)}`);
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
// ---------------------------------------------------------------------------
|
|
200
|
-
// GET /v1/human/inbox — enumerate
|
|
201
|
-
// ---------------------------------------------------------------------------
|
|
202
|
-
describe('GET /v1/human/inbox — enumerate', () => {
|
|
203
|
-
test('mixed deck + review tickets preserve canonical-root hash ids while sorting newest first', async () => {
|
|
204
|
-
const root = freshRoot('crouter');
|
|
205
|
-
// This is the pre-cutover opaque-id formula: canonical root + NUL + ticket
|
|
206
|
-
// basename. The single derived root retains that canonical root, so an id
|
|
207
|
-
// a client computed before root registration disappeared still resolves.
|
|
208
|
-
const olderDeckId = ticketIdFor(root, 'older-deck');
|
|
209
|
-
submitTestDeck(root, 'older-deck', '2026-01-01T00:00:00.000Z');
|
|
210
|
-
submitTestReview(root, 'newer-review', '2026-01-02T00:00:00.000Z');
|
|
211
|
-
const list = await client.listHumanInbox();
|
|
212
|
-
assertInboxListShape(list);
|
|
213
|
-
assertNoForbiddenContent(list, [root]);
|
|
214
|
-
assert.equal(list.tickets.length, 2);
|
|
215
|
-
assert.equal(list.tickets[0].kind, 'review', 'newer blocked_since sorts first');
|
|
216
|
-
assert.equal(list.tickets[1].kind, 'deck');
|
|
217
|
-
assert.equal(list.tickets[0].ticket_id, ticketIdFor(root, 'newer-review'));
|
|
218
|
-
assert.equal(list.tickets[1].ticket_id, olderDeckId);
|
|
219
|
-
assert.equal((await client.getHumanInboxDeck(olderDeckId)).deck.title, 'Ship it?');
|
|
220
|
-
});
|
|
221
|
-
test('sorts by parsed instant across differing UTC offsets, not lexical string order', async () => {
|
|
222
|
-
const root = freshRoot('crouter');
|
|
223
|
-
// '+14:00' is lexically GREATER than 'Z' at the date digit that differs,
|
|
224
|
-
// but the instant it names is two hours EARLIER than the 'Z' ticket
|
|
225
|
-
// below (2026-01-01T10:00:00Z vs. 2026-01-01T12:00:00Z). A lexical
|
|
226
|
-
// descending sort would (wrongly) place this ticket first.
|
|
227
|
-
submitTestDeck(root, 'lexically-later-but-earlier-instant', '2026-01-02T00:00:00+14:00');
|
|
228
|
-
submitTestDeck(root, 'lexically-earlier-but-later-instant', '2026-01-01T12:00:00Z');
|
|
229
|
-
const list = await client.listHumanInbox();
|
|
230
|
-
assert.equal(list.tickets.length, 2);
|
|
231
|
-
assert.equal(list.tickets[0].blocked_since, '2026-01-01T12:00:00Z', 'the chronologically newer instant sorts first regardless of lexical string order');
|
|
232
|
-
assert.equal(list.tickets[0].ticket_id, ticketIdFor(root, 'lexically-earlier-but-later-instant'));
|
|
233
|
-
assert.equal(list.tickets[1].ticket_id, ticketIdFor(root, 'lexically-later-but-earlier-instant'));
|
|
234
|
-
});
|
|
235
|
-
});
|
|
236
|
-
// ---------------------------------------------------------------------------
|
|
237
|
-
// GET /v1/human/inbox/:ticket_id — read a pending deck
|
|
238
|
-
// ---------------------------------------------------------------------------
|
|
239
|
-
describe('GET /v1/human/inbox/:ticket_id', () => {
|
|
240
|
-
test('inlines bodyPath at read time; no bodyPath key on the wire', async () => {
|
|
241
|
-
// RAW fixture: `submitDeck` resolves `bodyPath` to inline `body` at
|
|
242
|
-
// submit time, so a ticket with a still-unresolved `bodyPath` on disk
|
|
243
|
-
// (the state crtrd's own `parseDeck` read-time resolution exists to
|
|
244
|
-
// handle) cannot be produced through the public submission API.
|
|
245
|
-
const root = freshRoot('crouter');
|
|
246
|
-
const dir = join(root, 'body-deck');
|
|
247
|
-
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
248
|
-
writeFileSync(join(dir, 'body.md'), 'Full markdown body.\n');
|
|
249
|
-
writeFileSync(deckPath(dir), JSON.stringify({
|
|
250
|
-
title: 'Ship it?',
|
|
251
|
-
source: { blockedSince: '2026-01-01T00:00:00.000Z' },
|
|
252
|
-
interactions: [{ id: 'q', title: 'Ship it?', subtitle: 'Approve shipping now so the release can proceed.', bodyPath: 'body.md', options: [{ id: 'yes', label: 'Yes' }] }],
|
|
253
|
-
}));
|
|
254
|
-
const id = ticketIdFor(root, 'body-deck');
|
|
255
|
-
const deckDto = await client.getHumanInboxDeck(id);
|
|
256
|
-
assertInboxDeckShape(deckDto);
|
|
257
|
-
assertNoForbiddenContent(deckDto, [root, dir]);
|
|
258
|
-
assert.equal(deckDto.deck.interactions[0].body, 'Full markdown body.\n');
|
|
259
|
-
});
|
|
260
|
-
test('404 ticket_not_found for a syntactically valid but unknown ticket id', async () => {
|
|
261
|
-
await expectApiError(client.getHumanInboxDeck('a'.repeat(64)), 404, 'ticket_not_found');
|
|
262
|
-
});
|
|
263
|
-
test('409 ticket_kind_unsupported for a review ticket', async () => {
|
|
264
|
-
const root = freshRoot('crouter');
|
|
265
|
-
submitTestReview(root, 'rev', '2026-01-01T00:00:00.000Z');
|
|
266
|
-
await expectApiError(client.getHumanInboxDeck(ticketIdFor(root, 'rev')), 409, 'ticket_kind_unsupported');
|
|
267
|
-
});
|
|
268
|
-
test('malformed stored deck sanitizes to 500 internal: no bodyPath value or host path in error.message', async () => {
|
|
269
|
-
// RAW fixture: simulates a ticket mutated on disk after enumeration (or a
|
|
270
|
-
// corrupted store) — a state `submitDeck` cannot produce, since it
|
|
271
|
-
// validates and resolves bodyPath before ever writing deck.json. This
|
|
272
|
-
// reproduces the review's exact repro shape: a bodyPath that escapes the
|
|
273
|
-
// ticket directory to an existing absolute host file.
|
|
274
|
-
const root = freshRoot('crouter');
|
|
275
|
-
const dir = writeRawDeckTicket(root, 'malformed', deckJson('2026-01-01T00:00:00.000Z', {
|
|
276
|
-
interactions: [{ id: 'q', title: 'Ship it?', subtitle: 'Approve shipping now so the release can proceed.', bodyPath: process.execPath, options: [{ id: 'yes', label: 'Yes' }] }],
|
|
277
|
-
}));
|
|
278
|
-
const id = ticketIdFor(root, 'malformed');
|
|
279
|
-
const err = await expectApiError(client.getHumanInboxDeck(id), 500, 'internal');
|
|
280
|
-
assert.ok(!err.message.includes(process.execPath), `error.message leaked a host path: ${err.message}`);
|
|
281
|
-
assert.ok(!err.message.includes(dir), `error.message leaked the ticket directory: ${err.message}`);
|
|
282
|
-
assert.ok(!err.message.toLowerCase().includes('bodypath'), `error.message named bodyPath: ${err.message}`);
|
|
283
|
-
});
|
|
284
|
-
});
|
|
285
|
-
// ---------------------------------------------------------------------------
|
|
286
|
-
// POST /v1/human/inbox/:ticket_id/respond
|
|
287
|
-
// ---------------------------------------------------------------------------
|
|
288
|
-
describe('POST /v1/human/inbox/:ticket_id/respond', () => {
|
|
289
|
-
test('persists the canonical humanloop.response/v2 result unchanged and matches stored response.json exactly', async () => {
|
|
290
|
-
const root = freshRoot('crouter', true);
|
|
291
|
-
const dir = submitTestDeck(root, 'ask', '2026-01-01T00:00:00.000Z');
|
|
292
|
-
const id = ticketIdFor(root, 'ask');
|
|
293
|
-
const result = await client.respondHumanInboxDeck(id, { responses: [{ id: 'q', selectedOptionId: 'yes' }] });
|
|
294
|
-
assertDeckResultShape(result);
|
|
295
|
-
assertNoForbiddenContent(result, [root, dir]);
|
|
296
|
-
assert.deepEqual(result.responses, [{ id: 'q', selectedOptionId: 'yes' }]);
|
|
297
|
-
const stored = JSON.parse(readFileSync(responsePath(dir), 'utf8'));
|
|
298
|
-
assert.deepEqual(stored, result, 'the wire result is the stored humanloop response exactly, unreconstructed');
|
|
299
|
-
assert.ok(existsSync(responsePath(dir)), 'the canonical response remains the only ticket receipt');
|
|
300
|
-
});
|
|
301
|
-
test('ordinary notify acknowledgement — no special endpoint/shape', async () => {
|
|
302
|
-
const root = freshRoot('crouter');
|
|
303
|
-
const id_ = 'notify';
|
|
304
|
-
submitDeck({ dir: join(root, id_), deck: notifyDeck('Build done', { subtitle: 'The build completed successfully, so the change is ready to review.' }) });
|
|
305
|
-
const id = ticketIdFor(root, 'notify');
|
|
306
|
-
const result = await client.respondHumanInboxDeck(id, { responses: [{ id: 'notify', selectedOptionId: 'ok' }] });
|
|
307
|
-
assert.equal(result.kind, 'deck');
|
|
308
|
-
assert.deepEqual(result.responses, [{ id: 'notify', selectedOptionId: 'ok' }]);
|
|
309
|
-
});
|
|
310
|
-
test('409 ticket_kind_unsupported for a review ticket', async () => {
|
|
311
|
-
const root = freshRoot('crouter');
|
|
312
|
-
submitTestReview(root, 'rev', '2026-01-01T00:00:00.000Z');
|
|
313
|
-
await expectApiError(client.respondHumanInboxDeck(ticketIdFor(root, 'rev'), { responses: [] }), 409, 'ticket_kind_unsupported');
|
|
314
|
-
});
|
|
315
|
-
test('409 ticket_already_resolved on a second respond after the first succeeds', async () => {
|
|
316
|
-
const root = freshRoot('crouter');
|
|
317
|
-
submitTestDeck(root, 'ask', '2026-01-01T00:00:00.000Z');
|
|
318
|
-
const id = ticketIdFor(root, 'ask');
|
|
319
|
-
await client.respondHumanInboxDeck(id, { responses: [{ id: 'q', selectedOptionId: 'yes' }] });
|
|
320
|
-
await expectApiError(client.respondHumanInboxDeck(id, { responses: [{ id: 'q', selectedOptionId: 'no' }] }), 409, 'ticket_already_resolved');
|
|
321
|
-
});
|
|
322
|
-
test('a live foreign claim is taken over by the daemon finish path', async () => {
|
|
323
|
-
const root = freshRoot('crouter');
|
|
324
|
-
const dir = submitTestDeck(root, 'ask', '2026-01-01T00:00:00.000Z');
|
|
325
|
-
const id = ticketIdFor(root, 'ask');
|
|
326
|
-
const foreignClaim = claimTicket(dir, { host: 'someone-else' });
|
|
327
|
-
assert.ok(foreignClaim !== null, 'foreign claim acquired');
|
|
328
|
-
const result = await client.respondHumanInboxDeck(id, { responses: [{ id: 'q', selectedOptionId: 'yes' }] });
|
|
329
|
-
assertDeckResultShape(result);
|
|
330
|
-
assert.equal(releaseClaim(dir, foreignClaim.token), false, 'the takeover released the replaced claim');
|
|
331
|
-
});
|
|
332
|
-
test('external cancel/resolve race: a resolution that lands between the precheck and claimTicket() reports ticket_already_resolved, never ticket_unavailable', async () => {
|
|
333
|
-
const root = freshRoot('crouter');
|
|
334
|
-
const dir = submitTestDeck(root, 'race', '2026-01-01T00:00:00.000Z');
|
|
335
|
-
const id = ticketIdFor(root, 'race');
|
|
336
|
-
// A real separate OS process holds the SAME ticket lock humanloop's
|
|
337
|
-
// `claimTicket` contends for (`<dir>/.ticket-lock`, matching the marker
|
|
338
|
-
// scheme in humanloop's `convention.ts`). It signals once it holds the
|
|
339
|
-
// lock, then after a short real delay writes `response.json` directly
|
|
340
|
-
// (simulating an external actor's cancel/respond winning the race) and
|
|
341
|
-
// releases. Because the holder grabs the lock BEFORE this test sends the
|
|
342
|
-
// respond request, the precheck inside the handler is guaranteed to see
|
|
343
|
-
// the ticket still pending, and `claimTicket()`'s own lock acquisition is
|
|
344
|
-
// guaranteed to block until the holder resolves the ticket and releases
|
|
345
|
-
// — deterministically reproducing the exact interleaving the fix must
|
|
346
|
-
// handle, without relying on a microsecond-scale timing coincidence.
|
|
347
|
-
const script = `
|
|
348
|
-
const { mkdirSync, writeFileSync, rmSync } = require('node:fs');
|
|
349
|
-
const dir = process.env.RACE_TICKET_DIR;
|
|
350
|
-
const lockPath = dir + '/.ticket-lock';
|
|
351
|
-
mkdirSync(lockPath, { mode: 0o700 });
|
|
352
|
-
writeFileSync(lockPath + '/owner.race-holder', '', { flag: 'wx', mode: 0o600 });
|
|
353
|
-
process.stdout.write('holding\\n');
|
|
354
|
-
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 300);
|
|
355
|
-
writeFileSync(dir + '/response.json', JSON.stringify({
|
|
356
|
-
schema: 'humanloop.cancel/v1', kind: 'canceled',
|
|
357
|
-
canceledAt: new Date().toISOString(), reason: 'external race', actor: 'external',
|
|
358
|
-
}) + '\\n', { mode: 0o600 });
|
|
359
|
-
rmSync(lockPath, { recursive: true, force: true });
|
|
360
|
-
process.stdout.write('resolved\\n');
|
|
361
|
-
`;
|
|
362
|
-
const holder = spawn(process.execPath, ['-e', script], {
|
|
363
|
-
env: { ...process.env, RACE_TICKET_DIR: dir },
|
|
364
|
-
stdio: ['ignore', 'pipe', 'pipe'],
|
|
365
|
-
});
|
|
366
|
-
let stdout = '';
|
|
367
|
-
let stderr = '';
|
|
368
|
-
holder.stdout.setEncoding('utf8');
|
|
369
|
-
holder.stderr.setEncoding('utf8');
|
|
370
|
-
holder.stdout.on('data', (chunk) => {
|
|
371
|
-
stdout += chunk;
|
|
372
|
-
});
|
|
373
|
-
holder.stderr.on('data', (chunk) => {
|
|
374
|
-
stderr += chunk;
|
|
375
|
-
});
|
|
376
|
-
const exited = new Promise((resolve) => holder.once('close', resolve));
|
|
377
|
-
try {
|
|
378
|
-
await new Promise((resolve, reject) => {
|
|
379
|
-
const timer = setTimeout(() => reject(new Error(`race holder never signaled "holding": stdout=${stdout} stderr=${stderr}`)), 5000);
|
|
380
|
-
const check = () => {
|
|
381
|
-
if (stdout.includes('holding')) {
|
|
382
|
-
clearTimeout(timer);
|
|
383
|
-
resolve();
|
|
384
|
-
}
|
|
385
|
-
};
|
|
386
|
-
holder.stdout.on('data', check);
|
|
387
|
-
holder.once('error', (err) => {
|
|
388
|
-
clearTimeout(timer);
|
|
389
|
-
reject(err);
|
|
390
|
-
});
|
|
391
|
-
check();
|
|
392
|
-
});
|
|
393
|
-
await expectApiError(client.respondHumanInboxDeck(id, { responses: [{ id: 'q', selectedOptionId: 'yes' }] }), 409, 'ticket_already_resolved');
|
|
394
|
-
}
|
|
395
|
-
finally {
|
|
396
|
-
await exited;
|
|
397
|
-
}
|
|
398
|
-
assert.ok(stdout.includes('resolved'), `race holder did not complete its resolve+release: stdout=${stdout} stderr=${stderr}`);
|
|
399
|
-
});
|
|
400
|
-
test('500 internal for a finalize failure that is not a response-shape rejection — sanitized, not misclassified as 400', async () => {
|
|
401
|
-
const root = freshRoot('crouter');
|
|
402
|
-
const dir = submitTestDeck(root, 'ask', '2026-01-01T00:00:00.000Z');
|
|
403
|
-
const id = ticketIdFor(root, 'ask');
|
|
404
|
-
// RAW tamper: rewrite the persisted deck so its own re-read inside
|
|
405
|
-
// `finalizeDeck` fails deck-schema validation (interactions.min(1)) —
|
|
406
|
-
// this is a storage-layer failure, not a response-shape rejection, and
|
|
407
|
-
// `submitDeck` could never have written it in the first place.
|
|
408
|
-
writeFileSync(deckPath(dir), JSON.stringify({ title: 'Ship it?', interactions: [] }));
|
|
409
|
-
const err = await expectApiError(client.respondHumanInboxDeck(id, { responses: [{ id: 'q', selectedOptionId: 'yes' }] }), 500, 'internal');
|
|
410
|
-
assert.equal(err.message, 'the ticket could not be finalized');
|
|
411
|
-
assert.ok(!err.message.includes(dir), `error.message leaked the ticket directory: ${err.message}`);
|
|
412
|
-
});
|
|
413
|
-
test('400 invalid_ticket_response releases the claim so a following valid respond succeeds', async () => {
|
|
414
|
-
const root = freshRoot('crouter');
|
|
415
|
-
submitTestDeck(root, 'ask', '2026-01-01T00:00:00.000Z');
|
|
416
|
-
const id = ticketIdFor(root, 'ask');
|
|
417
|
-
const err = await expectApiError(client.respondHumanInboxDeck(id, { responses: [{ id: 'nonexistent', freetext: 'x' }] }), 400, 'invalid_ticket_response');
|
|
418
|
-
assert.match(err.message, /response does not match a unique deck interaction: nonexistent/);
|
|
419
|
-
const result = await client.respondHumanInboxDeck(id, { responses: [{ id: 'q', selectedOptionId: 'yes' }] });
|
|
420
|
-
assert.equal(result.kind, 'deck', 'the claim was released, so a valid respond now succeeds');
|
|
421
|
-
});
|
|
422
|
-
test('400 invalid_request for a malformed body', async () => {
|
|
423
|
-
const root = freshRoot('crouter');
|
|
424
|
-
submitTestDeck(root, 'ask', '2026-01-01T00:00:00.000Z');
|
|
425
|
-
const id = ticketIdFor(root, 'ask');
|
|
426
|
-
const path = `/v1/human/inbox/${id}/respond`;
|
|
427
|
-
await expectApiError(client.request('POST', path, { responses: [], extra: true }), 400, 'invalid_request');
|
|
428
|
-
await expectApiError(client.request('POST', path, { responses: 'nope' }), 400, 'invalid_request');
|
|
429
|
-
});
|
|
430
|
-
});
|
|
431
|
-
// ---------------------------------------------------------------------------
|
|
432
|
-
// POST /v1/human/inbox/:ticket_id/cancel
|
|
433
|
-
// ---------------------------------------------------------------------------
|
|
434
|
-
describe('POST /v1/human/inbox/:ticket_id/cancel', () => {
|
|
435
|
-
test('default reason and hardcoded human actor match stored response.json', async () => {
|
|
436
|
-
const root = freshRoot('crouter', true);
|
|
437
|
-
const dir = submitTestDeck(root, 'ask', '2026-01-01T00:00:00.000Z');
|
|
438
|
-
const id = ticketIdFor(root, 'ask');
|
|
439
|
-
const result = await client.cancelHumanInboxTicket(id);
|
|
440
|
-
assertCanceledResultShape(result);
|
|
441
|
-
assertNoForbiddenContent(result, [root, dir]);
|
|
442
|
-
assert.equal(result.reason, 'Canceled from the inbox.');
|
|
443
|
-
assert.equal(result.actor, 'human');
|
|
444
|
-
const stored = JSON.parse(readFileSync(responsePath(dir), 'utf8'));
|
|
445
|
-
assert.deepEqual(stored, result, 'the wire result is the stored humanloop cancellation exactly, unreconstructed');
|
|
446
|
-
assert.ok(existsSync(responsePath(dir)), 'the canonical cancellation remains the only ticket receipt');
|
|
447
|
-
});
|
|
448
|
-
test('custom reason is honored; actor is always human regardless of any client-supplied field', async () => {
|
|
449
|
-
const root = freshRoot('crouter');
|
|
450
|
-
submitTestDeck(root, 'ask', '2026-01-01T00:00:00.000Z');
|
|
451
|
-
const id = ticketIdFor(root, 'ask');
|
|
452
|
-
const result = await client.cancelHumanInboxTicket(id, { reason: 'changed my mind' });
|
|
453
|
-
assert.equal(result.reason, 'changed my mind');
|
|
454
|
-
assert.equal(result.actor, 'human');
|
|
455
|
-
});
|
|
456
|
-
test('recordless review cancellation returns the stored humanloop.cancel/v1 result', async () => {
|
|
457
|
-
const root = freshRoot('crouter');
|
|
458
|
-
const dir = submitTestReview(root, 'rev', '2026-01-01T00:00:00.000Z');
|
|
459
|
-
const result = await client.cancelHumanInboxTicket(ticketIdFor(root, 'rev'));
|
|
460
|
-
assertCanceledResultShape(result);
|
|
461
|
-
assert.deepEqual(JSON.parse(readFileSync(responsePath(dir), 'utf8')), result);
|
|
462
|
-
});
|
|
463
|
-
test('409 ticket_already_resolved after the ticket was already resolved via respond', async () => {
|
|
464
|
-
const root = freshRoot('crouter');
|
|
465
|
-
submitTestDeck(root, 'ask', '2026-01-01T00:00:00.000Z');
|
|
466
|
-
const id = ticketIdFor(root, 'ask');
|
|
467
|
-
await client.respondHumanInboxDeck(id, { responses: [{ id: 'q', selectedOptionId: 'yes' }] });
|
|
468
|
-
await expectApiError(client.cancelHumanInboxTicket(id), 409, 'ticket_already_resolved');
|
|
469
|
-
});
|
|
470
|
-
test('400 invalid_request for an empty (post-trim) reason and for a >1000-char reason', async () => {
|
|
471
|
-
const root = freshRoot('crouter');
|
|
472
|
-
submitTestDeck(root, 'ask', '2026-01-01T00:00:00.000Z');
|
|
473
|
-
const id = ticketIdFor(root, 'ask');
|
|
474
|
-
await expectApiError(client.cancelHumanInboxTicket(id, { reason: ' ' }), 400, 'invalid_request');
|
|
475
|
-
await expectApiError(client.cancelHumanInboxTicket(id, { reason: 'x'.repeat(1001) }), 400, 'invalid_request');
|
|
476
|
-
});
|
|
477
|
-
});
|
|
478
|
-
// ---------------------------------------------------------------------------
|
|
479
|
-
// Malformed ticket id syntax
|
|
480
|
-
// ---------------------------------------------------------------------------
|
|
481
|
-
describe('malformed ticket id syntax', () => {
|
|
482
|
-
test('400 invalid_request on GET/respond/cancel for a non-hex or wrong-length id', async () => {
|
|
483
|
-
for (const bad of ['not-hex-not-64-chars', 'a'.repeat(63), 'g'.repeat(64)]) {
|
|
484
|
-
await expectApiError(client.request('GET', `/v1/human/inbox/${bad}`), 400, 'invalid_request');
|
|
485
|
-
await expectApiError(client.request('POST', `/v1/human/inbox/${bad}/respond`, { responses: [] }), 400, 'invalid_request');
|
|
486
|
-
await expectApiError(client.request('POST', `/v1/human/inbox/${bad}/cancel`, {}), 400, 'invalid_request');
|
|
487
|
-
}
|
|
488
|
-
});
|
|
489
|
-
});
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|