@north-light/crouter 0.3.170 → 0.3.172
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/client.d.ts +37 -11
- package/dist/api/client.js +84 -15
- package/dist/api/dto/human.d.ts +53 -39
- package/dist/api/dto/human.js +2 -3
- package/dist/api/dto/inbox.d.ts +0 -1
- package/dist/api/dto/nodes.d.ts +12 -0
- package/dist/api/dto/review-comments.d.ts +137 -0
- package/dist/api/dto/review-comments.js +5 -0
- package/dist/api/dto/reviews.d.ts +109 -0
- package/dist/api/dto/reviews.js +5 -0
- package/dist/api/index.d.ts +2 -0
- package/dist/api/index.js +2 -0
- package/dist/api/routes.d.ts +17 -4
- package/dist/api/routes.js +21 -5
- package/dist/build-root.d.ts +1 -16
- package/dist/build-root.js +1 -25
- package/dist/builtin-memory/00-runtime-base.md +7 -5
- package/dist/builtin-memory/04-base-worker.md +1 -1
- package/dist/builtin-memory/04-orchestration-kernel.md +7 -7
- package/dist/builtin-memory/05-kinds/design/00-base.md +1 -1
- package/dist/builtin-memory/05-kinds/design/01-orchestrator.md +1 -1
- package/dist/builtin-memory/05-kinds/developer/00-base.md +1 -1
- package/dist/builtin-memory/05-kinds/explore/00-base.md +1 -1
- package/dist/builtin-memory/05-kinds/plan/00-base.md +1 -1
- package/dist/builtin-memory/05-kinds/plan/01-orchestrator.md +1 -1
- package/dist/builtin-memory/05-kinds/review/00-base.md +1 -1
- package/dist/builtin-memory/05-kinds/review/companion/00-base.md +20 -0
- package/dist/builtin-memory/05-kinds/spec/00-base.md +3 -7
- package/dist/builtin-memory/05-kinds/spec/01-orchestrator.md +3 -3
- package/dist/builtin-memory/05-kinds/spec/requirements.md +3 -3
- package/dist/builtin-memory/design.md +2 -2
- package/dist/builtin-memory/insights/capture.md +50 -0
- package/dist/builtin-memory/insights/init.md +45 -0
- package/dist/builtin-memory/insights/listen.md +9 -0
- package/dist/builtin-memory/internal/agent-shaping.md +2 -2
- package/dist/builtin-memory/internal/nodes-and-canvas.md +1 -1
- package/dist/builtin-memory/internal/plugins.md +12 -11
- package/dist/builtin-memory/internal/storage-tiers.md +2 -2
- package/dist/builtin-memory/{planning.md → plan/roadmap.md} +3 -3
- package/dist/builtin-memory/plan.md +19 -0
- package/dist/builtin-memory/spec/guide.md +38 -0
- package/dist/builtin-memory/spec/requirements.md +31 -0
- package/dist/builtin-memory/spec/roadmap.md +35 -0
- package/dist/builtin-memory/spec.md +10 -86
- package/dist/builtin-pi-packages/pi-crtr-extensions/README.md +3 -4
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/__tests__/provider-rotation.test.ts +49 -5
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.d.ts +56 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.js +920 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.ts +221 -156
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/statusline.ts +4 -5
- package/dist/cli.js +2 -6
- package/dist/clients/attach/__tests__/attach-chrome-remote.test.js +7 -35
- package/dist/clients/attach/__tests__/attach-keybindings.test.js +32 -16
- package/dist/clients/attach/__tests__/context-message.test.js +142 -6
- package/dist/clients/attach/__tests__/crtr-output.test.js +29 -45
- package/dist/clients/attach/__tests__/diagram.test.js +1 -1
- package/dist/clients/attach/__tests__/file-review-focus.test.js +48 -0
- package/dist/clients/attach/__tests__/group-activity.test.js +266 -0
- package/dist/clients/attach/__tests__/input-controller-extension-command.test.js +32 -0
- package/dist/clients/attach/__tests__/session-identity-refresh.test.js +32 -0
- package/dist/clients/attach/__tests__/titled-editor-preview.test.js +1 -2
- package/dist/clients/attach/chrome/header.d.ts +10 -0
- package/dist/clients/attach/chrome/header.js +30 -0
- package/dist/clients/attach/chrome/recap.d.ts +7 -0
- package/dist/clients/attach/chrome/recap.js +19 -0
- package/dist/clients/attach/chrome/status-line.d.ts +3 -0
- package/dist/clients/attach/chrome/status-line.js +5 -0
- package/dist/clients/attach/chrome/widgets.js +11 -21
- package/dist/clients/attach/command.js +11 -7
- package/dist/clients/attach/config.d.ts +4 -0
- package/dist/clients/attach/config.js +3 -0
- package/dist/clients/attach/input/controller.d.ts +19 -0
- package/dist/clients/attach/input/controller.js +62 -28
- package/dist/clients/attach/input/titled-editor.d.ts +0 -4
- package/dist/clients/attach/input/titled-editor.js +2 -10
- package/dist/clients/attach/overlays/file-review.d.ts +9 -5
- package/dist/clients/attach/overlays/file-review.js +9 -70
- package/dist/clients/attach/overlays/help.d.ts +33 -0
- package/dist/clients/attach/overlays/help.js +204 -0
- package/dist/clients/attach/render/activity-slot.d.ts +4 -0
- package/dist/clients/attach/render/activity-slot.js +13 -0
- package/dist/clients/attach/render/chat-view.d.ts +117 -12
- package/dist/clients/attach/render/chat-view.js +604 -135
- package/dist/clients/attach/render/context-message.d.ts +2 -1
- package/dist/clients/attach/render/context-message.js +17 -13
- package/dist/clients/attach/render/crtr-output.js +1 -3
- package/dist/clients/attach/render/diagram.js +2 -2
- package/dist/clients/attach/render/edit-diff.d.ts +4 -1
- package/dist/clients/attach/render/edit-diff.js +7 -11
- package/dist/clients/attach/render/group-activity.d.ts +32 -0
- package/dist/clients/attach/render/group-activity.js +206 -0
- package/dist/clients/attach/render/group-recap.d.ts +10 -0
- package/dist/clients/attach/render/group-recap.js +93 -0
- package/dist/clients/attach/render/html-markdown.d.ts +17 -0
- package/dist/clients/attach/render/html-markdown.js +228 -0
- package/dist/clients/attach/render/measured-container.d.ts +96 -0
- package/dist/clients/attach/render/measured-container.js +322 -0
- package/dist/clients/attach/render/scroll-animation.d.ts +8 -0
- package/dist/clients/attach/render/scroll-animation.js +80 -0
- package/dist/clients/attach/render/tool-calls.js +6 -6
- package/dist/clients/attach/render/transcript-copy.d.ts +9 -0
- package/dist/clients/attach/render/transcript-copy.js +81 -0
- package/dist/clients/attach/render/viewport.d.ts +29 -0
- package/dist/clients/attach/render/viewport.js +159 -0
- package/dist/clients/attach/session/bindings.d.ts +10 -7
- package/dist/clients/attach/session/bindings.js +23 -8
- package/dist/clients/attach/session/connection.js +4 -5
- package/dist/clients/attach/session/context.d.ts +6 -4
- package/dist/clients/attach/session/frame.d.ts +34 -0
- package/dist/clients/attach/session/frame.js +176 -0
- package/dist/clients/attach/session/frames.d.ts +4 -1
- package/dist/clients/attach/session/frames.js +14 -1
- package/dist/clients/attach/session/identity.js +4 -3
- package/dist/clients/attach/session/input-wiring.d.ts +14 -4
- package/dist/clients/attach/session/input-wiring.js +15 -13
- package/dist/clients/attach/session/invariant.d.ts +9 -0
- package/dist/clients/attach/session/invariant.js +15 -0
- package/dist/clients/attach/session/keys.d.ts +10 -2
- package/dist/clients/attach/session/keys.js +13 -5
- package/dist/clients/attach/session/layout.d.ts +10 -8
- package/dist/clients/attach/session/layout.js +33 -34
- package/dist/clients/attach/session/mouse.d.ts +18 -0
- package/dist/clients/attach/session/mouse.js +64 -0
- package/dist/clients/attach/session/pane-tag.d.ts +3 -0
- package/dist/clients/attach/session/pane-tag.js +51 -8
- package/dist/clients/attach/session/reconnect.d.ts +3 -0
- package/dist/clients/attach/session/reconnect.js +42 -5
- package/dist/clients/attach/session/surface-frame.d.ts +20 -0
- package/dist/clients/attach/session/surface-frame.js +73 -0
- package/dist/clients/attach/session/surface-host.d.ts +64 -0
- package/dist/clients/attach/session/surface-host.js +255 -0
- package/dist/clients/attach/session/whip.d.ts +17 -0
- package/dist/clients/attach/session/whip.js +334 -0
- package/dist/clients/attach/slash/dispatch.d.ts +13 -1
- package/dist/clients/attach/slash/dispatch.js +51 -29
- package/dist/clients/attach/viewer.js +907 -819
- package/dist/clients/conversation/conversation.d.ts +65 -0
- package/dist/clients/conversation/conversation.js +318 -0
- package/dist/clients/conversation/frames.d.ts +30 -0
- package/dist/clients/conversation/frames.js +52 -0
- package/dist/clients/conversation/region.d.ts +51 -0
- package/dist/clients/conversation/region.js +265 -0
- package/dist/clients/conversation/submit.d.ts +38 -0
- package/dist/clients/conversation/submit.js +51 -0
- package/dist/clients/inbox/__tests__/inbox-controller.test.js +247 -0
- package/dist/clients/inbox/__tests__/mount-panel.test.js +776 -0
- package/dist/clients/inbox/controller.d.ts +79 -0
- package/dist/clients/inbox/controller.js +448 -0
- package/dist/clients/inbox/deck-adapter.d.ts +29 -0
- package/dist/clients/inbox/deck-adapter.js +62 -0
- package/dist/clients/inbox/layout.d.ts +8 -0
- package/dist/clients/inbox/layout.js +9 -0
- package/dist/clients/inbox/resolve.d.ts +10 -0
- package/dist/clients/inbox/resolve.js +34 -0
- package/dist/clients/inbox/review/__tests__/editor-roundtrip.test.js +29 -0
- package/dist/clients/inbox/review/__tests__/remap.test.js +196 -0
- package/dist/clients/inbox/review/__tests__/review-core.test.js +341 -0
- package/dist/clients/inbox/review/anchors.d.ts +41 -0
- package/dist/clients/inbox/review/anchors.js +89 -0
- package/dist/clients/inbox/review/columns.d.ts +22 -0
- package/dist/clients/inbox/review/columns.js +40 -0
- package/dist/clients/inbox/review/comments-client.d.ts +66 -0
- package/dist/clients/inbox/review/comments-client.js +98 -0
- package/dist/clients/inbox/review/composition.d.ts +60 -0
- package/dist/clients/inbox/review/composition.js +278 -0
- package/dist/clients/inbox/review/document-region.d.ts +120 -0
- package/dist/clients/inbox/review/document-region.js +902 -0
- package/dist/clients/inbox/review/frame.d.ts +45 -0
- package/dist/clients/inbox/review/frame.js +215 -0
- package/dist/clients/inbox/review/keys.d.ts +67 -0
- package/dist/clients/inbox/review/keys.js +130 -0
- package/dist/clients/inbox/review/launch.d.ts +10 -0
- package/dist/clients/inbox/review/launch.js +129 -0
- package/dist/clients/inbox/review/live-source.d.ts +24 -0
- package/dist/clients/inbox/review/live-source.js +160 -0
- package/dist/clients/inbox/review/nvim.d.ts +13 -0
- package/dist/clients/inbox/review/nvim.js +42 -0
- package/dist/clients/inbox/review/remap.d.ts +51 -0
- package/dist/clients/inbox/review/remap.js +157 -0
- package/dist/clients/inbox/review/review-client.d.ts +30 -0
- package/dist/clients/inbox/review/review-client.js +107 -0
- package/dist/clients/inbox/review/roundtrip.d.ts +5 -0
- package/dist/clients/inbox/review/roundtrip.js +36 -0
- package/dist/clients/inbox/review/state.d.ts +143 -0
- package/dist/clients/inbox/review/state.js +282 -0
- package/dist/clients/inbox/review-adapter.d.ts +29 -0
- package/dist/clients/inbox/review-adapter.js +92 -0
- package/dist/clients/inbox/review-visibility.d.ts +5 -0
- package/dist/clients/inbox/review-visibility.js +19 -0
- package/dist/clients/inbox/surface.d.ts +19 -0
- package/dist/clients/inbox/surface.js +128 -0
- package/dist/clients/inbox/tui/ansi.d.ts +66 -0
- package/dist/clients/inbox/tui/ansi.js +317 -0
- package/dist/clients/inbox/tui/clipboard.d.ts +2 -0
- package/dist/clients/inbox/tui/clipboard.js +26 -0
- package/dist/clients/inbox/tui/input.d.ts +7 -0
- package/dist/clients/inbox/tui/input.js +653 -0
- package/dist/clients/inbox/tui/keys.d.ts +28 -0
- package/dist/clients/inbox/tui/keys.js +111 -0
- package/dist/clients/inbox/tui/panel.d.ts +2 -0
- package/dist/clients/inbox/tui/panel.js +217 -0
- package/dist/clients/inbox/tui/render.d.ts +37 -0
- package/dist/clients/inbox/tui/render.js +476 -0
- package/dist/clients/inbox/tui/types.d.ts +57 -0
- package/dist/clients/inbox/tui/types.js +1 -0
- package/dist/clients/inbox/tui.d.ts +6 -0
- package/dist/clients/inbox/tui.js +74 -0
- package/dist/clients/surfaces/host.d.ts +66 -0
- package/dist/clients/surfaces/host.js +1 -0
- package/dist/clients/surfaces/region.d.ts +16 -0
- package/dist/clients/surfaces/region.js +1 -0
- package/dist/clients/web/__tests__/push-engine.test.js +14 -158
- package/dist/clients/web/dev-server.d.ts +3 -3
- package/dist/clients/web/dev-server.js +9 -23
- package/dist/clients/web/events.js +4 -6
- package/dist/clients/web/push-engine.d.ts +2 -66
- package/dist/clients/web/push-engine.js +30 -161
- package/dist/clients/web/push-registry.d.ts +0 -4
- package/dist/clients/web/push-registry.js +2 -7
- package/dist/clients/web/server.js +3 -35
- package/dist/clients/web/web-client/shared/protocol.d.ts +0 -108
- package/dist/clients/web/web-cmd.js +2 -2
- package/dist/commands/__tests__/human.test.js +27 -15
- package/dist/commands/api-client.js +3 -3
- package/dist/commands/canvas-browse.js +1 -1
- package/dist/commands/canvas-issue.js +1 -1
- package/dist/commands/canvas-use.js +1 -1
- package/dist/commands/human/doc.d.ts +2 -0
- package/dist/commands/human/doc.js +98 -0
- package/dist/commands/human/inbox.d.ts +2 -0
- package/dist/commands/human/inbox.js +101 -0
- package/dist/commands/human/prompts.d.ts +2 -3
- package/dist/commands/human/prompts.js +27 -180
- package/dist/commands/human/queue.d.ts +1 -5
- package/dist/commands/human/queue.js +54 -216
- package/dist/commands/human/review.d.ts +2 -0
- package/dist/commands/human/review.js +298 -0
- package/dist/commands/human/shared.d.ts +2 -69
- package/dist/commands/human/shared.js +1 -181
- package/dist/commands/human.js +15 -20
- package/dist/commands/memory/__tests__/lint.test.d.ts +1 -0
- package/dist/commands/memory/__tests__/lint.test.js +15 -0
- package/dist/commands/memory/delete.js +2 -2
- package/dist/commands/memory/lint.d.ts +1 -0
- package/dist/commands/memory/lint.js +21 -3
- package/dist/commands/memory/read.js +4 -4
- package/dist/commands/node.js +8 -7
- package/dist/commands/pkg/plugin-manage.js +143 -68
- package/dist/commands/surface-inspect.js +2 -2
- package/dist/commands/surface.js +6 -12
- package/dist/commands/sys/__tests__/setup-core.test.js +9 -5
- package/dist/commands/sys/__tests__/setup-front-door.test.js +7 -42
- package/dist/commands/sys/config.js +29 -3
- package/dist/commands/sys/feedback.js +1 -1
- package/dist/commands/sys/setup-core.d.ts +12 -11
- package/dist/commands/sys/setup-core.js +55 -46
- package/dist/commands/sys/setup-wizard.d.ts +4 -1
- package/dist/commands/sys/setup-wizard.js +50 -9
- package/dist/commands/sys/sync-deps.js +1 -1
- package/dist/commands/sys.js +4 -6
- package/dist/core/__tests__/broker-sdk-wiring.test.js +6 -1
- package/dist/core/__tests__/broker-snapshot-history.test.js +9 -1
- package/dist/core/__tests__/dead-node-policy-table.test.js +3 -4
- package/dist/core/__tests__/fixtures/fake-engine.d.ts +8 -5
- package/dist/core/__tests__/fixtures/fake-engine.js +28 -2
- package/dist/core/__tests__/full/broker-provider-retry.test.js +87 -2
- package/dist/core/__tests__/full/broker-whip-interrupt.test.d.ts +1 -0
- package/dist/core/__tests__/full/broker-whip-interrupt.test.js +39 -0
- package/dist/core/__tests__/full/detach-focus.test.js +1 -1
- package/dist/core/__tests__/human-deliver-e2e.test.js +64 -64
- package/dist/core/__tests__/human-deliver.test.js +71 -345
- package/dist/core/__tests__/inline-memory-refs.test.js +2 -12
- package/dist/core/__tests__/memory-resolver-precedence.test.js +12 -15
- package/dist/core/__tests__/migration.test.js +10 -0
- package/dist/core/__tests__/model-pin-durability.test.js +14 -0
- package/dist/core/__tests__/phase4-review-migration.test.d.ts +1 -0
- package/dist/core/__tests__/phase4-review-migration.test.js +100 -0
- package/dist/core/__tests__/phase4-review-store.test.d.ts +1 -0
- package/dist/core/__tests__/phase4-review-store.test.js +143 -0
- package/dist/core/__tests__/remote-canvas-target.test.js +2 -2
- package/dist/core/__tests__/revive.test.js +22 -53
- package/dist/core/__tests__/session-cycles.test.js +48 -18
- package/dist/core/__tests__/spawn-no-kickoff.test.js +8 -12
- package/dist/core/__tests__/stop-guard.test.js +16 -1
- package/dist/core/__tests__/tmux-surface.test.js +21 -25
- package/dist/core/asset-root.d.ts +7 -0
- package/dist/core/asset-root.js +18 -0
- package/dist/core/broker-client/client.d.ts +0 -7
- package/dist/core/broker-client/client.js +4 -10
- package/dist/core/broker-client/transport-relay.d.ts +3 -4
- package/dist/core/broker-client/transport-relay.js +3 -4
- package/dist/core/canvas/__tests__/attention.test.js +1 -1
- package/dist/core/canvas/__tests__/remote-canvas-source.test.js +1 -1
- package/dist/core/canvas/__tests__/remote-transport.test.d.ts +1 -0
- package/dist/core/{view/__tests__/transport-remote.test.js → canvas/__tests__/remote-transport.test.js} +2 -2
- package/dist/core/canvas/__tests__/render-remote.test.js +1 -1
- package/dist/core/canvas/attention.js +4 -4
- package/dist/core/canvas/canvas.d.ts +6 -11
- package/dist/core/canvas/canvas.js +11 -33
- package/dist/core/canvas/db.js +207 -38
- package/dist/core/canvas/extensions.d.ts +1 -1
- package/dist/core/canvas/extensions.js +8 -1
- package/dist/core/canvas/index.d.ts +0 -1
- package/dist/core/canvas/index.js +0 -1
- package/dist/core/canvas/nav-model.d.ts +1 -1
- package/dist/core/canvas/nav-model.js +1 -1
- package/dist/core/canvas/paths.d.ts +5 -0
- package/dist/core/canvas/paths.js +16 -0
- package/dist/core/canvas/remote-canvas-source.js +2 -2
- package/dist/core/canvas/remote-transport.d.ts +7 -0
- package/dist/core/{view/transport-remote.js → canvas/remote-transport.js} +3 -4
- package/dist/core/canvas/source.js +1 -1
- package/dist/core/canvas/status-glyph.js +4 -12
- package/dist/core/canvas/types.d.ts +10 -35
- package/dist/core/clipboard-text.d.ts +8 -0
- package/dist/core/clipboard-text.js +18 -0
- package/dist/core/command-manifests/registry.d.ts +1 -3
- package/dist/core/command-plugins/bundle.d.ts +29 -0
- package/dist/core/command-plugins/bundle.js +198 -0
- package/dist/core/command-plugins/discovery.d.ts +0 -8
- package/dist/core/command-plugins/discovery.js +2 -39
- package/dist/core/command-plugins/transport/http-fetch.d.ts +4 -30
- package/dist/core/command-plugins/transport/http-fetch.js +17 -95
- package/dist/core/command.d.ts +1 -13
- package/dist/core/command.js +1 -16
- package/dist/core/config.d.ts +4 -0
- package/dist/core/config.js +28 -3
- package/dist/core/document-lines.d.ts +4 -0
- package/dist/core/document-lines.js +6 -0
- package/dist/core/feed/feed.d.ts +2 -0
- package/dist/core/feed/feed.js +11 -7
- package/dist/core/human/__tests__/inbox-cancel-worker.d.ts +1 -0
- package/dist/core/human/__tests__/inbox-cancel-worker.js +7 -0
- package/dist/core/human/__tests__/inbox-claim-worker.d.ts +1 -0
- package/dist/core/human/__tests__/inbox-claim-worker.js +17 -0
- package/dist/core/human/__tests__/inbox-core.test.d.ts +1 -0
- package/dist/core/human/__tests__/inbox-core.test.js +144 -0
- package/dist/core/human/__tests__/inbox-stale-claim-worker.d.ts +1 -0
- package/dist/core/human/__tests__/inbox-stale-claim-worker.js +8 -0
- package/dist/core/human/__tests__/visible-paths.test.d.ts +1 -0
- package/dist/{clients/attach → core/human}/__tests__/visible-paths.test.js +9 -0
- package/dist/core/human/claim.d.ts +23 -0
- package/dist/core/human/claim.js +67 -0
- package/dist/core/human/convention.d.ts +30 -0
- package/dist/core/human/convention.js +202 -0
- package/dist/core/human/deck-factories.d.ts +8 -0
- package/dist/core/human/deck-factories.js +15 -0
- package/dist/core/human/deck-schema.d.ts +70 -0
- package/dist/core/human/deck-schema.js +92 -0
- package/dist/core/human/root.d.ts +7 -0
- package/dist/core/human/root.js +37 -0
- package/dist/core/human/scan.d.ts +3 -0
- package/dist/core/human/scan.js +76 -0
- package/dist/core/human/summary.d.ts +8 -0
- package/dist/core/human/summary.js +44 -0
- package/dist/core/human/tickets.d.ts +49 -0
- package/dist/core/human/tickets.js +190 -0
- package/dist/core/human/types.d.ts +136 -0
- package/dist/core/human/types.js +5 -0
- package/dist/{clients/attach → core/human}/visible-paths.d.ts +1 -1
- package/dist/{clients/attach → core/human}/visible-paths.js +3 -2
- package/dist/core/inspector/chrome.d.ts +6 -0
- package/dist/core/inspector/chrome.js +14 -0
- package/dist/core/inspector/contract.d.ts +105 -0
- package/dist/core/inspector/contract.js +1 -0
- package/dist/core/inspector/core.d.ts +4 -5
- package/dist/core/inspector/core.js +3 -5
- package/dist/core/inspector/host.d.ts +46 -0
- package/dist/core/{tui → inspector}/host.js +42 -208
- package/dist/core/inspector/text.d.ts +2 -2
- package/dist/core/inspector/transport.d.ts +6 -0
- package/dist/core/inspector/transport.js +36 -0
- package/dist/core/inspector/tui.d.ts +2 -2
- package/dist/core/inspector/tui.js +15 -15
- package/dist/core/keybindings/__tests__/inbox-affordance.test.js +11 -11
- package/dist/core/keybindings/__tests__/resolve.test.js +10 -19
- package/dist/core/keybindings/attach-control.d.ts +9 -3
- package/dist/core/keybindings/attach-control.js +3 -1
- package/dist/core/keybindings/catalog.d.ts +6 -5
- package/dist/core/keybindings/catalog.js +61 -133
- package/dist/core/keybindings/inbox.d.ts +5 -6
- package/dist/core/keybindings/inbox.js +9 -10
- package/dist/core/keybindings/index.d.ts +3 -3
- package/dist/core/keybindings/index.js +3 -3
- package/dist/core/keybindings/persistence.d.ts +5 -1
- package/dist/core/keybindings/persistence.js +24 -6
- package/dist/core/keybindings/resolve.d.ts +6 -0
- package/dist/core/keybindings/resolve.js +10 -3
- package/dist/core/memory/inline-ref-grammar.js +2 -3
- package/dist/core/memory-resolver.d.ts +27 -29
- package/dist/core/memory-resolver.js +45 -39
- package/dist/core/model-routes.d.ts +33 -0
- package/dist/core/model-routes.js +42 -3
- package/dist/core/preview-registry.js +17 -55
- package/dist/core/profiles/select.js +3 -3
- package/dist/core/{view/remote-canvas-target.d.ts → remote-canvas-target.d.ts} +2 -2
- package/dist/core/{view/remote-canvas-target.js → remote-canvas-target.js} +4 -4
- package/dist/core/review/__tests__/capture-origin.test.d.ts +1 -0
- package/dist/core/review/__tests__/capture-origin.test.js +139 -0
- package/dist/core/review/__tests__/comments.test.d.ts +1 -0
- package/dist/core/review/__tests__/comments.test.js +98 -0
- package/dist/core/review/__tests__/project.test.d.ts +1 -0
- package/dist/core/review/__tests__/project.test.js +71 -0
- package/dist/core/review/__tests__/remap.test.d.ts +1 -0
- package/dist/core/review/__tests__/remap.test.js +159 -0
- package/dist/core/review/__tests__/stage-identity.test.d.ts +1 -0
- package/dist/core/review/__tests__/stage-identity.test.js +140 -0
- package/dist/core/review/birth.d.ts +7 -0
- package/dist/core/review/birth.js +23 -0
- package/dist/core/review/comments.d.ts +69 -0
- package/dist/core/review/comments.js +295 -0
- package/dist/core/review/companion.d.ts +35 -0
- package/dist/core/review/companion.js +205 -0
- package/dist/core/review/document.d.ts +27 -0
- package/dist/core/review/document.js +138 -0
- package/dist/core/review/project.d.ts +13 -0
- package/dist/core/review/project.js +58 -0
- package/dist/core/review/realize.d.ts +19 -0
- package/dist/core/review/realize.js +217 -0
- package/dist/core/review/remap.d.ts +24 -0
- package/dist/core/review/remap.js +156 -0
- package/dist/core/review/signal.d.ts +5 -0
- package/dist/core/review/signal.js +31 -0
- package/dist/core/review/stage.d.ts +26 -0
- package/dist/core/review/stage.js +184 -0
- package/dist/core/review/store.d.ts +46 -0
- package/dist/core/review/store.js +163 -0
- package/dist/core/review/ticket-filter.d.ts +17 -0
- package/dist/core/review/ticket-filter.js +32 -0
- package/dist/core/review/types.d.ts +130 -0
- package/dist/core/review/types.js +23 -0
- package/dist/core/runtime/__tests__/session-visibility.test.d.ts +1 -0
- package/dist/core/runtime/__tests__/session-visibility.test.js +119 -0
- package/dist/core/runtime/bearings.d.ts +5 -17
- package/dist/core/runtime/bearings.js +88 -71
- package/dist/core/runtime/broker-protocol.d.ts +31 -8
- package/dist/core/runtime/broker.d.ts +15 -1
- package/dist/core/runtime/broker.js +573 -141
- package/dist/core/runtime/canvas-extensions.d.ts +4 -5
- package/dist/core/runtime/canvas-extensions.js +5 -5
- package/dist/core/runtime/front-door.js +4 -4
- package/dist/core/runtime/headless-pi.d.ts +24 -0
- package/dist/core/runtime/headless-pi.js +152 -0
- package/dist/core/runtime/kickoff.d.ts +1 -5
- package/dist/core/runtime/kickoff.js +1 -5
- package/dist/core/runtime/model-registry.d.ts +3 -0
- package/dist/core/runtime/model-registry.js +13 -0
- package/dist/core/runtime/naming-persist.d.ts +4 -0
- package/dist/core/runtime/naming-persist.js +27 -1
- package/dist/core/runtime/naming.d.ts +17 -12
- package/dist/core/runtime/naming.js +91 -140
- package/dist/core/runtime/node-read.js +19 -10
- package/dist/core/runtime/nodes.d.ts +9 -14
- package/dist/core/runtime/nodes.js +3 -53
- package/dist/core/runtime/package-health.d.ts +6 -21
- package/dist/core/runtime/package-health.js +12 -123
- package/dist/core/runtime/placement-tmux.d.ts +2 -1
- package/dist/core/runtime/placement-tmux.js +6 -4
- package/dist/core/runtime/placement.d.ts +1 -0
- package/dist/core/runtime/placement.js +4 -8
- package/dist/core/runtime/promote.js +3 -0
- package/dist/core/runtime/recap.d.ts +2 -7
- package/dist/core/runtime/recap.js +35 -69
- package/dist/core/runtime/revive.js +34 -77
- package/dist/core/runtime/session-cycles.d.ts +4 -0
- package/dist/core/runtime/session-cycles.js +14 -1
- package/dist/core/runtime/session-visibility.d.ts +37 -0
- package/dist/core/runtime/session-visibility.js +83 -0
- package/dist/core/runtime/spawn.js +10 -22
- package/dist/core/runtime/stop-guard.d.ts +1 -1
- package/dist/core/runtime/stop-guard.js +18 -13
- package/dist/core/runtime/surface-bg.js +1 -1
- package/dist/core/runtime/tmux-chrome.d.ts +1 -1
- package/dist/core/runtime/tmux-chrome.js +1 -1
- package/dist/core/runtime/tmux.d.ts +35 -7
- package/dist/core/runtime/tmux.js +439 -62
- package/dist/core/runtime/tool-group-summary.d.ts +19 -0
- package/dist/core/runtime/tool-group-summary.js +88 -0
- package/dist/core/scope.d.ts +2 -7
- package/dist/core/scope.js +9 -35
- package/dist/core/substrate/schema.d.ts +2 -2
- package/dist/core/termrender/code-doc.d.ts +12 -0
- package/dist/core/termrender/code-doc.js +92 -0
- package/dist/core/termrender/display.d.ts +12 -0
- package/dist/core/termrender/display.js +19 -0
- package/dist/core/termrender/termrender.d.ts +73 -0
- package/dist/core/termrender/termrender.js +795 -0
- package/dist/core/termrender/version.d.ts +1 -0
- package/dist/core/termrender/version.js +1 -0
- package/dist/core/tui/terminal.js +1 -2
- package/dist/core/user-settings.d.ts +71 -3
- package/dist/core/user-settings.js +83 -1
- package/dist/daemon/api/__tests__/inbox.test.js +44 -133
- package/dist/daemon/api/handlers/human.d.ts +0 -10
- package/dist/daemon/api/handlers/human.js +104 -702
- package/dist/daemon/api/handlers/inbox.js +113 -142
- package/dist/daemon/api/handlers/review-comments.d.ts +2 -0
- package/dist/daemon/api/handlers/review-comments.js +500 -0
- package/dist/daemon/api/handlers/reviews.d.ts +2 -0
- package/dist/daemon/api/handlers/reviews.js +287 -0
- package/dist/daemon/api/map.d.ts +22 -7
- package/dist/daemon/api/map.js +159 -11
- package/dist/daemon/api/server.js +4 -0
- package/dist/daemon/cron-run.js +6 -9
- package/dist/daemon/crtrd.js +17 -33
- package/dist/daemon/fleet.d.ts +1 -8
- package/dist/daemon/fleet.js +4 -30
- package/dist/daemon/human/finish.d.ts +14 -0
- package/dist/daemon/human/finish.js +115 -0
- package/dist/daemon/human/sweep.d.ts +6 -0
- package/dist/daemon/human/sweep.js +49 -0
- package/dist/daemon/messaging/node-message.d.ts +18 -0
- package/dist/daemon/messaging/node-message.js +70 -0
- package/dist/daemon/review/comment-notify.d.ts +26 -0
- package/dist/daemon/review/comment-notify.js +107 -0
- package/dist/daemon/review/deliver.d.ts +7 -0
- package/dist/daemon/review/deliver.js +56 -0
- package/dist/daemon/review/finish.d.ts +22 -0
- package/dist/daemon/review/finish.js +254 -0
- package/dist/daemon/review/sweep.d.ts +11 -0
- package/dist/daemon/review/sweep.js +120 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -2
- package/dist/pi-extensions/__tests__/canvas-context-intro.test.js +42 -64
- package/dist/pi-extensions/__tests__/canvas-recap.test.d.ts +1 -0
- package/dist/pi-extensions/__tests__/canvas-recap.test.js +159 -0
- package/dist/pi-extensions/__tests__/canvas-stophook-agentend.test.js +16 -38
- package/dist/pi-extensions/__tests__/canvas-structured-output.test.d.ts +1 -0
- package/dist/pi-extensions/__tests__/canvas-structured-output.test.js +63 -0
- package/dist/pi-extensions/canvas-context-intro.d.ts +8 -11
- package/dist/pi-extensions/canvas-context-intro.js +50 -104
- package/dist/pi-extensions/canvas-recap.d.ts +15 -2
- package/dist/pi-extensions/canvas-recap.js +192 -69
- package/dist/pi-extensions/canvas-review-boundary.d.ts +59 -0
- package/dist/pi-extensions/canvas-review-boundary.js +81 -0
- package/dist/pi-extensions/canvas-stophook.d.ts +3 -3
- package/dist/pi-extensions/canvas-stophook.js +78 -128
- package/dist/pi-extensions/canvas-structured-output.js +52 -8
- package/dist/shared/generated-context.d.ts +29 -4
- package/dist/shared/generated-context.js +122 -7
- package/dist/shared/tool-groups.d.ts +23 -0
- package/dist/shared/tool-groups.js +60 -0
- package/dist/shared/working-activity.d.ts +8 -0
- package/dist/shared/working-activity.js +26 -0
- package/dist/types.d.ts +36 -2
- package/dist/types.js +51 -0
- package/dist/web-client/assets/index-CCPaLeW7.css +2 -0
- package/dist/web-client/assets/index-kyOWsnZK.js +86 -0
- package/dist/web-client/index.html +2 -2
- package/dist/web-client/sw.js +1 -1
- package/docs/compat/hearth-crtr-v4.md +2 -2
- package/docs/compat/hearth-crtr-v5.md +4 -2
- package/docs/public-api.md +3 -3
- package/package.json +21 -14
- package/runtime.lock.json +4661 -1453
- package/scripts/postinstall.mjs +15 -2
- package/dist/builtin-pi-packages/pi-mode-switch/README.md +0 -36
- package/dist/builtin-pi-packages/pi-mode-switch/bin/mode +0 -36
- package/dist/builtin-pi-packages/pi-mode-switch/extensions/index.ts +0 -449
- package/dist/builtin-pi-packages/pi-mode-switch/package.json +0 -14
- package/dist/builtin-pi-packages/pi-mode-switch/tsconfig.json +0 -9
- package/dist/builtin-views/_lib/states.mjs +0 -161
- package/dist/builtin-views/canvas/core.mjs +0 -657
- package/dist/builtin-views/canvas/text.mjs +0 -58
- package/dist/builtin-views/canvas/tui.mjs +0 -168
- package/dist/builtin-views/canvas/web.jsx +0 -121
- package/dist/builtin-views/chat/core.mjs +0 -684
- package/dist/builtin-views/chat/text.mjs +0 -101
- package/dist/builtin-views/chat/tui.mjs +0 -360
- package/dist/builtin-views/chat/web.jsx +0 -362
- package/dist/builtin-views/git-pr/core.mjs +0 -673
- package/dist/builtin-views/git-pr/text.mjs +0 -84
- package/dist/builtin-views/git-pr/tui.mjs +0 -301
- package/dist/builtin-views/git-pr/web.jsx +0 -216
- package/dist/builtin-views/inbox/_lib/render.mjs +0 -175
- package/dist/builtin-views/inbox/core.mjs +0 -1273
- package/dist/builtin-views/inbox/text.mjs +0 -73
- package/dist/builtin-views/inbox/tui.mjs +0 -314
- package/dist/builtin-views/inbox/web.jsx +0 -188
- package/dist/builtin-views/linkedin/core.mjs +0 -906
- package/dist/builtin-views/linkedin/text.mjs +0 -69
- package/dist/builtin-views/linkedin/tui.mjs +0 -413
- package/dist/builtin-views/linkedin/web.jsx +0 -206
- package/dist/builtin-views/prompt-review/core.mjs +0 -735
- package/dist/builtin-views/prompt-review/text.mjs +0 -15
- package/dist/builtin-views/prompt-review/tui.mjs +0 -196
- package/dist/builtin-views/prompt-review/web.jsx +0 -484
- package/dist/builtin-views/workspace-sidebar/__tests__/core.test.js +0 -50
- package/dist/builtin-views/workspace-sidebar/__tests__/core.test.ts +0 -53
- package/dist/builtin-views/workspace-sidebar/core.mjs +0 -670
- package/dist/builtin-views/workspace-sidebar/text.mjs +0 -53
- package/dist/builtin-views/workspace-sidebar/tui.mjs +0 -141
- package/dist/builtin-views/workspace-sidebar/web.jsx +0 -109
- package/dist/clients/attach/session/mode.d.ts +0 -25
- package/dist/clients/attach/session/mode.js +0 -97
- package/dist/commands/sys/promptstudio.d.ts +0 -2
- package/dist/commands/sys/promptstudio.js +0 -65
- package/dist/commands/view-cycle.d.ts +0 -2
- package/dist/commands/view-cycle.js +0 -130
- package/dist/commands/view-list.d.ts +0 -2
- package/dist/commands/view-list.js +0 -66
- package/dist/commands/view-new.d.ts +0 -2
- package/dist/commands/view-new.js +0 -74
- package/dist/commands/view-pick.d.ts +0 -6
- package/dist/commands/view-pick.js +0 -129
- package/dist/commands/view-run.d.ts +0 -2
- package/dist/commands/view-run.js +0 -214
- package/dist/commands/view.d.ts +0 -2
- package/dist/commands/view.js +0 -31
- package/dist/commands/workspace.d.ts +0 -2
- package/dist/commands/workspace.js +0 -165
- package/dist/core/__tests__/chat-view-reconnect.test.js +0 -105
- package/dist/core/__tests__/full/consult-startup-failure.test.js +0 -124
- package/dist/core/canvas/__tests__/human-work-outbox.test.js +0 -123
- package/dist/core/canvas/human-work-outbox.d.ts +0 -73
- package/dist/core/canvas/human-work-outbox.js +0 -261
- package/dist/core/command-plugins/store.d.ts +0 -16
- package/dist/core/command-plugins/store.js +0 -64
- package/dist/core/keybindings/__tests__/bespoke-consumers.test.js +0 -40
- package/dist/core/runtime/fault-recovery-nudge.d.ts +0 -3
- package/dist/core/runtime/fault-recovery-nudge.js +0 -3
- package/dist/core/tui/__tests__/host-keybindings.test.js +0 -113
- package/dist/core/tui/host.d.ts +0 -66
- package/dist/core/view/__tests__/transport-cache.test.js +0 -62
- package/dist/core/view/bridge.d.ts +0 -10
- package/dist/core/view/bridge.js +0 -31
- package/dist/core/view/chrome.d.ts +0 -9
- package/dist/core/view/chrome.js +0 -22
- package/dist/core/view/contract.d.ts +0 -205
- package/dist/core/view/contract.js +0 -23
- package/dist/core/view/loader.d.ts +0 -31
- package/dist/core/view/loader.js +0 -188
- package/dist/core/view/stream-local.d.ts +0 -3
- package/dist/core/view/stream-local.js +0 -231
- package/dist/core/view/transport-cache.d.ts +0 -8
- package/dist/core/view/transport-cache.js +0 -38
- package/dist/core/view/transport-local.d.ts +0 -7
- package/dist/core/view/transport-local.js +0 -83
- package/dist/core/view/transport-remote.d.ts +0 -2
- package/dist/core/view/transport.d.ts +0 -10
- package/dist/core/view/transport.js +0 -15
- package/dist/pi-extensions/naming-tool.d.ts +0 -24
- package/dist/pi-extensions/naming-tool.js +0 -67
- package/dist/prompts/view.d.ts +0 -7
- package/dist/prompts/view.js +0 -172
- package/dist/web/ViewChrome.d.ts +0 -7
- package/dist/web/ViewChrome.js +0 -28
- package/dist/web/ViewPane.d.ts +0 -39
- package/dist/web/ViewPane.js +0 -48
- package/dist/web/index.d.ts +0 -8
- package/dist/web/index.js +0 -22
- package/dist/web/runtime.d.ts +0 -39
- package/dist/web/runtime.js +0 -232
- package/dist/web/states.d.ts +0 -24
- package/dist/web/states.js +0 -24
- package/dist/web/transport-http.d.ts +0 -5
- package/dist/web/transport-http.js +0 -34
- package/dist/web/transport-stream.d.ts +0 -3
- package/dist/web/transport-stream.js +0 -204
- package/dist/web-client/assets/index-U_NZ66VE.js +0 -79
- package/dist/web-client/assets/index-aaeu4adv.css +0 -2
- /package/dist/{builtin-views/workspace-sidebar/__tests__/core.test.d.ts → clients/attach/__tests__/file-review-focus.test.d.ts} +0 -0
- /package/dist/clients/attach/__tests__/{visible-paths.test.d.ts → group-activity.test.d.ts} +0 -0
- /package/dist/{core/__tests__/chat-view-reconnect.test.d.ts → clients/attach/__tests__/input-controller-extension-command.test.d.ts} +0 -0
- /package/dist/{core/__tests__/full/consult-startup-failure.test.d.ts → clients/attach/__tests__/session-identity-refresh.test.d.ts} +0 -0
- /package/dist/{core/canvas/__tests__/human-work-outbox.test.d.ts → clients/inbox/__tests__/inbox-controller.test.d.ts} +0 -0
- /package/dist/{core/keybindings/__tests__/bespoke-consumers.test.d.ts → clients/inbox/__tests__/mount-panel.test.d.ts} +0 -0
- /package/dist/{core/tui/__tests__/host-keybindings.test.d.ts → clients/inbox/review/__tests__/editor-roundtrip.test.d.ts} +0 -0
- /package/dist/{core/view/__tests__/transport-cache.test.d.ts → clients/inbox/review/__tests__/remap.test.d.ts} +0 -0
- /package/dist/{core/view/__tests__/transport-remote.test.d.ts → clients/inbox/review/__tests__/review-core.test.d.ts} +0 -0
|
@@ -1,49 +1,27 @@
|
|
|
1
1
|
// Run with: node --import tsx/esm --test src/core/__tests__/human-deliver.test.ts
|
|
2
2
|
//
|
|
3
|
-
//
|
|
4
|
-
// pin the two crouter boundaries the hard cut leaves behind:
|
|
5
|
-
// 1. ask/review ENQUEUE only — they create a bridge node, write a minimal
|
|
6
|
-
// run.json, submit to humanloop, and return immediately. No pane/pid.
|
|
7
|
-
// 2. `_deliver` is the registered completion handler — it turns a humanloop
|
|
8
|
-
// completion event into the existing `pushFinal` delivery (deck/review) or
|
|
9
|
-
// a quiet bridge finalization (canceled), idempotently.
|
|
10
|
-
//
|
|
11
|
-
// Everything crosses the real humanloop package boundary: fixtures are the
|
|
12
|
-
// canonical `response.json` union that humanloop's strict `readTicketResult`
|
|
13
|
-
// decodes. Tickets live under a root REGISTERED to owner 'crouter' (the
|
|
14
|
-
// delivery contract), isolated via a temp XDG_STATE_HOME + HOME + CRTR_HOME.
|
|
3
|
+
// Crouter creates bridge tickets, while crtrd owns terminal ticket delivery.
|
|
15
4
|
import { test, describe, before, after, beforeEach, afterEach } from 'node:test';
|
|
16
5
|
import assert from 'node:assert/strict';
|
|
17
|
-
import { mkdtempSync,
|
|
6
|
+
import { mkdtempSync, rmSync, writeFileSync, readFileSync, existsSync } from 'node:fs';
|
|
18
7
|
import { tmpdir } from 'node:os';
|
|
19
|
-
import {
|
|
8
|
+
import { join, resolve } from 'node:path';
|
|
20
9
|
import { Readable } from 'node:stream';
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
10
|
+
import { createApiServer } from '../../daemon/api/server.js';
|
|
11
|
+
import { cancelHumanTicket, deliverTerminalResult, resolveDeckTicket } from '../../daemon/human/finish.js';
|
|
12
|
+
import { humanAsk, humanNotify } from '../../commands/human/prompts.js';
|
|
13
|
+
import { runCli } from '../command.js';
|
|
23
14
|
import { getNode, listNodes, closeDb } from '../canvas/index.js';
|
|
24
15
|
import { readInboxSince } from '../feed/inbox.js';
|
|
25
|
-
import { humanAsk, humanReview, humanNotify } from '../../commands/human/prompts.js';
|
|
26
|
-
import { runCli } from '../command.js';
|
|
27
16
|
import { resolveRef } from '../canvas/history.js';
|
|
28
|
-
import { humanDeliver } from '../../commands/human/queue.js';
|
|
29
|
-
import { createApiServer } from '../../daemon/api/server.js';
|
|
30
|
-
import { trustedCrouterVisualHandler } from '../../daemon/api/handlers/human.js';
|
|
31
17
|
import { apiSocketPath, nodeDir } from '../canvas/paths.js';
|
|
18
|
+
import { spawnNode } from '../runtime/nodes.js';
|
|
32
19
|
import { resolveRoot } from '../../build-root.js';
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
let home;
|
|
37
|
-
let stateHome; // XDG_STATE_HOME (humanloop root registry)
|
|
38
|
-
let root; // canonical registered interaction root, owner 'crouter'
|
|
20
|
+
import { validateDeck } from '../human/deck-schema.js';
|
|
21
|
+
import { ticketDir } from '../human/root.js';
|
|
22
|
+
import { readTicketResult, submitDeck } from '../human/tickets.js';
|
|
23
|
+
let home;
|
|
39
24
|
let priorHome;
|
|
40
|
-
// Since the crtrd-API re-plumb the producer + completion leaves are thin CLI
|
|
41
|
-
// forwarders: `ask`/`review` create their bridge node through
|
|
42
|
-
// `cliClient().createHumanBridge`, and `_deliver` forwards the completion event
|
|
43
|
-
// to crtrd, which owns the pushFinal/finalize delivery. Stand up a real
|
|
44
|
-
// in-process `createApiServer()` bound to the isolated CRTR_HOME's socket so the
|
|
45
|
-
// full leaf → client → server → handler path runs against the genuine seam —
|
|
46
|
-
// never an autostarted subprocess daemon, never a mock client.
|
|
47
25
|
let server;
|
|
48
26
|
async function waitForSocket(path) {
|
|
49
27
|
for (let i = 0; i < 200; i++) {
|
|
@@ -53,13 +31,6 @@ async function waitForSocket(path) {
|
|
|
53
31
|
}
|
|
54
32
|
throw new Error(`api socket never bound at ${path}`);
|
|
55
33
|
}
|
|
56
|
-
const ISO = '2026-07-10T12:00:00.000Z';
|
|
57
|
-
/** A benign direct-exec handler so humanloop's completion dispatch during the
|
|
58
|
-
* submit/cancel race is a fast no-op — the crouter delivery is exercised by
|
|
59
|
-
* calling `_deliver` in-process, not through this subprocess. */
|
|
60
|
-
function benignHandler() {
|
|
61
|
-
return { command: process.execPath, args: ['-e', ''] };
|
|
62
|
-
}
|
|
63
34
|
async function withPipedStdin(body, fn) {
|
|
64
35
|
const original = process.stdin;
|
|
65
36
|
const stdin = Readable.from([Buffer.from(body)]);
|
|
@@ -82,38 +53,22 @@ async function withMutedStdout(fn) {
|
|
|
82
53
|
process.stdout.write = originalWrite;
|
|
83
54
|
}
|
|
84
55
|
}
|
|
85
|
-
/** Register `dir` (created fresh) as an owner-'crouter' root and return its
|
|
86
|
-
* canonical path. */
|
|
87
|
-
function registerRoot(dir) {
|
|
88
|
-
return registerInboxRoot({ root: dir, owner: 'crouter', handler: benignHandler() }).root;
|
|
89
|
-
}
|
|
90
|
-
/** Create a subscribed parent + a terminal human bridge child; return both ids.
|
|
91
|
-
* The parent is auto-subscribed to the bridge at spawn, so a `pushFinal` from
|
|
92
|
-
* the bridge fans into the parent's inbox — the sole answer route. */
|
|
93
56
|
function bridgeUnder() {
|
|
94
57
|
const parent = spawnNode({ kind: 'general', parent: null, cwd: home, name: 'asker' }).node_id;
|
|
95
58
|
const bridge = spawnNode({ kind: 'human', parent, cwd: home, name: 'human-ask', lifecycle: 'terminal' }).node_id;
|
|
96
59
|
return { parent, bridge };
|
|
97
60
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
mkdirSync(dir, { recursive: true });
|
|
102
|
-
atomicWriteJson(join(dir, 'run.json'), { mode, ...(jobId !== undefined ? { job_id: jobId } : {}) });
|
|
103
|
-
return dir;
|
|
104
|
-
}
|
|
105
|
-
function completionEvent(dir, kind) {
|
|
106
|
-
return {
|
|
107
|
-
schema: 'humanloop.completion/v1',
|
|
108
|
-
root,
|
|
61
|
+
function submitBridgeDeck(bridge) {
|
|
62
|
+
const dir = ticketDir(bridge);
|
|
63
|
+
submitDeck({
|
|
109
64
|
dir,
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
};
|
|
65
|
+
deck: validateDeck({
|
|
66
|
+
title: 'Ship it?',
|
|
67
|
+
interactions: [{ id: 'question', title: 'Ship it?', subtitle: 'Decide whether to ship now so the release can proceed.', options: [], allowFreetext: true }],
|
|
68
|
+
}),
|
|
69
|
+
});
|
|
70
|
+
return dir;
|
|
115
71
|
}
|
|
116
|
-
/** Read the report body a subscriber inbox pointer references. */
|
|
117
72
|
function reportBody(ref) {
|
|
118
73
|
const resolved = resolveRef(ref);
|
|
119
74
|
if (resolved === null || resolved.source !== 'report')
|
|
@@ -126,18 +81,15 @@ before(() => {
|
|
|
126
81
|
beforeEach(async () => {
|
|
127
82
|
closeDb();
|
|
128
83
|
home = mkdtempSync(join(tmpdir(), 'crtr-deliver-home-'));
|
|
129
|
-
stateHome = mkdtempSync(join(tmpdir(), 'crtr-deliver-state-'));
|
|
130
|
-
const rootDir = mkdtempSync(join(tmpdir(), 'crtr-deliver-root-'));
|
|
131
84
|
process.env['CRTR_HOME'] = home;
|
|
132
85
|
process.env['HOME'] = home;
|
|
133
|
-
process.env['XDG_STATE_HOME'] = stateHome;
|
|
134
86
|
delete process.env['CRTR_NODE_ID'];
|
|
135
|
-
root = registerRoot(realpathSync(rootDir));
|
|
136
87
|
server = createApiServer();
|
|
137
88
|
await waitForSocket(apiSocketPath());
|
|
138
89
|
});
|
|
139
90
|
afterEach(async () => {
|
|
140
91
|
await server?.close();
|
|
92
|
+
rmSync(home, { recursive: true, force: true });
|
|
141
93
|
});
|
|
142
94
|
after(() => {
|
|
143
95
|
closeDb();
|
|
@@ -146,314 +98,88 @@ after(() => {
|
|
|
146
98
|
else
|
|
147
99
|
delete process.env['HOME'];
|
|
148
100
|
delete process.env['CRTR_HOME'];
|
|
149
|
-
delete process.env['XDG_STATE_HOME'];
|
|
150
101
|
delete process.env['CRTR_NODE_ID'];
|
|
151
102
|
});
|
|
152
|
-
// ---------------------------------------------------------------------------
|
|
153
|
-
// (a) ask/review enqueue immediately — no pane/pid; run.json captures fork provenance
|
|
154
|
-
// ---------------------------------------------------------------------------
|
|
155
|
-
test('Visual handler trusts sealed sibling runtime generations across a daemon roll', () => {
|
|
156
|
-
const currentGeneration = 'a'.repeat(64);
|
|
157
|
-
const retainedGeneration = 'b'.repeat(64);
|
|
158
|
-
const current = {
|
|
159
|
-
command: '/home/.crouter/host/crouter',
|
|
160
|
-
args: [`/home/.crouter/runtime/generations/${currentGeneration}/dist/cli.js`, 'human', '_visual'],
|
|
161
|
-
};
|
|
162
|
-
const retained = {
|
|
163
|
-
command: '/opt/bin/node',
|
|
164
|
-
args: [`/home/.crouter/runtime/generations/${retainedGeneration}/dist/cli.js`, 'human', '_visual'],
|
|
165
|
-
};
|
|
166
|
-
assert.equal(trustedCrouterVisualHandler(retained, current), true);
|
|
167
|
-
assert.equal(trustedCrouterVisualHandler({ ...retained, command: '/tmp/python' }, current), false);
|
|
168
|
-
assert.equal(trustedCrouterVisualHandler({ ...retained, args: ['/tmp/cli.js', 'human', '_visual'] }, current), false);
|
|
169
|
-
assert.equal(trustedCrouterVisualHandler({ ...retained, args: [retained.args[0], 'human', '_deliver'] }, current), false);
|
|
170
|
-
});
|
|
171
103
|
describe('enqueue is producer-only', () => {
|
|
172
104
|
test('ask requires and preserves an explicit title instead of deriving one from the body', async () => {
|
|
173
105
|
const parent = spawnNode({ kind: 'general', parent: null, cwd: home, name: 'asker' }).node_id;
|
|
174
106
|
process.env['CRTR_NODE_ID'] = parent;
|
|
175
107
|
await assert.rejects(() => humanAsk.run({ question: 'This first line must never become the title.' }), /require a non-empty --title/);
|
|
176
|
-
const
|
|
177
|
-
assert.equal(typeof
|
|
178
|
-
assert.equal(typeof
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
}
|
|
183
|
-
const deck = JSON.parse(readFileSync(join(r['dir'], 'deck.json'), 'utf8'));
|
|
108
|
+
const result = (await humanAsk.run({ title: 'Release decision', subtitle: 'Decide whether to release now so the launch can proceed.', question: 'This first line must never become the title.' }));
|
|
109
|
+
assert.equal(typeof result['job_id'], 'string');
|
|
110
|
+
assert.equal(typeof result['dir'], 'string');
|
|
111
|
+
for (const forbidden of ['pane_id', 'render_pane_id', 'pid', 'worker_pid'])
|
|
112
|
+
assert.ok(!(forbidden in result), `ask result must not expose ${forbidden}`);
|
|
113
|
+
const deck = JSON.parse(readFileSync(join(result['dir'], 'deck.json'), 'utf8'));
|
|
184
114
|
assert.equal(deck.title, 'Release decision');
|
|
185
115
|
assert.equal(deck.interactions[0]?.title, 'Release decision');
|
|
186
116
|
assert.equal(deck.interactions[0]?.subtitle, 'Decide whether to release now so the launch can proceed.');
|
|
187
117
|
assert.equal(deck.interactions[0]?.body, 'This first line must never become the title.');
|
|
188
118
|
assert.equal(deck.interactions[0]?.kind, 'decision');
|
|
189
|
-
const
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
],
|
|
196
|
-
},
|
|
197
|
-
}));
|
|
198
|
-
const structuredDeck = JSON.parse(readFileSync(join(structured['dir'], 'deck.json'), 'utf8'));
|
|
199
|
-
assert.deepEqual(structuredDeck.interactions.map((interaction) => interaction.kind), ['decision', 'context']);
|
|
200
|
-
const deckDir = mkdtempSync(join(tmpdir(), 'crtr-context-file-deck-'));
|
|
201
|
-
assert.notEqual(resolve(process.cwd()), deckDir, 'the CLI caller cwd must differ from the deck directory');
|
|
202
|
-
const deckPath = join(deckDir, 'deck.json');
|
|
203
|
-
writeFileSync(join(deckDir, 'body.md'), 'The body came from beside the deck JSON.');
|
|
204
|
-
writeFileSync(deckPath, JSON.stringify({
|
|
205
|
-
title: 'Context file body',
|
|
206
|
-
interactions: [{
|
|
207
|
-
id: 'decision',
|
|
208
|
-
title: 'Use the deck',
|
|
209
|
-
subtitle: 'Use the deck body so the person can decide with its context.',
|
|
210
|
-
bodyPath: 'body.md',
|
|
211
|
-
options: [{ id: 'yes', label: 'Yes' }],
|
|
212
|
-
}],
|
|
213
|
-
}));
|
|
214
|
-
const nodesBeforeContextFile = new Set(listNodes().map((node) => node.node_id));
|
|
119
|
+
const deckDirectory = mkdtempSync(join(tmpdir(), 'crtr-context-file-deck-'));
|
|
120
|
+
assert.notEqual(resolve(process.cwd()), deckDirectory, 'the CLI caller cwd must differ from the deck directory');
|
|
121
|
+
const deckPath = join(deckDirectory, 'deck.json');
|
|
122
|
+
writeFileSync(join(deckDirectory, 'body.md'), 'The body came from beside the deck JSON.');
|
|
123
|
+
writeFileSync(deckPath, JSON.stringify({ title: 'Context file body', interactions: [{ id: 'decision', title: 'Use the deck', subtitle: 'Use the deck body so the person can decide with its context.', bodyPath: 'body.md', options: [{ id: 'yes', label: 'Yes' }] }] }));
|
|
124
|
+
const nodesBefore = new Set(listNodes().map((node) => node.node_id));
|
|
215
125
|
await withMutedStdout(() => withPipedStdin('', async () => {
|
|
216
126
|
await runCli(await resolveRoot('human'), ['node', 'crtr', 'human', 'ask', '--context-file', deckPath]);
|
|
217
127
|
}));
|
|
218
|
-
const
|
|
219
|
-
assert.ok(
|
|
220
|
-
const
|
|
221
|
-
assert.equal(
|
|
222
|
-
assert.equal(
|
|
223
|
-
await assert.rejects(() => humanAsk.run({
|
|
224
|
-
deck: {
|
|
225
|
-
title: 'Absolute path',
|
|
226
|
-
interactions: [{
|
|
227
|
-
id: 'decision',
|
|
228
|
-
title: 'Reject absolute path',
|
|
229
|
-
subtitle: 'Reject the invalid path so the documented deck boundary remains intact.',
|
|
230
|
-
bodyPath: join(deckDir, 'body.md'),
|
|
231
|
-
options: [{ id: 'yes', label: 'Yes' }],
|
|
232
|
-
}],
|
|
233
|
-
},
|
|
234
|
-
}, { providedParams: new Set(['deck']), contextFilePaths: new Map([['deck', deckPath]]) }), /absolute paths are unsupported/);
|
|
235
|
-
const rc = JSON.parse(readFileSync(join(r['dir'], 'run.json'), 'utf8'));
|
|
236
|
-
assert.equal(rc['mode'], 'ask');
|
|
237
|
-
assert.equal(rc['job_id'], r['job_id']);
|
|
238
|
-
assert.deepEqual(rc['conversation_fork'] && {
|
|
239
|
-
status: rc['conversation_fork']['status'],
|
|
240
|
-
reason: rc['conversation_fork']['reason'],
|
|
241
|
-
}, { status: 'unavailable', reason: 'broker_unavailable' });
|
|
242
|
-
const bridge = getNode(r['job_id']);
|
|
243
|
-
assert.equal(bridge?.kind, 'human');
|
|
244
|
-
assert.equal(bridge?.parent, parent);
|
|
245
|
-
});
|
|
246
|
-
test('review returns immediately and writes run.json = {mode:review, job_id}', async () => {
|
|
247
|
-
const parent = spawnNode({ kind: 'general', parent: null, cwd: home, name: 'asker' }).node_id;
|
|
248
|
-
process.env['CRTR_NODE_ID'] = parent;
|
|
249
|
-
const md = join(home, 'plan.md');
|
|
250
|
-
writeFileSync(md, '# Plan\n\nline\n');
|
|
251
|
-
const r = (await humanReview.run({ file: md, subtitle: 'Review this plan so implementation can begin safely.' }));
|
|
252
|
-
assert.equal(typeof r['job_id'], 'string');
|
|
253
|
-
assert.ok(!('pane_id' in r) && !('render_pane_id' in r), 'no pane fields');
|
|
254
|
-
const rc = JSON.parse(readFileSync(join(r['dir'], 'run.json'), 'utf8'));
|
|
255
|
-
assert.deepEqual(rc, { mode: 'review', job_id: r['job_id'] });
|
|
128
|
+
const bridge = listNodes().find((node) => !nodesBefore.has(node.node_id));
|
|
129
|
+
assert.ok(bridge, 'the real CLI invocation created a human bridge');
|
|
130
|
+
const contextDeck = JSON.parse(readFileSync(join(nodeDir(bridge.node_id), 'deck.json'), 'utf8'));
|
|
131
|
+
assert.equal(contextDeck.interactions[0]?.body, 'The body came from beside the deck JSON.');
|
|
132
|
+
assert.equal(contextDeck.interactions[0]?.bodyPath, undefined);
|
|
256
133
|
});
|
|
257
134
|
});
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
// ---------------------------------------------------------------------------
|
|
261
|
-
describe('_deliver: deck', () => {
|
|
262
|
-
test('pushFinals the readable answer once and wakes the subscribed parent', async () => {
|
|
135
|
+
describe('terminal ticket delivery', () => {
|
|
136
|
+
test('resolveDeckTicket pushFinals the readable answer once and wakes the subscribed parent', async () => {
|
|
263
137
|
const { parent, bridge } = bridgeUnder();
|
|
264
|
-
const dir =
|
|
265
|
-
const
|
|
266
|
-
|
|
267
|
-
kind: 'deck',
|
|
268
|
-
responses: [{ id: 'question', freetext: 'yes, ship' }],
|
|
269
|
-
summary: 'Ship it?: yes, ship',
|
|
270
|
-
completedAt: ISO,
|
|
271
|
-
};
|
|
272
|
-
writeFileSync(join(dir, 'response.json'), JSON.stringify(deckResult));
|
|
273
|
-
const out = (await humanDeliver.run({ body: JSON.stringify(completionEvent(dir, 'deck')) }));
|
|
274
|
-
assert.equal(out.delivered, true);
|
|
275
|
-
// Bridge finalized.
|
|
138
|
+
const dir = submitBridgeDeck(bridge);
|
|
139
|
+
const result = await resolveDeckTicket(bridge, [{ id: 'question', freetext: 'yes, ship' }]);
|
|
140
|
+
assert.equal(result.kind, 'deck');
|
|
276
141
|
closeDb();
|
|
277
142
|
assert.equal(getNode(bridge)?.status, 'done');
|
|
278
|
-
|
|
279
|
-
// the summary, not a serialized envelope — plus the metadata path.
|
|
280
|
-
const finals = readInboxSince(parent).filter((e) => e.from === bridge && e.kind === 'final');
|
|
143
|
+
const finals = readInboxSince(parent).filter((entry) => entry.from === bridge && entry.kind === 'final');
|
|
281
144
|
assert.equal(finals.length, 1, 'exactly one pushFinal reached the parent');
|
|
282
145
|
const body = reportBody(finals[0].ref);
|
|
283
|
-
assert.equal(body.split('\n')[0],
|
|
284
|
-
assert.ok(body.includes(join(dir, 'response.json'))
|
|
285
|
-
assert.ok(!body.includes('humanloop.response/v2')
|
|
146
|
+
assert.equal(body.split('\n')[0], 'Ship it?: yes, ship');
|
|
147
|
+
assert.ok(body.includes(join(dir, 'response.json')));
|
|
148
|
+
assert.ok(!body.includes('humanloop.response/v2'));
|
|
286
149
|
});
|
|
287
|
-
|
|
288
|
-
test('a second _deliver is idempotent — no second push, still delivered', async () => {
|
|
150
|
+
test('a replay against a terminal bridge is a no-op', async () => {
|
|
289
151
|
const { parent, bridge } = bridgeUnder();
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
await humanDeliver.run({ body: ev });
|
|
294
|
-
const replay = (await humanDeliver.run({ body: ev }));
|
|
295
|
-
assert.equal(replay.delivered, true);
|
|
152
|
+
submitBridgeDeck(bridge);
|
|
153
|
+
await resolveDeckTicket(bridge, [{ id: 'question', freetext: 'yes' }]);
|
|
154
|
+
assert.equal(await deliverTerminalResult(bridge), true);
|
|
296
155
|
closeDb();
|
|
297
|
-
const finals = readInboxSince(parent).filter((
|
|
156
|
+
const finals = readInboxSince(parent).filter((entry) => entry.from === bridge && entry.kind === 'final');
|
|
298
157
|
assert.equal(finals.length, 1, 'replay after a terminal bridge pushes nothing further');
|
|
299
158
|
});
|
|
300
|
-
|
|
301
|
-
// ---------------------------------------------------------------------------
|
|
302
|
-
// (d) review _deliver: delivered == readable anchored comments + record path
|
|
303
|
-
// ---------------------------------------------------------------------------
|
|
304
|
-
describe('_deliver: review', () => {
|
|
305
|
-
test('pushes readable anchored comments plus the feedback-record path', async () => {
|
|
306
|
-
const { parent, bridge } = bridgeUnder();
|
|
307
|
-
const dir = seedTicket(bridge, 'review', bridge);
|
|
308
|
-
const md = realpathSync(home) + '/spec.md';
|
|
309
|
-
writeFileSync(md, '# spec\n');
|
|
310
|
-
const feedback = {
|
|
311
|
-
file: md,
|
|
312
|
-
submitted: true,
|
|
313
|
-
approved: false,
|
|
314
|
-
comments: [{ id: 'c1', line: 1, endLine: 1, lineText: '# spec', comment: 'tighten', createdAt: ISO }],
|
|
315
|
-
submittedAt: ISO,
|
|
316
|
-
savedAt: ISO,
|
|
317
|
-
};
|
|
318
|
-
writeFileSync(join(dir, 'response.json'), JSON.stringify({ schema: 'humanloop.review-response/v1', kind: 'review', result: feedback, completedAt: ISO }));
|
|
319
|
-
// The output projection humanloop writes: the bare FeedbackResult.
|
|
320
|
-
const projection = join(dir, 'feedback.json');
|
|
321
|
-
writeFileSync(projection, JSON.stringify(feedback));
|
|
322
|
-
const out = (await humanDeliver.run({ body: JSON.stringify(completionEvent(dir, 'review')) }));
|
|
323
|
-
assert.equal(out.delivered, true);
|
|
324
|
-
closeDb();
|
|
325
|
-
const finals = readInboxSince(parent).filter((e) => e.from === bridge && e.kind === 'final');
|
|
326
|
-
assert.equal(finals.length, 1);
|
|
327
|
-
const delivered = reportBody(finals[0].ref);
|
|
328
|
-
assert.ok(delivered.includes('1 comment on ' + md), 'the comment count and file lead the report');
|
|
329
|
-
assert.ok(delivered.includes('tighten'), 'the human\'s comment text is inline');
|
|
330
|
-
assert.ok(delivered.includes(join(dir, 'response.json')), 'the full feedback record is one path away');
|
|
331
|
-
assert.ok(!delivered.includes('"savedAt"'), 'no serialized FeedbackResult is inlined');
|
|
332
|
-
assert.deepEqual(JSON.parse(readFileSync(projection, 'utf8')), feedback, 'the output projection file is untouched');
|
|
333
|
-
});
|
|
334
|
-
});
|
|
335
|
-
// ---------------------------------------------------------------------------
|
|
336
|
-
// (e) canceled _deliver: bridge finalized, deferred note skips the actor
|
|
337
|
-
// ---------------------------------------------------------------------------
|
|
338
|
-
describe('_deliver: canceled', () => {
|
|
339
|
-
test('finalizes the bridge and sends a deferred no-answer note to non-actor subscribers only', async () => {
|
|
340
|
-
// Two subscribers: the actor (who canceled) and another waiter.
|
|
159
|
+
test('cancelHumanTicket finishes the bridge and notifies non-actor subscribers', async () => {
|
|
341
160
|
const actor = spawnNode({ kind: 'general', parent: null, cwd: home, name: 'actor' }).node_id;
|
|
342
161
|
const bridge = spawnNode({ kind: 'human', parent: actor, cwd: home, name: 'human-ask', lifecycle: 'terminal' }).node_id;
|
|
343
162
|
const other = spawnNode({ kind: 'general', parent: null, cwd: home, name: 'other' }).node_id;
|
|
344
|
-
// `other` also subscribes to the bridge.
|
|
345
163
|
const { subscribe } = await import('../canvas/canvas.js');
|
|
346
164
|
subscribe(other, bridge, true);
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
const out = (await humanDeliver.run({ body: JSON.stringify(completionEvent(dir, 'canceled')) }));
|
|
350
|
-
assert.equal(out.delivered, true);
|
|
351
|
-
closeDb();
|
|
352
|
-
assert.equal(getNode(bridge)?.status, 'done', 'canceled bridge finalized');
|
|
353
|
-
// Actor (who canceled) gets no note; the other waiter does.
|
|
354
|
-
assert.equal(readInboxSince(actor).length, 0, 'the cancelling actor is not messaged');
|
|
355
|
-
const otherNotes = readInboxSince(other);
|
|
356
|
-
assert.equal(otherNotes.length, 1, 'the other waiter gets one deferred note');
|
|
357
|
-
assert.equal(otherNotes[0].tier, 'deferred');
|
|
358
|
-
assert.match(otherNotes[0].label, /canceled/);
|
|
359
|
-
});
|
|
360
|
-
});
|
|
361
|
-
// ---------------------------------------------------------------------------
|
|
362
|
-
// (e2) REGRESSION (Unit X DEFECT F) — a completion event whose root/dir carry an
|
|
363
|
-
// UNRESOLVED symlinked path component still delivers.
|
|
364
|
-
//
|
|
365
|
-
// Humanloop's registry stores every root realpath-canonicalized, but its
|
|
366
|
-
// `dispatchCompletion` only `resolve()`s the dir into the event (not realpath),
|
|
367
|
-
// and crouter's own `human cancel` hands `cancelTicket` a CRTR_HOME-derived dir
|
|
368
|
-
// that is likewise not realpath'd. On any host whose interaction path has a
|
|
369
|
-
// symlinked component (macOS `/tmp`→`/private/tmp`, `/var`→`/private/var`) the
|
|
370
|
-
// event thus carries `/tmp/…` while the registry holds `/private/tmp/…`. Before
|
|
371
|
-
// the fix, `_deliver` compared those with a plain `resolve()` and spuriously
|
|
372
|
-
// threw `interaction dir is not a direct child of the event root` (exit 2) →
|
|
373
|
-
// humanloop wrote delivery-error.json and NO delivery.json, and the cancel
|
|
374
|
-
// completion was never acknowledged. The deck-SUBMIT path dodged this only
|
|
375
|
-
// because the controller's dir already comes from scanning the realpath'd root.
|
|
376
|
-
// `_deliver` now realpath-canonicalizes both sides, so any caller's event
|
|
377
|
-
// delivers regardless of symlinked components.
|
|
378
|
-
// ---------------------------------------------------------------------------
|
|
379
|
-
describe('_deliver: symlinked event paths (DEFECT F regression)', () => {
|
|
380
|
-
test('delivers a canceled completion whose root/dir carry an unresolved symlink', async () => {
|
|
381
|
-
// A symlink whose target is the registered root's PARENT, so `symRoot`
|
|
382
|
-
// realpath-resolves to the registered (realpath'd) `root` but is a distinct
|
|
383
|
-
// string with an unresolved symlink component — exactly humanloop's event shape.
|
|
384
|
-
const linkParent = mkdtempSync(join(tmpdir(), 'crtr-deliver-link-'));
|
|
385
|
-
const link = join(linkParent, 'lnk');
|
|
386
|
-
symlinkSync(dirname(root), link);
|
|
387
|
-
const symRoot = join(link, basename(root));
|
|
388
|
-
assert.notEqual(symRoot, root, 'symRoot is a distinct string');
|
|
389
|
-
assert.equal(realpathSync(symRoot), root, 'but realpath-resolves to the registered root');
|
|
390
|
-
const actor = spawnNode({ kind: 'general', parent: null, cwd: home, name: 'actor' }).node_id;
|
|
391
|
-
const bridge = spawnNode({ kind: 'human', parent: actor, cwd: home, name: 'human-ask', lifecycle: 'terminal' }).node_id;
|
|
392
|
-
const dir = seedTicket(bridge, 'ask', bridge); // real (realpath'd) dir on disk
|
|
393
|
-
writeFileSync(join(dir, 'response.json'), JSON.stringify({ schema: 'humanloop.cancel/v1', kind: 'canceled', canceledAt: ISO, actor }));
|
|
394
|
-
// The event carries the SYMLINKED root/dir/responsePath (non-realpath), the
|
|
395
|
-
// way dispatchCompletion + `human cancel` build it on a symlinked host.
|
|
396
|
-
const symDir = join(symRoot, bridge);
|
|
397
|
-
const event = {
|
|
398
|
-
schema: 'humanloop.completion/v1',
|
|
399
|
-
root: symRoot,
|
|
400
|
-
dir: symDir,
|
|
401
|
-
ticketId: bridge,
|
|
402
|
-
kind: 'canceled',
|
|
403
|
-
outcome: 'canceled',
|
|
404
|
-
responsePath: join(symDir, 'response.json'),
|
|
405
|
-
};
|
|
406
|
-
const out = (await humanDeliver.run({ body: JSON.stringify(event) }));
|
|
407
|
-
assert.equal(out.delivered, true, 'the cancel completion delivers (no exit-2 rejection)');
|
|
408
|
-
closeDb();
|
|
409
|
-
assert.equal(getNode(bridge)?.status, 'done', 'the bridge is finalized exactly once');
|
|
410
|
-
assert.equal(readInboxSince(actor).length, 0, 'the cancelling actor is not messaged');
|
|
411
|
-
});
|
|
412
|
-
});
|
|
413
|
-
// ---------------------------------------------------------------------------
|
|
414
|
-
// (f) submit/cancel race via humanloop primitives → one outcome; crouter converges
|
|
415
|
-
// ---------------------------------------------------------------------------
|
|
416
|
-
describe('submit/cancel race', () => {
|
|
417
|
-
test('one canonical outcome wins and _deliver converges the bridge to a single terminal state', async () => {
|
|
418
|
-
const { bridge } = bridgeUnder();
|
|
419
|
-
const dir = join(root, bridge);
|
|
420
|
-
mkdirSync(dir, { recursive: true });
|
|
421
|
-
atomicWriteJson(join(dir, 'run.json'), { mode: 'ask', job_id: bridge });
|
|
422
|
-
const deck = validateDeck({ title: 'Go?', interactions: [{ id: 'q', title: 'Go?', subtitle: 'Decide whether to proceed so the work can continue.', options: [], allowFreetext: true }] });
|
|
423
|
-
submitDeck({ root, id: bridge, deck });
|
|
424
|
-
const claim = claimTicket(dir);
|
|
425
|
-
assert.ok(claim !== null, 'claimed the fresh ticket');
|
|
426
|
-
// Race an answer against a cancellation on the same exclusive publish.
|
|
427
|
-
const [completed, canceled] = await Promise.allSettled([
|
|
428
|
-
completeDeck(dir, [{ id: 'q', freetext: 'go' }], claim.token),
|
|
429
|
-
cancelTicket(dir, { reason: 'changed mind', actor: 'someone' }),
|
|
430
|
-
]);
|
|
431
|
-
// Exactly one canonical final marker exists on disk.
|
|
432
|
-
const result = readTicketResult(dir);
|
|
433
|
-
assert.ok(result !== null, 'a single canonical response.json won');
|
|
434
|
-
assert.ok(result.kind === 'deck' || result.kind === 'canceled');
|
|
435
|
-
// Whatever won, at most one side reports a win.
|
|
436
|
-
const wonDeck = completed.status === 'fulfilled' && completed.value.won === true;
|
|
437
|
-
const wonCancel = canceled.status === 'fulfilled' && canceled.value.status === 'canceled';
|
|
438
|
-
assert.ok(!(wonDeck && wonCancel), 'submit and cancel cannot both win');
|
|
439
|
-
// Feed the winning outcome to crouter; the bridge reaches exactly one terminal state.
|
|
440
|
-
const out = (await humanDeliver.run({ body: JSON.stringify(completionEvent(dir, result.kind)) }));
|
|
441
|
-
assert.equal(out.delivered, true);
|
|
165
|
+
submitBridgeDeck(bridge);
|
|
166
|
+
await cancelHumanTicket(bridge, { reason: 'stale', actor });
|
|
442
167
|
closeDb();
|
|
443
|
-
assert.equal(getNode(bridge)?.status, 'done'
|
|
168
|
+
assert.equal(getNode(bridge)?.status, 'done');
|
|
169
|
+
assert.equal(readInboxSince(actor).length, 0, 'the canceling actor is not messaged');
|
|
170
|
+
const notes = readInboxSince(other);
|
|
171
|
+
assert.equal(notes.length, 1, 'the other waiter gets one deferred note');
|
|
172
|
+
assert.equal(notes[0].tier, 'deferred');
|
|
173
|
+
assert.match(notes[0].label, /canceled/);
|
|
444
174
|
});
|
|
445
175
|
});
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
assert.ok(existsSync(join(r['dir'], 'deck.json')), 'notify wrote a durable deck');
|
|
456
|
-
closeDb();
|
|
457
|
-
assert.equal(listNodes().length, before, 'notify created no node');
|
|
458
|
-
});
|
|
176
|
+
test('notify enqueues a durable deck and creates no canvas node', async () => {
|
|
177
|
+
const before = listNodes().length;
|
|
178
|
+
const result = (await humanNotify.run({ title: 'Build done', subtitle: 'The build passed, so the change is ready to review.' }));
|
|
179
|
+
assert.equal(result['queued'], true);
|
|
180
|
+
assert.equal(typeof result['dir'], 'string');
|
|
181
|
+
assert.ok(existsSync(join(result['dir'], 'deck.json')));
|
|
182
|
+
assert.ok(readTicketResult(result['dir']) === null);
|
|
183
|
+
closeDb();
|
|
184
|
+
assert.equal(listNodes().length, before);
|
|
459
185
|
});
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
// Load-bearing shared-contract regression for the inline memory-reference
|
|
4
4
|
// token grammar (spec §4.1): `src/core/memory/inline-ref-grammar.ts` is the
|
|
5
5
|
// SINGLE implementation the broker, terminal attach viewer, and web composer
|
|
6
|
-
// all consume. This file (Wave C1) covers the grammar/caret
|
|
7
|
-
//
|
|
6
|
+
// all consume. This file (Wave C1) covers the grammar/caret cases. Wave C4
|
|
7
|
+
// extends it (below, in its own `describe`) with the
|
|
8
8
|
// corpus/inventory/guidance cases: `buildRefInventory`'s precedence dedup,
|
|
9
9
|
// both-kinds/gated/slash:false referenceability, INDEX naming, and
|
|
10
10
|
// metadata-only output, plus `buildGuidance`'s exact-match resolution,
|
|
@@ -113,16 +113,6 @@ test('findRefTokenAtCaret: caret at start of a leading token', () => {
|
|
|
113
113
|
const caret = findRefTokenAtCaret(text, 1); // right after the slash
|
|
114
114
|
assert.deepEqual(caret, { start: 0, end: 4, surfacePrefix: '/' });
|
|
115
115
|
});
|
|
116
|
-
test('browser barrel (src/web/index.ts) re-exports the identical grammar', async () => {
|
|
117
|
-
const barrel = await import('../../web/index.js');
|
|
118
|
-
assert.equal(barrel.findRefTokens, findRefTokens, 'must be the same function, not a mirrored copy');
|
|
119
|
-
assert.equal(barrel.formatRefToken, formatRefToken);
|
|
120
|
-
assert.equal(barrel.findRefTokenAtCaret, findRefTokenAtCaret);
|
|
121
|
-
// And it behaves identically when driven through the barrel.
|
|
122
|
-
const [tok] = barrel.findRefTokens('read /dev before starting');
|
|
123
|
-
assert.equal(tok.candidate, 'dev');
|
|
124
|
-
assert.equal(barrel.formatRefToken('taste/foo'), '/taste:foo');
|
|
125
|
-
});
|
|
126
116
|
// ---------------------------------------------------------------------------
|
|
127
117
|
// Wave C4 — buildGuidance: pure over (text, names), no filesystem/corpus
|
|
128
118
|
// involved. See the fixture-backed buildRefInventory suite below for the
|
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
// Regression matrix for `resolveMemoryDoc`'s precedence rule:
|
|
2
|
-
// are
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
// a nearer
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
// frontmatter `name` had since diverged from the physical filename).
|
|
1
|
+
// Regression matrix for `resolveMemoryDoc`'s precedence rule: exact identity
|
|
2
|
+
// and direct physical-path matches are resolved NEAREST-FIRST across the whole
|
|
3
|
+
// scope stack before bare-leaf fallback is considered. This prevents a nested
|
|
4
|
+
// doc's coincidental leaf from hiding a farther canonical identity while still
|
|
5
|
+
// ensuring a nearer worktree's own physical `AGENTS.md` beats a farther doc
|
|
6
|
+
// named exactly `AGENTS`, even when the nearer file's explicit frontmatter
|
|
7
|
+
// identity has diverged from its physical filename.
|
|
9
8
|
//
|
|
10
9
|
// Fixture shape: two nested project scopes on disk —
|
|
11
10
|
// root/.crouter/memory/... (farther project scope)
|
|
@@ -149,19 +148,17 @@ test('--kind skips a nearer wrong-kind (frontmatter-less, kind-defaulted) doc an
|
|
|
149
148
|
process.chdir(prevCwd);
|
|
150
149
|
}
|
|
151
150
|
});
|
|
152
|
-
test('
|
|
151
|
+
test('an exact identity match beats a nearer document reached only by leaf fallback', () => {
|
|
153
152
|
process.chdir(child);
|
|
154
153
|
resetScopeCache();
|
|
155
154
|
try {
|
|
156
155
|
// Nearest scope's doc lives at "sub/shared.md" (derived name "sub/shared",
|
|
157
156
|
// leaf "shared"); the farther scope's doc lives at top-level "shared.md"
|
|
158
|
-
// (derived name "shared", an
|
|
159
|
-
// Precedence-as-outer-loop means the nearer source's mere leaf-fallback
|
|
160
|
-
// hit must still beat the farther source's exact identity hit.
|
|
157
|
+
// (derived name "shared", an exact identity match for the bare query).
|
|
161
158
|
const doc = resolveMemoryDoc('shared');
|
|
162
|
-
assert.equal(doc.path, join(
|
|
163
|
-
assert.equal(doc.name, '
|
|
164
|
-
assert.match(doc.body, /
|
|
159
|
+
assert.equal(doc.path, join(root, '.crouter', 'memory', 'shared.md'));
|
|
160
|
+
assert.equal(doc.name, 'shared');
|
|
161
|
+
assert.match(doc.body, /ROOT SHARED BODY/);
|
|
165
162
|
}
|
|
166
163
|
finally {
|
|
167
164
|
process.chdir(prevCwd);
|
|
@@ -18,6 +18,12 @@ const PRE_TOOL_GUIDE_CANVAS_EXTENSION_NAMES = [
|
|
|
18
18
|
'canvas-goal-capture', 'canvas-passive-context', 'canvas-context-intro',
|
|
19
19
|
'canvas-doc-substrate', 'canvas-structured-output', 'canvas-bash-valve',
|
|
20
20
|
];
|
|
21
|
+
const REVIEW_BOUNDARY_CANVAS_EXTENSION_NAMES = [
|
|
22
|
+
'canvas-inbox-watcher', 'canvas-stophook', 'canvas-recap',
|
|
23
|
+
'canvas-goal-capture', 'canvas-passive-context', 'canvas-review-boundary',
|
|
24
|
+
'canvas-context-intro', 'canvas-tool-guide', 'canvas-doc-substrate',
|
|
25
|
+
'canvas-structured-output', 'canvas-bash-valve',
|
|
26
|
+
];
|
|
21
27
|
let home;
|
|
22
28
|
async function waitForPath(path) {
|
|
23
29
|
for (;;) {
|
|
@@ -74,6 +80,10 @@ test('opening a fresh home migrates to the latest user_version', () => {
|
|
|
74
80
|
const db = openDb();
|
|
75
81
|
assert.equal(userVersion(db), MIGRATIONS.length);
|
|
76
82
|
});
|
|
83
|
+
test('a persisted review-boundary canvas prefix is not treated as custom extensions', () => {
|
|
84
|
+
const persisted = REVIEW_BOUNDARY_CANVAS_EXTENSION_NAMES.map((name) => `/old-generation/pi-extensions/${name}.js`);
|
|
85
|
+
assert.deepEqual(customExtensionPaths(persisted), []);
|
|
86
|
+
});
|
|
77
87
|
test('a v14 canvas normalizes historical canvas paths while retaining custom launch extras', () => {
|
|
78
88
|
const metaPath = join(home, 'nodes', 'saved', 'meta.json');
|
|
79
89
|
mkdirSync(join(home, 'nodes', 'saved'), { recursive: true });
|