@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
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { Deck, ReviewDescriptor } from './types.js';
|
|
3
|
+
export declare const interactionOptionSchema: z.ZodObject<{
|
|
4
|
+
id: z.ZodString;
|
|
5
|
+
label: z.ZodString;
|
|
6
|
+
description: z.ZodOptional<z.ZodString>;
|
|
7
|
+
}, z.core.$strip>;
|
|
8
|
+
export declare const preAnswerSchema: z.ZodObject<{
|
|
9
|
+
selectedOptionId: z.ZodOptional<z.ZodString>;
|
|
10
|
+
selectedOptionIds: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
11
|
+
freetext: z.ZodOptional<z.ZodString>;
|
|
12
|
+
label: z.ZodOptional<z.ZodString>;
|
|
13
|
+
}, z.core.$strip>;
|
|
14
|
+
export declare const deckSchema: z.ZodObject<{
|
|
15
|
+
title: z.ZodString;
|
|
16
|
+
source: z.ZodOptional<z.ZodObject<{
|
|
17
|
+
sessionName: z.ZodOptional<z.ZodString>;
|
|
18
|
+
askedBy: z.ZodOptional<z.ZodString>;
|
|
19
|
+
blockedSince: z.ZodOptional<z.ZodString>;
|
|
20
|
+
nodeId: z.ZodOptional<z.ZodString>;
|
|
21
|
+
}, z.core.$strip>>;
|
|
22
|
+
interactions: z.ZodArray<z.ZodObject<{
|
|
23
|
+
id: z.ZodString;
|
|
24
|
+
title: z.ZodString;
|
|
25
|
+
subtitle: z.ZodString;
|
|
26
|
+
body: z.ZodOptional<z.ZodString>;
|
|
27
|
+
bodyPath: z.ZodOptional<z.ZodString>;
|
|
28
|
+
options: z.ZodArray<z.ZodObject<{
|
|
29
|
+
id: z.ZodString;
|
|
30
|
+
label: z.ZodString;
|
|
31
|
+
description: z.ZodOptional<z.ZodString>;
|
|
32
|
+
}, z.core.$strip>>;
|
|
33
|
+
multiSelect: z.ZodOptional<z.ZodBoolean>;
|
|
34
|
+
allowFreetext: z.ZodOptional<z.ZodBoolean>;
|
|
35
|
+
freetextLabel: z.ZodOptional<z.ZodString>;
|
|
36
|
+
kind: z.ZodOptional<z.ZodEnum<{
|
|
37
|
+
error: "error";
|
|
38
|
+
context: "context";
|
|
39
|
+
notify: "notify";
|
|
40
|
+
review: "review";
|
|
41
|
+
decision: "decision";
|
|
42
|
+
}>>;
|
|
43
|
+
preAnswered: z.ZodOptional<z.ZodObject<{
|
|
44
|
+
selectedOptionId: z.ZodOptional<z.ZodString>;
|
|
45
|
+
selectedOptionIds: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
46
|
+
freetext: z.ZodOptional<z.ZodString>;
|
|
47
|
+
label: z.ZodOptional<z.ZodString>;
|
|
48
|
+
}, z.core.$strip>>;
|
|
49
|
+
}, z.core.$strip>>;
|
|
50
|
+
}, z.core.$strip>;
|
|
51
|
+
export declare const reviewDescriptorSchema: z.ZodObject<{
|
|
52
|
+
schema: z.ZodLiteral<"humanloop.review/v1">;
|
|
53
|
+
file: z.ZodString;
|
|
54
|
+
output: z.ZodString;
|
|
55
|
+
title: z.ZodString;
|
|
56
|
+
subtitle: z.ZodString;
|
|
57
|
+
source: z.ZodObject<{
|
|
58
|
+
sessionName: z.ZodOptional<z.ZodString>;
|
|
59
|
+
askedBy: z.ZodOptional<z.ZodString>;
|
|
60
|
+
blockedSince: z.ZodOptional<z.ZodString>;
|
|
61
|
+
nodeId: z.ZodOptional<z.ZodString>;
|
|
62
|
+
}, z.core.$strip>;
|
|
63
|
+
blockedSince: z.ZodString;
|
|
64
|
+
}, z.core.$strict>;
|
|
65
|
+
export declare function resolveDeckBodyPaths(deck: Deck, dir: string): Deck;
|
|
66
|
+
export declare function parseDeck(path: string): Deck;
|
|
67
|
+
export declare function validateDeck(parsed: unknown): Deck;
|
|
68
|
+
export declare function validateReviewDescriptor(parsed: unknown): ReviewDescriptor;
|
|
69
|
+
/** Canonicalize and authorize the one review projection boundary before every write. */
|
|
70
|
+
export declare function validateReviewProjection(dir: string, parsed: unknown): ReviewDescriptor;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { existsSync, lstatSync, readFileSync, realpathSync } from 'node:fs';
|
|
2
|
+
import { basename, dirname, isAbsolute, resolve, sep } from 'node:path';
|
|
3
|
+
import { claimPath, deckPath, progressPath, responsePath, reviewPath } from './convention.js';
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
import { INTERACTION_KINDS } from './types.js';
|
|
6
|
+
import { checkMarkdown } from '../termrender/termrender.js';
|
|
7
|
+
import { checkReviewableFile } from './visible-paths.js';
|
|
8
|
+
export const interactionOptionSchema = z.object({ id: z.string().min(1), label: z.string().min(1), description: z.string().optional() });
|
|
9
|
+
export const preAnswerSchema = z.object({ selectedOptionId: z.string().optional(), selectedOptionIds: z.array(z.string()).optional(), freetext: z.string().optional(), label: z.string().optional() });
|
|
10
|
+
const interactionSchema = z.object({
|
|
11
|
+
id: z.string().regex(/^[A-Za-z0-9_-]+$/, { error: 'interaction id must match /^[A-Za-z0-9_-]+$/' }).min(1).max(64),
|
|
12
|
+
title: z.string().trim().min(1), subtitle: z.string().trim().min(1), body: z.string().optional(), bodyPath: z.string().optional(),
|
|
13
|
+
options: z.array(interactionOptionSchema), multiSelect: z.boolean().optional(), allowFreetext: z.boolean().optional(), freetextLabel: z.string().optional(), kind: z.enum(INTERACTION_KINDS).optional(), preAnswered: preAnswerSchema.optional(),
|
|
14
|
+
});
|
|
15
|
+
const deckSourceSchema = z.object({ sessionName: z.string().optional(), askedBy: z.string().optional(), blockedSince: z.string().optional(), nodeId: z.string().optional() });
|
|
16
|
+
export const deckSchema = z.object({ title: z.string().trim().min(1), source: deckSourceSchema.optional(), interactions: z.array(interactionSchema).min(1) }).superRefine((input, ctx) => {
|
|
17
|
+
const seen = new Set();
|
|
18
|
+
input.interactions.forEach((interaction, index) => {
|
|
19
|
+
if (interaction.body !== undefined && interaction.bodyPath !== undefined)
|
|
20
|
+
ctx.addIssue({ code: 'custom', message: 'body and bodyPath are mutually exclusive', path: ['interactions', index] });
|
|
21
|
+
if (seen.has(interaction.id))
|
|
22
|
+
ctx.addIssue({ code: 'custom', message: `duplicate interaction id "${interaction.id}"`, path: ['interactions', index, 'id'] });
|
|
23
|
+
seen.add(interaction.id);
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
const reviewSourceSchema = deckSourceSchema;
|
|
27
|
+
export const reviewDescriptorSchema = z.object({
|
|
28
|
+
schema: z.literal('humanloop.review/v1'),
|
|
29
|
+
file: z.string().min(1).refine(isAbsolute, 'file must be absolute'),
|
|
30
|
+
output: z.string().min(1).refine(isAbsolute, 'output must be absolute'),
|
|
31
|
+
title: z.string().trim().min(1),
|
|
32
|
+
subtitle: z.string().trim().min(1),
|
|
33
|
+
source: reviewSourceSchema,
|
|
34
|
+
blockedSince: z.string().datetime({ offset: true }),
|
|
35
|
+
}).strict();
|
|
36
|
+
function readBodyPathFile(dir, bodyPath) {
|
|
37
|
+
const joined = resolve(dir, bodyPath);
|
|
38
|
+
if (!existsSync(joined))
|
|
39
|
+
throw new Error(`bodyPath does not exist: '${bodyPath}'`);
|
|
40
|
+
if (!lstatSync(joined).isFile())
|
|
41
|
+
throw new Error(`bodyPath must be a regular file: ${bodyPath}`);
|
|
42
|
+
const realResolved = realpathSync(joined);
|
|
43
|
+
const realDeckDir = realpathSync(dir);
|
|
44
|
+
if (!realResolved.startsWith(realDeckDir + sep))
|
|
45
|
+
throw new Error(`bodyPath '${bodyPath}' escapes the deck directory`);
|
|
46
|
+
return readFileSync(joined, 'utf8');
|
|
47
|
+
}
|
|
48
|
+
export function resolveDeckBodyPaths(deck, dir) {
|
|
49
|
+
return { ...deck, interactions: deck.interactions.map((interaction) => {
|
|
50
|
+
if (interaction.bodyPath === undefined)
|
|
51
|
+
return interaction;
|
|
52
|
+
const { bodyPath: _bodyPath, ...rest } = interaction;
|
|
53
|
+
return { ...rest, body: readBodyPathFile(dir, interaction.bodyPath) };
|
|
54
|
+
}) };
|
|
55
|
+
}
|
|
56
|
+
export function parseDeck(path) {
|
|
57
|
+
let raw;
|
|
58
|
+
try {
|
|
59
|
+
raw = JSON.parse(readFileSync(path, 'utf8'));
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
throw new Error('deck is not valid JSON');
|
|
63
|
+
}
|
|
64
|
+
const deck = resolveDeckBodyPaths(deckSchema.parse(raw), dirname(path));
|
|
65
|
+
for (const interaction of deck.interactions)
|
|
66
|
+
if (interaction.body !== undefined) {
|
|
67
|
+
const check = checkMarkdown(interaction.body);
|
|
68
|
+
if (!check.ok)
|
|
69
|
+
throw new Error(check.error);
|
|
70
|
+
}
|
|
71
|
+
return deck;
|
|
72
|
+
}
|
|
73
|
+
export function validateDeck(parsed) { return deckSchema.parse(parsed); }
|
|
74
|
+
export function validateReviewDescriptor(parsed) { return reviewDescriptorSchema.parse(parsed); }
|
|
75
|
+
/** Canonicalize and authorize the one review projection boundary before every write. */
|
|
76
|
+
export function validateReviewProjection(dir, parsed) {
|
|
77
|
+
const descriptor = validateReviewDescriptor(parsed);
|
|
78
|
+
// Any reviewable UTF-8 text file: a .md artifact renders as a document, a
|
|
79
|
+
// source file as a syntax-highlighted code panel.
|
|
80
|
+
if (!existsSync(descriptor.file))
|
|
81
|
+
throw new Error('review file must be an existing absolute path');
|
|
82
|
+
const reviewable = checkReviewableFile(descriptor.file);
|
|
83
|
+
if (!reviewable.ok)
|
|
84
|
+
throw new Error(`review file is not reviewable: ${reviewable.reason}`);
|
|
85
|
+
const file = realpathSync(descriptor.file);
|
|
86
|
+
const output = resolve(realpathSync(dirname(descriptor.output)), basename(descriptor.output));
|
|
87
|
+
const reserved = new Set(['deck.json', 'review.json', 'response.json', 'progress.json', 'claim.json']);
|
|
88
|
+
const ownProtocolPaths = new Set([deckPath(dir), reviewPath(dir), responsePath(dir), progressPath(dir), claimPath(dir)]);
|
|
89
|
+
if (output === file || reserved.has(basename(output)) || ownProtocolPaths.has(output))
|
|
90
|
+
throw new Error('review output must not alias the source or ticket protocol files');
|
|
91
|
+
return { ...descriptor, file, output };
|
|
92
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare function ticketsRoot(): string;
|
|
2
|
+
/** A ticket directory is the bridge node's canvas directory, the same path by construction. */
|
|
3
|
+
export declare function ticketDir(nodeId: string): string;
|
|
4
|
+
export declare function inboxActivityPath(): string;
|
|
5
|
+
/** Signal one durable ticket mutation to every open inbox without watching every ticket directory. */
|
|
6
|
+
export declare function signalInboxActivity(): void;
|
|
7
|
+
export declare function watchInboxActivity(onChange: () => void): () => void;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { mkdirSync, watch, writeFileSync } from 'node:fs';
|
|
2
|
+
import { basename, dirname, join } from 'node:path';
|
|
3
|
+
import { crtrHome, nodeDir, nodesRoot } from '../canvas/paths.js';
|
|
4
|
+
export function ticketsRoot() {
|
|
5
|
+
return nodesRoot();
|
|
6
|
+
}
|
|
7
|
+
/** A ticket directory is the bridge node's canvas directory, the same path by construction. */
|
|
8
|
+
export function ticketDir(nodeId) {
|
|
9
|
+
return nodeDir(nodeId);
|
|
10
|
+
}
|
|
11
|
+
export function inboxActivityPath() {
|
|
12
|
+
return join(crtrHome(), 'signals', 'inbox-activity');
|
|
13
|
+
}
|
|
14
|
+
/** Signal one durable ticket mutation to every open inbox without watching every ticket directory. */
|
|
15
|
+
export function signalInboxActivity() {
|
|
16
|
+
try {
|
|
17
|
+
mkdirSync(dirname(inboxActivityPath()), { recursive: true, mode: 0o700 });
|
|
18
|
+
writeFileSync(inboxActivityPath(), `${Date.now()}\n`, { mode: 0o600 });
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
// A later inbox scan is still authoritative.
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
export function watchInboxActivity(onChange) {
|
|
25
|
+
const activityPath = inboxActivityPath();
|
|
26
|
+
try {
|
|
27
|
+
mkdirSync(dirname(activityPath), { recursive: true, mode: 0o700 });
|
|
28
|
+
const watcher = watch(dirname(activityPath), (_event, filename) => {
|
|
29
|
+
if (String(filename) === basename(activityPath))
|
|
30
|
+
onChange();
|
|
31
|
+
});
|
|
32
|
+
return () => watcher.close();
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return () => { };
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { readdirSync, statSync } from 'node:fs';
|
|
2
|
+
import { basename, join } from 'node:path';
|
|
3
|
+
import { claimPath, deckPath, isResolved, readJson, reviewPath } from './convention.js';
|
|
4
|
+
import { validateDeck, validateReviewDescriptor } from './deck-schema.js';
|
|
5
|
+
import { ticketsRoot } from './root.js';
|
|
6
|
+
function claimSummary(dir) {
|
|
7
|
+
const claim = readJson(claimPath(dir));
|
|
8
|
+
if (claim === null || typeof claim.host !== 'string' || typeof claim.claimedAt !== 'string' || typeof claim.heartbeatAt !== 'string')
|
|
9
|
+
return undefined;
|
|
10
|
+
return { owner: claim.host, claimedAt: claim.claimedAt, heartbeatAt: claim.heartbeatAt };
|
|
11
|
+
}
|
|
12
|
+
function deckSummary(dir, id) {
|
|
13
|
+
const raw = readJson(deckPath(dir));
|
|
14
|
+
if (raw === null)
|
|
15
|
+
return null;
|
|
16
|
+
let deck;
|
|
17
|
+
try {
|
|
18
|
+
deck = validateDeck(raw);
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
const first = deck.interactions[0];
|
|
24
|
+
if (first === undefined)
|
|
25
|
+
return null;
|
|
26
|
+
let blockedSince = deck.source?.blockedSince;
|
|
27
|
+
if (blockedSince === undefined) {
|
|
28
|
+
try {
|
|
29
|
+
blockedSince = statSync(deckPath(dir)).mtime.toISOString();
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return { dir, id, kind: 'deck', title: deck.title, subtitle: first.subtitle, interactionKind: first.kind, interactionCount: deck.interactions.length, source: deck.source ?? {}, blockedSince, claim: claimSummary(dir) };
|
|
36
|
+
}
|
|
37
|
+
function reviewSummary(dir, id) {
|
|
38
|
+
const raw = readJson(reviewPath(dir));
|
|
39
|
+
if (raw === null)
|
|
40
|
+
return null;
|
|
41
|
+
let review;
|
|
42
|
+
try {
|
|
43
|
+
review = validateReviewDescriptor(raw);
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
return { dir, id, kind: 'review', title: review.title, subtitle: review.subtitle, file: review.file, output: review.output, source: review.source, blockedSince: review.blockedSince, claim: claimSummary(dir) };
|
|
49
|
+
}
|
|
50
|
+
/** Read all unresolved deck/review tickets, newest first. Progress never affects visibility. */
|
|
51
|
+
export function scanInbox() {
|
|
52
|
+
let entries;
|
|
53
|
+
try {
|
|
54
|
+
entries = readdirSync(ticketsRoot());
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return [];
|
|
58
|
+
}
|
|
59
|
+
const items = [];
|
|
60
|
+
for (const entry of entries) {
|
|
61
|
+
const dir = join(ticketsRoot(), entry);
|
|
62
|
+
try {
|
|
63
|
+
if (!statSync(dir).isDirectory())
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
if (isResolved(dir))
|
|
70
|
+
continue;
|
|
71
|
+
const item = deckSummary(dir, basename(dir)) ?? reviewSummary(dir, basename(dir));
|
|
72
|
+
if (item !== null)
|
|
73
|
+
items.push(item);
|
|
74
|
+
}
|
|
75
|
+
return items.sort((a, b) => b.blockedSince.localeCompare(a.blockedSince) || a.id.localeCompare(b.id));
|
|
76
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Deck, InteractionResponse } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Deterministic, no-LLM resolution summary — one line per answered
|
|
4
|
+
* interaction: `"<title>: <option label>[ — <freetext>]"`. Shared by `ask()`
|
|
5
|
+
* (envelope summary) and `writeResponse` (persisted into response.json at write
|
|
6
|
+
* time).
|
|
7
|
+
*/
|
|
8
|
+
export declare function buildSummary(deck: Deck, responses: InteractionResponse[]): string;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deterministic, no-LLM resolution summary — one line per answered
|
|
3
|
+
* interaction: `"<title>: <option label>[ — <freetext>]"`. Shared by `ask()`
|
|
4
|
+
* (envelope summary) and `writeResponse` (persisted into response.json at write
|
|
5
|
+
* time).
|
|
6
|
+
*/
|
|
7
|
+
export function buildSummary(deck, responses) {
|
|
8
|
+
const byId = new Map(responses.map((r) => [r.id, r]));
|
|
9
|
+
const lines = [];
|
|
10
|
+
for (const it of deck.interactions) {
|
|
11
|
+
const r = byId.get(it.id);
|
|
12
|
+
if (r === undefined)
|
|
13
|
+
continue;
|
|
14
|
+
const ft = r.freetext !== undefined && r.freetext !== '' ? r.freetext : undefined;
|
|
15
|
+
let picked;
|
|
16
|
+
if (r.selectedOptionIds !== undefined) {
|
|
17
|
+
const oc = r.optionComments;
|
|
18
|
+
const parts = r.selectedOptionIds
|
|
19
|
+
.map((id) => it.options.find((o) => o.id === id))
|
|
20
|
+
.filter((o) => o !== undefined)
|
|
21
|
+
.map((o) => {
|
|
22
|
+
const note = oc !== undefined ? oc[o.id] : undefined;
|
|
23
|
+
return typeof note === 'string' && note.length > 0
|
|
24
|
+
? `${o.label} ("${note}")`
|
|
25
|
+
: o.label;
|
|
26
|
+
});
|
|
27
|
+
picked = parts.length > 0 ? parts.join(', ') : undefined;
|
|
28
|
+
}
|
|
29
|
+
else if (r.selectedOptionId !== undefined) {
|
|
30
|
+
picked = it.options.find((o) => o.id === r.selectedOptionId)?.label;
|
|
31
|
+
}
|
|
32
|
+
let val;
|
|
33
|
+
if (picked !== undefined && ft !== undefined)
|
|
34
|
+
val = `${picked} — ${ft}`;
|
|
35
|
+
else if (picked !== undefined)
|
|
36
|
+
val = picked;
|
|
37
|
+
else if (ft !== undefined)
|
|
38
|
+
val = ft;
|
|
39
|
+
else
|
|
40
|
+
val = '(skipped)';
|
|
41
|
+
lines.push(`${it.title}: ${val}`);
|
|
42
|
+
}
|
|
43
|
+
return lines.join('\n');
|
|
44
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { Deck, DeckTicketResult, ReviewDescriptor, TicketResult } from './types.js';
|
|
2
|
+
/** Strict decoder for the only canonical final marker. */
|
|
3
|
+
export declare function readTicketResult(dir: string): TicketResult | null;
|
|
4
|
+
export interface SubmitDeckOptions {
|
|
5
|
+
dir: string;
|
|
6
|
+
deck: Deck;
|
|
7
|
+
}
|
|
8
|
+
export declare function submitDeck(opts: SubmitDeckOptions): {
|
|
9
|
+
id: string;
|
|
10
|
+
dir: string;
|
|
11
|
+
kind: 'deck';
|
|
12
|
+
};
|
|
13
|
+
export interface SubmitReviewOptions {
|
|
14
|
+
dir: string;
|
|
15
|
+
review: Omit<ReviewDescriptor, 'schema' | 'file' | 'output' | 'blockedSince'> & {
|
|
16
|
+
file: string;
|
|
17
|
+
output?: string;
|
|
18
|
+
blockedSince?: string;
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export declare function submitReview(opts: SubmitReviewOptions): {
|
|
22
|
+
id: string;
|
|
23
|
+
dir: string;
|
|
24
|
+
kind: 'review';
|
|
25
|
+
};
|
|
26
|
+
/** Validate a deck resolution against its canonical ticket before claim takeover. */
|
|
27
|
+
export declare function validateDeckTicketResponses(dir: string, responses: unknown): DeckTicketResult['responses'];
|
|
28
|
+
export declare function completeDeck(dir: string, responses: DeckTicketResult['responses'], claimToken: string, completedAt?: string): {
|
|
29
|
+
won: boolean;
|
|
30
|
+
result: TicketResult;
|
|
31
|
+
};
|
|
32
|
+
/** Atomically take a ticket's claim over, complete it, and release the takeover claim. */
|
|
33
|
+
export declare function takeoverAndCompleteDeck(dir: string, responses: DeckTicketResult['responses'], owner: {
|
|
34
|
+
host: string;
|
|
35
|
+
pid: number;
|
|
36
|
+
}): {
|
|
37
|
+
won: boolean;
|
|
38
|
+
result: TicketResult;
|
|
39
|
+
};
|
|
40
|
+
/** Cancellation races finalization but never requires or removes another claim. */
|
|
41
|
+
export declare function cancelTicket(dir: string, opts?: {
|
|
42
|
+
reason?: string;
|
|
43
|
+
actor?: string;
|
|
44
|
+
}): {
|
|
45
|
+
status: 'canceled' | 'already_resolved';
|
|
46
|
+
result: TicketResult;
|
|
47
|
+
};
|
|
48
|
+
/** Write the validated review output once its review result is published. */
|
|
49
|
+
export declare function projectReviewOutput(dir: string): 'projected' | 'not_a_review' | 'no_result';
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, realpathSync, unlinkSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { basename, isAbsolute, resolve } from 'node:path';
|
|
3
|
+
import { randomUUID } from 'node:crypto';
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
import { buildSummary } from './summary.js';
|
|
6
|
+
import { atomicWriteJson, clearProgress, claimPath, deckPath, progressPath, publishJsonExclusive, requireTicket, responsePath, reviewPath } from './convention.js';
|
|
7
|
+
import { validateDeck, validateReviewDescriptor, validateReviewProjection, resolveDeckBodyPaths } from './deck-schema.js';
|
|
8
|
+
import { signalInboxActivity } from './root.js';
|
|
9
|
+
import { readTicketClaim, releaseClaimLocked, withTicketLock } from './claim.js';
|
|
10
|
+
import { checkReviewableFile } from './visible-paths.js';
|
|
11
|
+
const responseSchema = z.object({ id: z.string().min(1), selectedOptionId: z.string().optional(), selectedOptionIds: z.array(z.string()).optional(), freetext: z.string().optional(), optionComments: z.record(z.string(), z.string()).optional() }).strict();
|
|
12
|
+
const feedbackCommentSchema = z.object({ id: z.string().min(1), line: z.number().int().positive(), endLine: z.number().int().positive(), quote: z.string().optional(), colStart: z.number().int().nonnegative().optional(), colEnd: z.number().int().nonnegative().optional(), lineText: z.string(), comment: z.string().min(1), createdAt: z.string().min(1) }).strict();
|
|
13
|
+
const iso = z.string().datetime({ offset: true });
|
|
14
|
+
const feedbackSchema = z.object({ file: z.string().min(1).refine(isAbsolute, 'file must be absolute').refine((file) => resolve(file) === file, 'file must be canonical'), submitted: z.literal(true), approved: z.boolean(), comments: z.array(feedbackCommentSchema), submittedAt: iso, savedAt: iso, reviewId: z.string().optional(), changed: z.boolean().optional(), baselineSha256: z.string().optional(), approvedSha256: z.string().optional(), companionNodeId: z.string().optional(), commentsTotal: z.number().int().nonnegative().optional(), commentsUnresolved: z.number().int().nonnegative().optional() }).strict().superRefine((result, ctx) => {
|
|
15
|
+
result.comments.forEach((comment, index) => {
|
|
16
|
+
if (comment.endLine < comment.line)
|
|
17
|
+
ctx.addIssue({ code: 'custom', message: 'endLine must be >= line', path: ['comments', index, 'endLine'] });
|
|
18
|
+
if ((comment.colStart === undefined) !== (comment.colEnd === undefined))
|
|
19
|
+
ctx.addIssue({ code: 'custom', message: 'columns must be supplied together', path: ['comments', index] });
|
|
20
|
+
if (comment.line === comment.endLine && comment.colStart !== undefined && comment.colEnd !== undefined && comment.colEnd <= comment.colStart)
|
|
21
|
+
ctx.addIssue({ code: 'custom', message: 'colEnd must exceed colStart', path: ['comments', index, 'colEnd'] });
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
const deckResultSchema = z.object({ schema: z.literal('humanloop.response/v2'), kind: z.literal('deck'), responses: z.array(responseSchema), summary: z.string(), completedAt: iso }).strict();
|
|
25
|
+
const reviewResultSchema = z.object({ schema: z.literal('humanloop.review-response/v1'), kind: z.literal('review'), result: feedbackSchema, completedAt: iso }).strict();
|
|
26
|
+
const canceledResultSchema = z.object({ schema: z.literal('humanloop.cancel/v1'), kind: z.literal('canceled'), canceledAt: iso, reason: z.string().optional(), actor: z.string().optional() }).strict();
|
|
27
|
+
/** Strict decoder for the only canonical final marker. */
|
|
28
|
+
export function readTicketResult(dir) {
|
|
29
|
+
let raw;
|
|
30
|
+
try {
|
|
31
|
+
raw = JSON.parse(readFileSync(responsePath(dir), 'utf8'));
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
const parsed = deckResultSchema.safeParse(raw);
|
|
37
|
+
if (parsed.success)
|
|
38
|
+
return parsed.data;
|
|
39
|
+
const review = reviewResultSchema.safeParse(raw);
|
|
40
|
+
if (review.success)
|
|
41
|
+
return review.data;
|
|
42
|
+
const canceled = canceledResultSchema.safeParse(raw);
|
|
43
|
+
return canceled.success ? canceled.data : null;
|
|
44
|
+
}
|
|
45
|
+
function hasTicketProtocolState(dir) {
|
|
46
|
+
return [deckPath(dir), reviewPath(dir), responsePath(dir), progressPath(dir), claimPath(dir)].some(existsSync);
|
|
47
|
+
}
|
|
48
|
+
function publishRequest(path, value) {
|
|
49
|
+
if (!publishJsonExclusive(path, value))
|
|
50
|
+
throw new Error(`ticket request already exists: ${path}`);
|
|
51
|
+
}
|
|
52
|
+
export function submitDeck(opts) {
|
|
53
|
+
// Validate shape before mutating the bridge node's canvas directory.
|
|
54
|
+
validateDeck(opts.deck);
|
|
55
|
+
mkdirSync(opts.dir, { recursive: true, mode: 0o700 });
|
|
56
|
+
const dir = realpathSync(opts.dir);
|
|
57
|
+
if (hasTicketProtocolState(dir))
|
|
58
|
+
throw new Error(`ticket protocol state already exists: ${dir}`);
|
|
59
|
+
const deck = validateDeck(resolveDeckBodyPaths(opts.deck, dir));
|
|
60
|
+
const stamped = { ...deck, source: { ...(deck.source ?? {}), blockedSince: deck.source?.blockedSince ?? new Date().toISOString() } };
|
|
61
|
+
publishRequest(deckPath(dir), stamped);
|
|
62
|
+
signalInboxActivity();
|
|
63
|
+
return { id: basename(dir), dir, kind: 'deck' };
|
|
64
|
+
}
|
|
65
|
+
export function submitReview(opts) {
|
|
66
|
+
// A review takes any reviewable text file: a .md artifact renders as a document,
|
|
67
|
+
// and source code renders as a syntax-highlighted code panel.
|
|
68
|
+
if (!isAbsolute(opts.review.file) || !existsSync(opts.review.file))
|
|
69
|
+
throw new Error('review file must be an existing absolute path');
|
|
70
|
+
const reviewable = checkReviewableFile(opts.review.file);
|
|
71
|
+
if (!reviewable.ok)
|
|
72
|
+
throw new Error(`review file is not reviewable: ${reviewable.reason}`);
|
|
73
|
+
const source = realpathSync(opts.review.file);
|
|
74
|
+
mkdirSync(opts.dir, { recursive: true, mode: 0o700 });
|
|
75
|
+
const dir = realpathSync(opts.dir);
|
|
76
|
+
if (hasTicketProtocolState(dir))
|
|
77
|
+
throw new Error(`ticket protocol state already exists: ${dir}`);
|
|
78
|
+
const descriptor = validateReviewProjection(dir, { schema: 'humanloop.review/v1', file: source, output: resolve(opts.review.output ?? `${dir}/feedback.json`), title: opts.review.title, subtitle: opts.review.subtitle, source: opts.review.source, blockedSince: opts.review.blockedSince ?? new Date().toISOString() });
|
|
79
|
+
publishRequest(reviewPath(dir), descriptor);
|
|
80
|
+
signalInboxActivity();
|
|
81
|
+
return { id: basename(dir), dir, kind: 'review' };
|
|
82
|
+
}
|
|
83
|
+
function exclusiveResult(dir, result) {
|
|
84
|
+
return publishJsonExclusive(responsePath(dir), result);
|
|
85
|
+
}
|
|
86
|
+
function requireDeck(dir) { return validateDeck(JSON.parse(readFileSync(deckPath(dir), 'utf8'))); }
|
|
87
|
+
function requireReview(dir) { return validateReviewDescriptor(JSON.parse(readFileSync(reviewPath(dir), 'utf8'))); }
|
|
88
|
+
function validateDeckResponses(deck, raw) {
|
|
89
|
+
const responses = z.array(responseSchema).parse(raw);
|
|
90
|
+
const interactions = new Map(deck.interactions.map((interaction) => [interaction.id, interaction]));
|
|
91
|
+
const seen = new Set();
|
|
92
|
+
for (const response of responses) {
|
|
93
|
+
const interaction = interactions.get(response.id);
|
|
94
|
+
if (interaction === undefined || seen.has(response.id))
|
|
95
|
+
throw new Error(`response does not match a unique deck interaction: ${response.id}`);
|
|
96
|
+
seen.add(response.id);
|
|
97
|
+
const optionIds = new Set(interaction.options.map((option) => option.id));
|
|
98
|
+
if (response.selectedOptionId !== undefined && (!optionIds.has(response.selectedOptionId) || interaction.multiSelect === true))
|
|
99
|
+
throw new Error(`invalid single-select response for ${response.id}`);
|
|
100
|
+
if (response.selectedOptionIds !== undefined && (interaction.multiSelect !== true || response.selectedOptionIds.some((id) => !optionIds.has(id)) || new Set(response.selectedOptionIds).size !== response.selectedOptionIds.length))
|
|
101
|
+
throw new Error(`invalid multi-select response for ${response.id}`);
|
|
102
|
+
if (response.freetext !== undefined && interaction.allowFreetext !== true)
|
|
103
|
+
throw new Error(`freetext is not allowed for ${response.id}`);
|
|
104
|
+
if (response.optionComments !== undefined && (interaction.multiSelect !== true || Object.keys(response.optionComments).some((id) => !optionIds.has(id))))
|
|
105
|
+
throw new Error(`invalid option comments for ${response.id}`);
|
|
106
|
+
}
|
|
107
|
+
for (const interaction of deck.interactions.filter((candidate) => candidate.kind === 'notify')) {
|
|
108
|
+
const response = responses.find((candidate) => candidate.id === interaction.id);
|
|
109
|
+
if (response === undefined || (response.selectedOptionId === undefined && (response.selectedOptionIds?.length ?? 0) === 0 && (response.freetext?.trim() ?? '') === '')) {
|
|
110
|
+
throw new Error(`notification requires an explicit acknowledgement: ${interaction.id}`);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return responses;
|
|
114
|
+
}
|
|
115
|
+
/** Validate a deck resolution against its canonical ticket before claim takeover. */
|
|
116
|
+
export function validateDeckTicketResponses(dir, responses) {
|
|
117
|
+
const ticket = requireTicket(dir);
|
|
118
|
+
return validateDeckResponses(requireDeck(ticket), responses);
|
|
119
|
+
}
|
|
120
|
+
function requireClaimOwnership(dir, token) {
|
|
121
|
+
if (readTicketClaim(dir)?.token !== token)
|
|
122
|
+
throw new Error('only the current claim holder may submit a result');
|
|
123
|
+
}
|
|
124
|
+
function clearOwnedWork(dir, claimToken) { clearProgress(dir); releaseClaimLocked(dir, claimToken); }
|
|
125
|
+
/** Caller holds `.ticket-lock`. */
|
|
126
|
+
function completeDeckLocked(dir, responses, claimToken, completedAt = new Date().toISOString()) {
|
|
127
|
+
requireClaimOwnership(dir, claimToken);
|
|
128
|
+
const deck = requireDeck(dir);
|
|
129
|
+
const parsedResponses = validateDeckResponses(deck, responses);
|
|
130
|
+
const result = { schema: 'humanloop.response/v2', kind: 'deck', responses: parsedResponses, summary: buildSummary(deck, parsedResponses), completedAt };
|
|
131
|
+
const won = exclusiveResult(dir, result);
|
|
132
|
+
clearOwnedWork(dir, claimToken);
|
|
133
|
+
return { won, result: won ? result : readTicketResult(dir) ?? result };
|
|
134
|
+
}
|
|
135
|
+
export function completeDeck(dir, responses, claimToken, completedAt) {
|
|
136
|
+
const ticket = requireTicket(dir);
|
|
137
|
+
const completed = withTicketLock(ticket, () => completeDeckLocked(ticket, responses, claimToken, completedAt));
|
|
138
|
+
if (completed.won)
|
|
139
|
+
signalInboxActivity();
|
|
140
|
+
return completed;
|
|
141
|
+
}
|
|
142
|
+
function takeoverClaim(dir, owner) {
|
|
143
|
+
const existing = readTicketClaim(dir);
|
|
144
|
+
if (existing !== null)
|
|
145
|
+
unlinkSync(claimPath(dir));
|
|
146
|
+
const token = randomUUID();
|
|
147
|
+
const now = new Date().toISOString();
|
|
148
|
+
writeFileSync(claimPath(dir), `${JSON.stringify({ token, host: owner.host, pid: owner.pid, claimedAt: now, heartbeatAt: now })}\n`, { flag: 'wx', mode: 0o600 });
|
|
149
|
+
return token;
|
|
150
|
+
}
|
|
151
|
+
/** Atomically take a ticket's claim over, complete it, and release the takeover claim. */
|
|
152
|
+
export function takeoverAndCompleteDeck(dir, responses, owner) {
|
|
153
|
+
const ticket = requireTicket(dir);
|
|
154
|
+
const completed = withTicketLock(ticket, () => {
|
|
155
|
+
const token = takeoverClaim(ticket, owner);
|
|
156
|
+
try {
|
|
157
|
+
return completeDeckLocked(ticket, responses, token);
|
|
158
|
+
}
|
|
159
|
+
finally {
|
|
160
|
+
releaseClaimLocked(ticket, token);
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
if (completed.won)
|
|
164
|
+
signalInboxActivity();
|
|
165
|
+
return completed;
|
|
166
|
+
}
|
|
167
|
+
/** Cancellation races finalization but never requires or removes another claim. */
|
|
168
|
+
export function cancelTicket(dir, opts = {}) {
|
|
169
|
+
const ticket = requireTicket(dir);
|
|
170
|
+
const canceled = withTicketLock(ticket, () => {
|
|
171
|
+
const result = { schema: 'humanloop.cancel/v1', kind: 'canceled', canceledAt: new Date().toISOString(), ...(opts.reason === undefined ? {} : { reason: opts.reason }), ...(opts.actor === undefined ? {} : { actor: opts.actor }) };
|
|
172
|
+
const won = exclusiveResult(ticket, result);
|
|
173
|
+
return { status: won ? 'canceled' : 'already_resolved', result: won ? result : readTicketResult(ticket) ?? result };
|
|
174
|
+
});
|
|
175
|
+
if (canceled.status === 'canceled')
|
|
176
|
+
signalInboxActivity();
|
|
177
|
+
return canceled;
|
|
178
|
+
}
|
|
179
|
+
/** Write the validated review output once its review result is published. */
|
|
180
|
+
export function projectReviewOutput(dir) {
|
|
181
|
+
const result = readTicketResult(dir);
|
|
182
|
+
if (result === null)
|
|
183
|
+
return 'no_result';
|
|
184
|
+
if (result.kind !== 'review')
|
|
185
|
+
return 'not_a_review';
|
|
186
|
+
const ticket = requireTicket(dir);
|
|
187
|
+
const descriptor = validateReviewProjection(ticket, requireReview(ticket));
|
|
188
|
+
atomicWriteJson(descriptor.output, result.result);
|
|
189
|
+
return 'projected';
|
|
190
|
+
}
|