@north-light/crouter 0.3.311 → 0.3.313
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 +27 -30
- package/dist/api/client.js +80 -67
- package/dist/api/dto/broker-ops.d.ts +10 -20
- package/dist/api/dto/canvas.d.ts +1 -10
- package/dist/api/dto/health.d.ts +113 -0
- package/dist/api/dto/human-requests.d.ts +14 -3
- package/dist/api/dto/human.d.ts +2 -48
- package/dist/api/dto/human.js +3 -2
- package/dist/api/dto/inbox.d.ts +14 -0
- package/dist/api/dto/mail.d.ts +43 -0
- package/dist/api/dto/nodes.d.ts +11 -8
- package/dist/api/dto/recovery.d.ts +96 -0
- package/dist/api/dto/reviews.d.ts +2 -2
- package/dist/api/routes.d.ts +9 -6
- package/dist/api/routes.js +11 -11
- package/dist/build-root.d.ts +4 -0
- package/dist/build-root.js +11 -1
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/__tests__/integration/provider-rotation.test.ts +35 -47
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.d.ts +1 -1
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.js +12 -5
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.ts +12 -5
- package/dist/cli.js +10 -1
- package/dist/clients/__tests__/helpers/human-daemon.d.ts +11 -0
- package/dist/clients/__tests__/helpers/human-daemon.js +60 -0
- package/dist/clients/attach/chrome/canvas-panels.js +1 -1
- package/dist/clients/attach/chrome/inbox-strip.d.ts +3 -3
- package/dist/clients/attach/chrome/inbox-strip.js +17 -9
- package/dist/clients/attach/chrome/ticket-panel.d.ts +2 -2
- package/dist/clients/attach/chrome/ticket-panel.js +77 -46
- package/dist/clients/attach/overlays/graph.js +6 -9
- package/dist/clients/attach/render/chat-view.d.ts +5 -4
- package/dist/clients/attach/render/chat-view.js +22 -13
- package/dist/clients/attach/render/page-block.d.ts +11 -7
- package/dist/clients/attach/render/page-block.js +64 -55
- package/dist/clients/attach/viewer.js +746 -735
- package/dist/clients/inbox/__tests__/integration/inbox-controller.test.js +56 -56
- package/dist/clients/inbox/__tests__/integration/stale-row-activation.test.js +45 -32
- package/dist/clients/inbox/controller.d.ts +42 -14
- package/dist/clients/inbox/controller.js +240 -124
- package/dist/clients/inbox/dto-adapt.d.ts +28 -0
- package/dist/clients/inbox/dto-adapt.js +93 -0
- package/dist/clients/inbox/page-adapter.d.ts +5 -4
- package/dist/clients/inbox/page-adapter.js +12 -12
- package/dist/clients/inbox/resolve.d.ts +10 -5
- package/dist/clients/inbox/resolve.js +13 -12
- package/dist/clients/inbox/review/review-client.d.ts +0 -1
- package/dist/clients/inbox/review/review-client.js +0 -4
- package/dist/clients/inbox/review-adapter.d.ts +2 -1
- package/dist/clients/inbox/review-adapter.js +3 -5
- package/dist/clients/inbox/surface.d.ts +2 -2
- package/dist/clients/inbox/surface.js +19 -8
- package/dist/clients/inbox/tui.d.ts +3 -3
- package/dist/commands/__tests__/human.test.js +31 -15
- package/dist/commands/__tests__/integration/dashboard-snapshot.test.js +36 -11
- package/dist/commands/{sys/__tests__ → __tests__/integration}/migrate.test.js +142 -36
- package/dist/commands/__tests__/revive-now-gate.test.js +2 -0
- package/dist/commands/api-client.d.ts +5 -4
- package/dist/commands/api-client.js +13 -7
- package/dist/commands/canvas-history/shared.js +1 -1
- package/dist/commands/canvas-history.js +1 -1
- package/dist/commands/canvas-roster.js +1 -1
- package/dist/commands/canvas.js +1 -2
- package/dist/commands/human/feedback.js +20 -17
- package/dist/commands/human/prompts.js +45 -36
- package/dist/commands/human/queue.js +73 -123
- package/dist/commands/human/review.js +6 -16
- package/dist/commands/memory/__tests__/command-selector-and-mutation-guards.test.js +2 -0
- package/dist/commands/memory/__tests__/memory-list-and-lint-ignore.test.js +2 -0
- package/dist/commands/memory/__tests__/repository-root-lint.test.js +2 -0
- package/dist/commands/node-inspect-artifacts.js +1 -1
- package/dist/commands/node-lifecycle-revive.d.ts +2 -2
- package/dist/commands/node-lifecycle-revive.js +9 -19
- package/dist/commands/pkg/plugin-manage.js +0 -1
- package/dist/commands/profile/show.js +4 -12
- package/dist/commands/surface-tmux-spread.js +1 -5
- package/dist/commands/sys/__tests__/config-model-ladders.test.js +23 -30
- package/dist/commands/sys/__tests__/sync-project-guidance.test.js +37 -11
- package/dist/commands/sys/branch.d.ts +2 -0
- package/dist/commands/sys/branch.js +19 -0
- package/dist/commands/sys/config.js +106 -33
- package/dist/commands/sys/daemon.d.ts +2 -0
- package/dist/commands/sys/daemon.js +130 -7
- package/dist/commands/sys/doctor.js +5 -15
- package/dist/commands/sys/migrate.js +21 -92
- package/dist/commands/sys/setup-settings-runner.js +4 -2
- package/dist/commands/sys.js +2 -15
- package/dist/core/__tests__/boot-fault-attempt.test.js +23 -1
- package/dist/core/__tests__/boot.test.js +32 -25
- package/dist/core/__tests__/broker-launch-candidates.test.js +49 -0
- package/dist/core/__tests__/canvas-inbox-watcher-hold.test.js +149 -176
- package/dist/core/__tests__/canvas-inbox-watcher-naming.test.js +59 -10
- package/dist/core/__tests__/canvas-inbox-watcher.test.js +76 -20
- package/dist/core/__tests__/canvas.test.js +18 -47
- package/dist/core/__tests__/child-death-wake.test.js +29 -7
- package/dist/core/__tests__/cli-help-contract.test.js +2 -0
- package/dist/core/__tests__/close.test.js +29 -10
- package/dist/core/__tests__/collectible.test.js +2 -1
- package/dist/core/__tests__/config-change-delta.test.js +2 -0
- package/dist/core/__tests__/context-intro.test.js +17 -5
- package/dist/core/__tests__/cron-armed-context-failure.test.js +17 -12
- package/dist/core/__tests__/cron-held-settlement.test.js +21 -3
- package/dist/core/__tests__/cron-node-sink-parked-root.test.js +29 -10
- package/dist/core/__tests__/cron-self-cancel-delivery.test.js +14 -2
- package/dist/core/__tests__/cron-timeout-descendants.test.js +13 -1
- package/dist/core/__tests__/daemon-boot.test.js +51 -14
- package/dist/core/__tests__/fixtures/fake-engine.d.ts +1 -1
- package/dist/core/__tests__/fixtures/fake-engine.js +8 -3
- package/dist/core/__tests__/focuses.test.js +10 -5
- package/dist/core/__tests__/helpers/harness.js +50 -18
- package/dist/core/__tests__/history-inbox.test.js +12 -16
- package/dist/core/__tests__/human-action-delivery.test.js +48 -28
- package/dist/core/__tests__/human-actions.test.js +7 -3
- package/dist/core/__tests__/inline-memory-refs.test.js +7 -2
- package/dist/core/__tests__/integration/broker-fork-seam.test.js +37 -10
- package/dist/core/__tests__/integration/broker-sdk-wiring.test.js +42 -0
- package/dist/core/__tests__/integration/broker-snapshot-history.test.js +42 -29
- package/dist/core/__tests__/integration/broker-wedge-supervision.test.js +36 -35
- package/dist/core/__tests__/integration/command-plugins.test.js +15 -6
- package/dist/core/__tests__/integration/deferred-no-wake.test.js +113 -92
- package/dist/core/__tests__/integration/host-teardown-process-group.test.js +9 -5
- package/dist/core/__tests__/integration/lifecycle-hooks.test.js +312 -1
- package/dist/core/__tests__/integration/plugin-revalidate.test.js +4 -0
- package/dist/core/__tests__/integration/profile-pause.test.js +4 -4
- package/dist/core/__tests__/integration/refresh-stall-recycle.test.js +9 -12
- package/dist/core/__tests__/integration/revive.test.js +67 -21
- package/dist/core/__tests__/integration/spawn-root.test.js +62 -19
- package/dist/core/__tests__/integration/subscription-delivery.test.js +33 -21
- package/dist/core/__tests__/integration/worktree-land.test.js +5 -2
- package/dist/core/__tests__/integration/worktree-reap.test.js +15 -1
- package/dist/core/__tests__/kickoff.test.js +36 -39
- package/dist/core/__tests__/lifecycle-terminal-reasons.test.js +2 -1
- package/dist/core/__tests__/lifecycle.test.js +2 -1
- package/dist/core/__tests__/live-lifecycle-prompt.test.js +13 -1
- package/dist/core/__tests__/memory-resolver-precedence.test.js +2 -0
- package/dist/core/__tests__/migration.test.js +145 -31
- package/dist/core/__tests__/model-pin-durability.test.js +4 -1
- package/dist/core/__tests__/model-routes-config.test.js +13 -5
- package/dist/core/__tests__/node-outcome.test.js +93 -26
- package/dist/core/__tests__/on-read-crouter-home-fence.test.js +4 -3
- package/dist/core/__tests__/on-read-dedup-resume.test.js +8 -7
- package/dist/core/__tests__/on-read-nested-store.test.js +8 -7
- package/dist/core/__tests__/passive-subscription.test.js +50 -157
- package/dist/core/__tests__/plugin-kinds.test.js +6 -4
- package/dist/core/__tests__/plugin-link-symlinked-scope-root.test.js +6 -1
- package/dist/core/__tests__/plugin-page-components.test.js +6 -4
- package/dist/core/__tests__/preview-registry-sync.test.js +2 -0
- package/dist/core/__tests__/profile-project-memory-delivery.test.js +35 -32
- package/dist/core/__tests__/prune.test.js +11 -5
- package/dist/core/__tests__/push-final-guard.test.js +14 -7
- package/dist/core/__tests__/relaunch-root.test.js +30 -2
- package/dist/core/__tests__/remote-canvas-target.test.js +7 -1
- package/dist/core/__tests__/repository-root-identity.test.js +4 -0
- package/dist/core/__tests__/review-model-floor.test.js +6 -3
- package/dist/core/__tests__/revive-all.test.js +13 -3
- package/dist/core/__tests__/revive-capacity.test.js +26 -4
- package/dist/core/__tests__/revive-parked-fresh.test.js +31 -8
- package/dist/core/__tests__/seam/broker-attach-stream.test.js +1 -1
- package/dist/core/__tests__/seam/broker-cap-freeze.test.js +4 -3
- package/dist/core/__tests__/seam/broker-crash-teardown.test.js +11 -14
- package/dist/core/__tests__/seam/broker-provider-retry.test.js +85 -71
- package/dist/core/__tests__/seam/dormancy-release.test.js +33 -19
- package/dist/core/__tests__/seam/held-deferred-human-prompt.test.js +7 -5
- package/dist/core/__tests__/seam/inbox-reference-guidance.test.js +20 -6
- package/dist/core/__tests__/seam/node-outcome-delivery.test.js +27 -3
- package/dist/core/__tests__/spawn-worktree-id-conflict.test.js +5 -4
- package/dist/core/__tests__/stop-guard.test.js +2 -1
- package/dist/core/__tests__/subscription-pool-credential-guard.test.js +4 -3
- package/dist/core/__tests__/warm-claim-preference-snapshot.test.js +19 -5
- package/dist/core/__tests__/yield-ensures-daemon.test.js +2 -1
- package/dist/core/bootstrap.js +2 -0
- package/dist/core/broker-client/__tests__/transport-socket.test.js +51 -6
- package/dist/core/broker-client/transport-socket.d.ts +1 -0
- package/dist/core/broker-client/transport-socket.js +13 -5
- package/dist/core/canvas/__tests__/attention.test.js +29 -35
- package/dist/core/canvas/__tests__/history-transcript.test.js +6 -6
- package/dist/core/canvas/__tests__/render-remote.test.js +25 -9
- package/dist/core/canvas/attention.d.ts +2 -5
- package/dist/core/canvas/attention.js +15 -64
- package/dist/core/canvas/boot.d.ts +6 -7
- package/dist/core/canvas/boot.js +5 -9
- package/dist/core/canvas/canvas.d.ts +13 -109
- package/dist/core/canvas/canvas.js +140 -401
- package/dist/core/canvas/crons.d.ts +2 -0
- package/dist/core/canvas/crons.js +16 -15
- package/dist/core/canvas/daemon-owner.js +10 -0
- package/dist/core/canvas/db.d.ts +2 -2
- package/dist/core/canvas/db.js +2 -18
- package/dist/core/canvas/deliveries.d.ts +104 -0
- package/dist/core/canvas/deliveries.js +354 -0
- package/dist/core/canvas/executions.d.ts +29 -0
- package/dist/core/canvas/executions.js +68 -0
- package/dist/core/canvas/history.js +35 -35
- package/dist/core/canvas/index.d.ts +3 -1
- package/dist/core/canvas/index.js +3 -1
- package/dist/core/canvas/migrations.js +20 -12
- package/dist/core/canvas/nav-model.js +1 -3
- package/dist/core/canvas/nav-render.d.ts +4 -4
- package/dist/core/canvas/nav-render.js +11 -21
- package/dist/core/canvas/node-sql-migration.d.ts +3 -0
- package/dist/core/canvas/node-sql-migration.js +261 -0
- package/dist/core/canvas/paths.d.ts +2 -16
- package/dist/core/canvas/paths.js +2 -31
- package/dist/core/canvas/recovery.d.ts +76 -0
- package/dist/core/canvas/recovery.js +588 -0
- package/dist/core/canvas/remote-canvas-source.js +4 -0
- package/dist/core/canvas/render-source.d.ts +16 -27
- package/dist/core/canvas/render-source.js +16 -45
- package/dist/core/canvas/sessions.d.ts +33 -0
- package/dist/core/canvas/sessions.js +78 -0
- package/dist/core/canvas/types.d.ts +33 -33
- package/dist/core/canvas/types.js +2 -5
- package/dist/core/canvas/waits.d.ts +18 -0
- package/dist/core/canvas/waits.js +70 -0
- package/dist/core/canvas/worktrees.d.ts +40 -0
- package/dist/core/canvas/worktrees.js +93 -0
- package/dist/core/command-hooks/artifact.d.ts +6 -0
- package/dist/core/command-hooks/artifact.js +22 -6
- package/dist/core/command-hooks/discovery.d.ts +2 -0
- package/dist/core/command-hooks/discovery.js +2 -0
- package/dist/core/command-hooks/lifecycle-catalog.d.ts +20 -2
- package/dist/core/command-hooks/lifecycle-catalog.js +7 -2
- package/dist/core/command-hooks/lifecycle-create.d.ts +4 -0
- package/dist/core/command-hooks/lifecycle-create.js +51 -0
- package/dist/core/command-hooks/schema.d.ts +2 -2
- package/dist/core/command-hooks/schema.js +5 -4
- package/dist/core/command-hooks/transport/exec-invoke.js +3 -1
- package/dist/core/command-hooks/transport/exec-lifecycle.d.ts +18 -8
- package/dist/core/command-hooks/transport/exec-lifecycle.js +89 -30
- package/dist/core/config.d.ts +17 -12
- package/dist/core/config.js +106 -155
- package/dist/core/errors.d.ts +1 -0
- package/dist/core/errors.js +4 -0
- package/dist/core/feed/__tests__/inbox-migrate.test.js +27 -31
- package/dist/core/feed/feed.d.ts +0 -6
- package/dist/core/feed/feed.js +68 -56
- package/dist/core/feed/inbox.d.ts +7 -81
- package/dist/core/feed/inbox.js +46 -378
- package/dist/core/feed/messages.d.ts +58 -0
- package/dist/core/feed/messages.js +217 -0
- package/dist/core/fs-utils.d.ts +4 -0
- package/dist/core/fs-utils.js +21 -1
- package/dist/core/human/answer.d.ts +1 -1
- package/dist/core/human/answer.js +1 -1
- package/dist/core/human/claim.d.ts +1 -1
- package/dist/core/human/claim.js +2 -4
- package/dist/core/human/component-docs.js +1 -1
- package/dist/core/human/feedback-companion.js +4 -3
- package/dist/core/human/feedback.d.ts +5 -8
- package/dist/core/human/feedback.js +57 -85
- package/dist/core/human/page-authoring.d.ts +30 -0
- package/dist/core/human/page-authoring.js +19 -0
- package/dist/core/human/requests.d.ts +136 -0
- package/dist/core/human/requests.js +515 -0
- package/dist/core/human/root.d.ts +0 -7
- package/dist/core/human/root.js +0 -17
- package/dist/core/human/scan.d.ts +2 -7
- package/dist/core/human/scan.js +48 -132
- package/dist/core/human/summary.d.ts +1 -1
- package/dist/core/human/summary.js +1 -1
- package/dist/core/human/tickets.d.ts +23 -83
- package/dist/core/human/tickets.js +92 -243
- package/dist/core/human/types.d.ts +5 -1
- package/dist/core/installed-plugins.js +8 -3
- package/dist/core/keybindings/__tests__/resolve.test.js +19 -17
- package/dist/core/locked-file.d.ts +6 -3
- package/dist/core/locked-file.js +36 -9
- package/dist/core/memory/extensions.js +2 -0
- package/dist/core/preview-registry.js +0 -1
- package/dist/core/profiles/__tests__/env-store.test.js +2 -0
- package/dist/core/profiles/default-binding.d.ts +0 -4
- package/dist/core/profiles/default-binding.js +12 -58
- package/dist/core/profiles/env-store.js +8 -3
- package/dist/core/profiles/manifest.d.ts +2 -37
- package/dist/core/profiles/manifest.js +35 -161
- package/dist/core/profiles/select.js +3 -0
- package/dist/core/review/__tests__/capture-origin.test.js +13 -2
- package/dist/core/review/__tests__/comments.test.js +28 -10
- package/dist/core/review/__tests__/remap.test.js +28 -10
- package/dist/core/review/__tests__/stage-identity.test.js +17 -7
- package/dist/core/review/birth.d.ts +1 -1
- package/dist/core/review/birth.js +34 -5
- package/dist/core/review/comments.js +1 -1
- package/dist/core/review/companion.d.ts +1 -1
- package/dist/core/review/companion.js +2 -2
- package/dist/core/review/document.js +1 -1
- package/dist/core/review/project.d.ts +5 -1
- package/dist/core/review/project.js +14 -36
- package/dist/core/review/realize.d.ts +3 -6
- package/dist/core/review/realize.js +51 -168
- package/dist/core/review/remap.js +1 -1
- package/dist/core/review/stage.d.ts +3 -2
- package/dist/core/review/stage.js +2 -3
- package/dist/core/review/store.d.ts +3 -21
- package/dist/core/review/store.js +140 -186
- package/dist/core/review/types.d.ts +0 -1
- package/dist/core/runtime/__tests__/install-id-cache-scoping.test.js +9 -5
- package/dist/core/runtime/__tests__/spawn-env.test.js +8 -9
- package/dist/core/runtime/broker/auth-reload.js +9 -10
- package/dist/core/runtime/broker/daemon-ops.d.ts +25 -8
- package/dist/core/runtime/broker/daemon-ops.js +42 -9
- package/dist/core/runtime/broker/extension-abort.d.ts +3 -0
- package/dist/core/runtime/broker/extension-abort.js +11 -0
- package/dist/core/runtime/broker/fault-retry.d.ts +15 -6
- package/dist/core/runtime/broker/fault-retry.js +142 -95
- package/dist/core/runtime/broker/inbox.d.ts +4 -32
- package/dist/core/runtime/broker/inbox.js +4 -92
- package/dist/core/runtime/broker/rebind.d.ts +1 -0
- package/dist/core/runtime/broker/rebind.js +21 -12
- package/dist/core/runtime/broker-persona-guidance.d.ts +1 -1
- package/dist/core/runtime/broker-persona-guidance.js +2 -13
- package/dist/core/runtime/broker.js +28 -22
- package/dist/core/runtime/close.d.ts +3 -9
- package/dist/core/runtime/close.js +16 -27
- package/dist/core/runtime/fault.d.ts +3 -93
- package/dist/core/runtime/fault.js +9 -419
- package/dist/core/runtime/kickoff.d.ts +3 -6
- package/dist/core/runtime/kickoff.js +12 -18
- package/dist/core/runtime/launch.js +1 -1
- package/dist/core/runtime/lifecycle.js +40 -7
- package/dist/core/runtime/nodes.d.ts +5 -1
- package/dist/core/runtime/nodes.js +26 -11
- package/dist/core/runtime/placement.js +2 -2
- package/dist/core/runtime/recycle.js +24 -14
- package/dist/core/runtime/reset.js +26 -7
- package/dist/core/runtime/revive.js +226 -217
- package/dist/core/runtime/spawn.d.ts +4 -1
- package/dist/core/runtime/spawn.js +43 -5
- package/dist/core/runtime/warm-pool.d.ts +2 -2
- package/dist/core/runtime/warm-pool.js +23 -3
- package/dist/core/scoped-state/db.d.ts +7 -0
- package/dist/core/scoped-state/db.js +92 -0
- package/dist/core/scoped-state/migrate.d.ts +11 -0
- package/dist/core/scoped-state/migrate.js +198 -0
- package/dist/core/scoped-state/paths.d.ts +9 -0
- package/dist/core/scoped-state/paths.js +27 -0
- package/dist/core/scoped-state/profiles.d.ts +12 -0
- package/dist/core/scoped-state/profiles.js +62 -0
- package/dist/core/scoped-state/providers.d.ts +16 -0
- package/dist/core/scoped-state/providers.js +8 -0
- package/dist/core/scoped-state/schema.d.ts +3 -0
- package/dist/core/scoped-state/schema.js +26 -0
- package/dist/core/scoped-state/settings.d.ts +28 -0
- package/dist/core/scoped-state/settings.js +82 -0
- package/dist/core/subscription-state.d.ts +29 -48
- package/dist/core/subscription-state.js +176 -712
- package/dist/core/worktree-close.js +4 -4
- package/dist/core/worktree-mutation-async.js +2 -2
- package/dist/core/worktree-sweep.js +11 -16
- package/dist/core/worktree.js +6 -12
- package/dist/daemon/__tests__/autostart-storm.test.js +1 -39
- package/dist/daemon/__tests__/helpers/source-daemon.d.ts +2 -2
- package/dist/daemon/__tests__/helpers/source-daemon.js +7 -6
- package/dist/daemon/__tests__/integration/migration-startup.test.js +59 -26
- package/dist/daemon/__tests__/node-deadline-lane.test.js +2 -1
- package/dist/daemon/__tests__/node-outcome-birth-invariants.test.js +41 -17
- package/dist/daemon/__tests__/node-outcome-delivery.test.js +39 -10
- package/dist/daemon/__tests__/reconciler-signature.test.js +2 -2
- package/dist/daemon/__tests__/subtree-filter-freshness.test.js +2 -2
- package/dist/daemon/api/__tests__/broker-settle-park.test.js +17 -12
- package/dist/daemon/api/__tests__/canvas-snapshot-fields.test.js +27 -5
- package/dist/daemon/api/__tests__/model-config.test.js +8 -8
- package/dist/daemon/api/__tests__/node-create-description.test.js +22 -5
- package/dist/daemon/api/__tests__/node-model-validation.test.js +21 -1
- package/dist/daemon/api/__tests__/nodes-activity-query.test.js +10 -12
- package/dist/daemon/api/__tests__/profile-launch-gates.test.js +6 -3
- package/dist/daemon/api/__tests__/profile-metadata-route.test.js +4 -1
- package/dist/daemon/api/__tests__/reopen-delivery.test.js +26 -8
- package/dist/daemon/api/__tests__/seam/api-server.test.js +24 -32
- package/dist/daemon/api/__tests__/seam/b10-attach-modelauth.test.js +4 -1
- package/dist/daemon/api/__tests__/seam/leaf-api-parity.test.js +5 -4
- package/dist/daemon/api/__tests__/seam/profile-delete.test.js +29 -43
- package/dist/daemon/api/__tests__/submit-result.test.js +3 -2
- package/dist/daemon/api/bridge.js +1 -1
- package/dist/daemon/api/handlers/bash-jobs.js +6 -7
- package/dist/daemon/api/handlers/broker-ops.js +47 -84
- package/dist/daemon/api/handlers/broker-recovery.d.ts +4 -0
- package/dist/daemon/api/handlers/broker-recovery.js +251 -0
- package/dist/daemon/api/handlers/canvas.js +2 -44
- package/dist/daemon/api/handlers/daemon.js +41 -0
- package/dist/daemon/api/handlers/feedback-comments.js +2 -2
- package/dist/daemon/api/handlers/health.js +10 -5
- package/dist/daemon/api/handlers/human-requests.js +168 -188
- package/dist/daemon/api/handlers/human.js +3 -148
- package/dist/daemon/api/handlers/inbox-page.d.ts +4 -0
- package/dist/daemon/api/handlers/inbox-page.js +89 -0
- package/dist/daemon/api/handlers/inbox.js +21 -120
- package/dist/daemon/api/handlers/messages.d.ts +1 -0
- package/dist/daemon/api/handlers/messages.js +73 -15
- package/dist/daemon/api/handlers/node-outcomes.js +58 -13
- package/dist/daemon/api/handlers/nodes.d.ts +1 -0
- package/dist/daemon/api/handlers/nodes.js +41 -42
- package/dist/daemon/api/handlers/reviews.js +4 -29
- package/dist/daemon/api/map.d.ts +25 -3
- package/dist/daemon/api/map.js +84 -14
- package/dist/daemon/api/server.js +68 -9
- package/dist/daemon/control.d.ts +18 -0
- package/dist/daemon/cron/disposition.d.ts +2 -0
- package/dist/daemon/cron/disposition.js +8 -5
- package/dist/daemon/cron/settle.js +37 -13
- package/dist/daemon/cron/sinks.d.ts +18 -1
- package/dist/daemon/cron/sinks.js +47 -93
- package/dist/daemon/crtrd-cli.js +4 -19
- package/dist/daemon/crtrd.d.ts +2 -0
- package/dist/daemon/crtrd.js +206 -81
- package/dist/daemon/fleet.js +5 -6
- package/dist/daemon/human/finish.d.ts +12 -24
- package/dist/daemon/human/finish.js +88 -285
- package/dist/daemon/human/settle.d.ts +40 -0
- package/dist/daemon/human/settle.js +89 -0
- package/dist/daemon/human/sweep.d.ts +20 -5
- package/dist/daemon/human/sweep.js +56 -60
- package/dist/daemon/manage.d.ts +21 -16
- package/dist/daemon/manage.js +85 -51
- package/dist/daemon/messaging/node-message.d.ts +1 -1
- package/dist/daemon/messaging/node-message.js +9 -12
- package/dist/daemon/park-activity.js +3 -3
- package/dist/daemon/reconcilers/bash-deadline.js +6 -7
- package/dist/daemon/reconcilers/broker-supervision.d.ts +1 -1
- package/dist/daemon/reconcilers/broker-supervision.js +41 -19
- package/dist/daemon/reconcilers/controller-death.js +6 -18
- package/dist/daemon/reconcilers/delivery-lane.d.ts +9 -0
- package/dist/daemon/reconcilers/delivery-lane.js +130 -0
- package/dist/daemon/reconcilers/live-obligation.js +3 -3
- package/dist/daemon/reconcilers/node-deadline.js +1 -1
- package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.d.ts +1 -1
- package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.js +10 -12
- package/dist/daemon/reconcilers/node-lifecycle/tick.js +5 -5
- package/dist/daemon/reconcilers/node-lifecycle/wants-execution.js +1 -1
- package/dist/daemon/reconcilers/pending-review-submit.js +3 -3
- package/dist/daemon/reconcilers/storage-maintenance.d.ts +2 -8
- package/dist/daemon/reconcilers/storage-maintenance.js +13 -43
- package/dist/daemon/review/companion.js +5 -11
- package/dist/daemon/review/deliver.d.ts +1 -5
- package/dist/daemon/review/deliver.js +3 -52
- package/dist/daemon/review/finish.d.ts +2 -27
- package/dist/daemon/review/finish.js +79 -263
- package/dist/daemon/review/sweep.d.ts +3 -10
- package/dist/daemon/review/sweep.js +13 -131
- package/dist/daemon/startup-policy.d.ts +0 -5
- package/dist/daemon/startup-policy.js +0 -5
- package/dist/hook-authoring.d.ts +28 -2
- package/dist/hook-authoring.js +53 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.js +1 -1
- package/dist/migrations/__tests__/activation-concurrency.test.js +3 -2
- package/dist/migrations/__tests__/activation.test.js +9 -6
- package/dist/migrations/activation.d.ts +3 -2
- package/dist/migrations/activation.js +2 -4
- package/dist/migrations/corpus.d.ts +2 -5
- package/dist/migrations/corpus.js +9 -20
- package/dist/migrations/runner.d.ts +3 -1
- package/dist/migrations/runner.js +6 -2
- package/dist/pi-extensions/__tests__/canvas-context-intro.test.js +21 -89
- package/dist/pi-extensions/__tests__/canvas-goal-capture-envelope.test.js +4 -2
- package/dist/pi-extensions/__tests__/canvas-stophook-agentend.test.js +51 -33
- package/dist/pi-extensions/__tests__/canvas-stophook-context-nudge.test.js +16 -2
- package/dist/pi-extensions/__tests__/pre-command-gate.test.js +13 -1
- package/dist/pi-extensions/canvas-inbox-watcher.js +98 -244
- package/dist/pi-extensions/canvas-passive-context.d.ts +4 -8
- package/dist/pi-extensions/canvas-passive-context.js +85 -37
- package/dist/pi-extensions/canvas-stophook.js +47 -31
- package/dist/shared/env.d.ts +1 -0
- package/dist/shared/env.js +3 -0
- package/package.json +1 -1
- package/runtime.lock.json +5 -5
- package/dist/clients/attach/__tests__/page-block.test.js +0 -54
- package/dist/clients/inbox/review-visibility.d.ts +0 -5
- package/dist/clients/inbox/review-visibility.js +0 -19
- package/dist/commands/canvas-rebuild-index.d.ts +0 -2
- package/dist/commands/canvas-rebuild-index.js +0 -46
- package/dist/core/__tests__/human-cancel-guard.test.js +0 -110
- package/dist/core/__tests__/human-deliver.test.d.ts +0 -1
- package/dist/core/__tests__/human-deliver.test.js +0 -256
- package/dist/core/__tests__/human-node-not-supervised.test.d.ts +0 -1
- package/dist/core/__tests__/human-node-not-supervised.test.js +0 -89
- package/dist/core/__tests__/integration/human-deliver-e2e.test.d.ts +0 -1
- package/dist/core/__tests__/integration/human-deliver-e2e.test.js +0 -131
- package/dist/core/__tests__/phase4-review-store.test.d.ts +0 -1
- package/dist/core/__tests__/phase4-review-store.test.js +0 -144
- package/dist/core/__tests__/watchdog-abort-arms-retry.test.d.ts +0 -1
- package/dist/core/__tests__/watchdog-abort-arms-retry.test.js +0 -110
- package/dist/core/canvas/human-deliveries.d.ts +0 -39
- package/dist/core/canvas/human-deliveries.js +0 -75
- package/dist/core/canvas/node-outcome-deliveries.d.ts +0 -64
- package/dist/core/canvas/node-outcome-deliveries.js +0 -159
- package/dist/core/feed/passive.d.ts +0 -3
- package/dist/core/feed/passive.js +0 -53
- package/dist/core/human/__tests__/inbox-cancel-worker.d.ts +0 -1
- package/dist/core/human/__tests__/inbox-cancel-worker.js +0 -7
- package/dist/core/human/__tests__/inbox-claim-worker.d.ts +0 -1
- package/dist/core/human/__tests__/inbox-claim-worker.js +0 -17
- package/dist/core/human/__tests__/inbox-stale-claim-worker.d.ts +0 -1
- package/dist/core/human/__tests__/inbox-stale-claim-worker.js +0 -8
- package/dist/core/human/__tests__/integration/inbox-core.test.d.ts +0 -1
- package/dist/core/human/__tests__/integration/inbox-core.test.js +0 -145
- package/dist/core/human/__tests__/page-tickets.test.d.ts +0 -1
- package/dist/core/human/__tests__/page-tickets.test.js +0 -161
- package/dist/core/review/ticket-filter.d.ts +0 -17
- package/dist/core/review/ticket-filter.js +0 -21
- package/dist/core/runtime/broker/passive.d.ts +0 -17
- package/dist/core/runtime/broker/passive.js +0 -44
- package/dist/core/runtime/busy.d.ts +0 -46
- package/dist/core/runtime/busy.js +0 -150
- package/dist/daemon/__tests__/startup-block-marker.test.d.ts +0 -1
- package/dist/daemon/__tests__/startup-block-marker.test.js +0 -86
- package/dist/daemon/api/__tests__/review-terminal-conflict.test.d.ts +0 -1
- package/dist/daemon/api/__tests__/review-terminal-conflict.test.js +0 -98
- package/dist/daemon/human/deliver-action.d.ts +0 -3
- package/dist/daemon/human/deliver-action.js +0 -9
- package/dist/daemon/node-outcome/deliver-outcome.d.ts +0 -3
- package/dist/daemon/node-outcome/deliver-outcome.js +0 -9
- package/dist/daemon/reconcilers/human-delivery-lane.d.ts +0 -10
- package/dist/daemon/reconcilers/human-delivery-lane.js +0 -41
- package/dist/daemon/reconcilers/node-outcome-delivery-lane.d.ts +0 -10
- package/dist/daemon/reconcilers/node-outcome-delivery-lane.js +0 -41
- package/dist/daemon/startup-block-marker.d.ts +0 -25
- package/dist/daemon/startup-block-marker.js +0 -99
- /package/dist/{clients/attach/__tests__/page-block.test.d.ts → api/dto/mail.js} +0 -0
- /package/dist/{commands/sys/__tests__/migrate.test.d.ts → api/dto/recovery.js} +0 -0
- /package/dist/{core/__tests__/human-cancel-guard.test.d.ts → commands/__tests__/integration/migrate.test.d.ts} +0 -0
|
@@ -1,148 +1,3 @@
|
|
|
1
|
-
// Human
|
|
2
|
-
//
|
|
3
|
-
|
|
4
|
-
import { existsSync } from 'node:fs';
|
|
5
|
-
import { ApiError } from '../../../api/index.js';
|
|
6
|
-
import { isSafeNodeId } from '../../../core/canvas/paths.js';
|
|
7
|
-
import { pageManifestPath, readTicketReplyRoute, reviewPath } from '../../../core/human/convention.js';
|
|
8
|
-
import { ticketDir } from '../../../core/human/root.js';
|
|
9
|
-
import { readTicketResult, validatePageTicketResponses } from '../../../core/human/tickets.js';
|
|
10
|
-
import { getReviewByBridge } from '../../../core/review/store.js';
|
|
11
|
-
import { ReviewOperationError } from '../../../core/review/types.js';
|
|
12
|
-
import { spawnNode } from '../../../core/runtime/nodes.js';
|
|
13
|
-
import { cancelHumanTicket, resolvePageTicket } from '../../human/finish.js';
|
|
14
|
-
import { cancelReview } from '../../review/finish.js';
|
|
15
|
-
function requireInteractionTicketId(ctx) {
|
|
16
|
-
const ticketId = ctx.params['ticket_id'];
|
|
17
|
-
if (ticketId === undefined || !isSafeNodeId(ticketId)) {
|
|
18
|
-
throw new ApiError(400, 'invalid_request', 'invalid interaction ticket id');
|
|
19
|
-
}
|
|
20
|
-
return ticketId;
|
|
21
|
-
}
|
|
22
|
-
// POST /v1/human/bridge — create a terminal bridge without a broker
|
|
23
|
-
function handleCreateBridge(ctx) {
|
|
24
|
-
const req = ctx.body;
|
|
25
|
-
if (req === undefined || typeof req !== 'object') {
|
|
26
|
-
throw new ApiError(400, 'invalid_request', 'bridge body is required');
|
|
27
|
-
}
|
|
28
|
-
const { kind, cwd, name } = req;
|
|
29
|
-
if (kind !== 'human')
|
|
30
|
-
throw new ApiError(400, 'invalid_request', 'bridge kind must be "human"');
|
|
31
|
-
if (typeof cwd !== 'string' || cwd === '')
|
|
32
|
-
throw new ApiError(400, 'invalid_request', 'bridge body requires `cwd`');
|
|
33
|
-
if (typeof name !== 'string' || name === '')
|
|
34
|
-
throw new ApiError(400, 'invalid_request', 'bridge body requires `name`');
|
|
35
|
-
const parent = req.parent ?? null;
|
|
36
|
-
if (parent !== null && (typeof parent !== 'string' || parent === '')) {
|
|
37
|
-
throw new ApiError(400, 'invalid_request', 'bridge `parent` must be a node id or null');
|
|
38
|
-
}
|
|
39
|
-
try {
|
|
40
|
-
const node = spawnNode({ kind: 'human', parent, creator: parent, cwd, name, lifecycle: 'terminal' });
|
|
41
|
-
return { status: 200, body: { node_id: node.node_id, name: node.name } };
|
|
42
|
-
}
|
|
43
|
-
catch (error) {
|
|
44
|
-
throw new ApiError(400, 'invalid_request', String(error));
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
// POST /v1/human/tickets/:ticket_id/resolve and /cancel
|
|
48
|
-
function reviewSubmitGuidance() {
|
|
49
|
-
return new ApiError(400, 'invalid_request', 'review approvals use POST /v1/human/reviews/:review_id/submit');
|
|
50
|
-
}
|
|
51
|
-
/** The ticket resolve route accepts only a page response body. */
|
|
52
|
-
function requireResolveRequest(ctx) {
|
|
53
|
-
const request = ctx.body;
|
|
54
|
-
if (request === undefined || request === null || typeof request !== 'object' || Array.isArray(request)) {
|
|
55
|
-
throw new ApiError(400, 'invalid_request', 'ticket resolve body is required');
|
|
56
|
-
}
|
|
57
|
-
const body = request;
|
|
58
|
-
const fields = Object.keys(body);
|
|
59
|
-
if (fields.length === 1 && fields[0] === 'responses')
|
|
60
|
-
return { responses: body['responses'] };
|
|
61
|
-
if ('feedback' in body)
|
|
62
|
-
throw reviewSubmitGuidance();
|
|
63
|
-
throw new ApiError(400, 'invalid_request', 'ticket resolve body requires exactly `responses`');
|
|
64
|
-
}
|
|
65
|
-
function requirePageTicket(dir) {
|
|
66
|
-
const page = existsSync(pageManifestPath(dir));
|
|
67
|
-
const review = existsSync(reviewPath(dir));
|
|
68
|
-
if (review && !page)
|
|
69
|
-
throw reviewSubmitGuidance();
|
|
70
|
-
if (!page || review) {
|
|
71
|
-
throw new ApiError(400, 'invalid_request', 'ticket has no unambiguous page kind');
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
function invalidResolveRequest(error) {
|
|
75
|
-
const detail = error instanceof Error ? error.message : String(error);
|
|
76
|
-
if (detail === 'page_has_no_response_lifecycle')
|
|
77
|
-
return new ApiError(409, 'page_has_no_response_lifecycle', 'this page has no response lifecycle');
|
|
78
|
-
return new ApiError(400, 'invalid_request', `invalid ticket resolve body: ${detail}`);
|
|
79
|
-
}
|
|
80
|
-
function preflightResolve(validate) {
|
|
81
|
-
try {
|
|
82
|
-
return validate();
|
|
83
|
-
}
|
|
84
|
-
catch (error) {
|
|
85
|
-
throw invalidResolveRequest(error);
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
async function handleResolve(ctx) {
|
|
89
|
-
const ticketId = requireInteractionTicketId(ctx);
|
|
90
|
-
const request = requireResolveRequest(ctx);
|
|
91
|
-
const dir = ticketDir(ticketId);
|
|
92
|
-
requirePageTicket(dir);
|
|
93
|
-
const responses = preflightResolve(() => validatePageTicketResponses(dir, request.responses));
|
|
94
|
-
const replyExpected = readTicketReplyRoute(dir) !== null;
|
|
95
|
-
await resolvePageTicket(ticketId, responses);
|
|
96
|
-
return { status: 200, body: { completed: true, reply_delivered: replyExpected, kind: 'page' } };
|
|
97
|
-
}
|
|
98
|
-
function hasPublishedTicket(dir) {
|
|
99
|
-
return existsSync(pageManifestPath(dir)) || readTicketResult(dir) !== null;
|
|
100
|
-
}
|
|
101
|
-
async function handleCancel(ctx) {
|
|
102
|
-
const ticketId = requireInteractionTicketId(ctx);
|
|
103
|
-
const request = ctx.body;
|
|
104
|
-
if (request !== undefined && (typeof request !== 'object' || request === null)) {
|
|
105
|
-
throw new ApiError(400, 'invalid_request', 'ticket cancel body must be an object');
|
|
106
|
-
}
|
|
107
|
-
if (request?.disposition !== undefined && request.disposition !== 'canceled' && request.disposition !== 'dismissed') {
|
|
108
|
-
throw new ApiError(400, 'invalid_request', '`disposition` must be "canceled" or "dismissed"');
|
|
109
|
-
}
|
|
110
|
-
const dir = ticketDir(ticketId);
|
|
111
|
-
const review = getReviewByBridge(ticketId);
|
|
112
|
-
try {
|
|
113
|
-
if (review !== null) {
|
|
114
|
-
if (review.state === 'approved') {
|
|
115
|
-
throw new ApiError(409, 'ticket_already_resolved', 'ticket already resolved');
|
|
116
|
-
}
|
|
117
|
-
const finished = await cancelReview(review.review_id, request ?? {});
|
|
118
|
-
if (finished.outcome === 'already_settled') {
|
|
119
|
-
throw new ApiError(409, 'ticket_already_resolved', 'ticket already resolved');
|
|
120
|
-
}
|
|
121
|
-
return { status: 200, body: { canceled: true } };
|
|
122
|
-
}
|
|
123
|
-
// A binding row has no published ticket. It is intentionally
|
|
124
|
-
// indistinguishable from an unknown node id on this ticket surface.
|
|
125
|
-
if (!hasPublishedTicket(dir)) {
|
|
126
|
-
throw new ApiError(404, 'ticket_not_found', 'no matching ticket');
|
|
127
|
-
}
|
|
128
|
-
await cancelHumanTicket(ticketId, request ?? {});
|
|
129
|
-
return { status: 200, body: { canceled: true } };
|
|
130
|
-
}
|
|
131
|
-
catch (error) {
|
|
132
|
-
if (error instanceof ApiError)
|
|
133
|
-
throw error;
|
|
134
|
-
if (error instanceof Error && error.message === 'page_has_no_response_lifecycle') {
|
|
135
|
-
throw new ApiError(409, 'page_has_no_response_lifecycle', 'this page has no response lifecycle');
|
|
136
|
-
}
|
|
137
|
-
// Review errors are not part of the retained ticket route's vocabulary.
|
|
138
|
-
if (error instanceof ReviewOperationError) {
|
|
139
|
-
throw new ApiError(409, 'ticket_already_resolved', 'ticket already resolved');
|
|
140
|
-
}
|
|
141
|
-
throw new ApiError(500, 'internal', 'the ticket could not be canceled');
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
export const humanRoutes = [
|
|
145
|
-
{ method: 'POST', pattern: '/v1/human/bridge', handler: handleCreateBridge },
|
|
146
|
-
{ method: 'POST', pattern: '/v1/human/tickets/:ticket_id/resolve', handler: handleResolve },
|
|
147
|
-
{ method: 'POST', pattern: '/v1/human/tickets/:ticket_id/cancel', handler: handleCancel },
|
|
148
|
-
];
|
|
1
|
+
// Human page and review lifecycle routes live on request identity. The former
|
|
2
|
+
// bridge-creation and ticket resolve/cancel routes are intentionally absent.
|
|
3
|
+
export const humanRoutes = [];
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { InboxPageDTO } from '../../../api/index.js';
|
|
2
|
+
import { type HumanRequestRecord } from '../../../core/human/requests.js';
|
|
3
|
+
/** Project the one SQL-selected page revision for every page reader. */
|
|
4
|
+
export declare function inboxPageProjection(request: HumanRequestRecord): InboxPageDTO;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { readPageFeedback } from '../../../core/human/feedback.js';
|
|
3
|
+
import { pageModulePath, pagePath } from '../../../core/human/convention.js';
|
|
4
|
+
import { parsePage } from '../../../core/human/page.js';
|
|
5
|
+
import { presentationDir } from '../../../core/human/requests.js';
|
|
6
|
+
import { readPageProgress, readTicketResult } from '../../../core/human/tickets.js';
|
|
7
|
+
import { toPageFeedbackDTO } from '../map.js';
|
|
8
|
+
function pageSlotToDTO(slot) {
|
|
9
|
+
const dto = {
|
|
10
|
+
kind: slot.kind,
|
|
11
|
+
step: slot.step,
|
|
12
|
+
config: slot.config,
|
|
13
|
+
};
|
|
14
|
+
if (slot.id !== undefined)
|
|
15
|
+
dto.id = slot.id;
|
|
16
|
+
if (slot.unvalidated === true)
|
|
17
|
+
dto.unvalidated = true;
|
|
18
|
+
if (slot.display === true)
|
|
19
|
+
dto.display = true;
|
|
20
|
+
return dto;
|
|
21
|
+
}
|
|
22
|
+
function pageManifestToDTO(manifest) {
|
|
23
|
+
const dto = {
|
|
24
|
+
schema: 'crtr.page/v2',
|
|
25
|
+
dialect: manifest.dialect,
|
|
26
|
+
title: manifest.title,
|
|
27
|
+
delivery: manifest.delivery,
|
|
28
|
+
document: manifest.document,
|
|
29
|
+
steps: manifest.steps,
|
|
30
|
+
slots: manifest.slots.map(pageSlotToDTO),
|
|
31
|
+
};
|
|
32
|
+
if (manifest.subtitle !== undefined)
|
|
33
|
+
dto.subtitle = manifest.subtitle;
|
|
34
|
+
if (manifest.source !== undefined) {
|
|
35
|
+
const source = {};
|
|
36
|
+
if (manifest.source.sessionName !== undefined)
|
|
37
|
+
source.sessionName = manifest.source.sessionName;
|
|
38
|
+
if (manifest.source.askedBy !== undefined)
|
|
39
|
+
source.askedBy = manifest.source.askedBy;
|
|
40
|
+
if (manifest.source.emittedAt !== undefined)
|
|
41
|
+
source.emittedAt = manifest.source.emittedAt;
|
|
42
|
+
if (manifest.source.profileName !== undefined)
|
|
43
|
+
source.profileName = manifest.source.profileName;
|
|
44
|
+
if (manifest.source.nodeId !== undefined)
|
|
45
|
+
source.nodeId = manifest.source.nodeId;
|
|
46
|
+
if (Object.keys(source).length > 0)
|
|
47
|
+
dto.source = source;
|
|
48
|
+
}
|
|
49
|
+
return dto;
|
|
50
|
+
}
|
|
51
|
+
function state(request) {
|
|
52
|
+
if (!request.settleable)
|
|
53
|
+
return 'passive';
|
|
54
|
+
if (request.state !== 'settled')
|
|
55
|
+
return 'pending';
|
|
56
|
+
return request.outcome === 'canceled' || request.outcome === 'dismissed' ? 'canceled' : 'resolved';
|
|
57
|
+
}
|
|
58
|
+
function result(request) {
|
|
59
|
+
const terminal = readTicketResult(request.request_dir);
|
|
60
|
+
if (terminal === null)
|
|
61
|
+
return null;
|
|
62
|
+
if (terminal.kind === 'page' || terminal.kind === 'canceled') {
|
|
63
|
+
return terminal;
|
|
64
|
+
}
|
|
65
|
+
throw new Error(`page request has an invalid terminal result: ${request.request_id}`);
|
|
66
|
+
}
|
|
67
|
+
/** Project the one SQL-selected page revision for every page reader. */
|
|
68
|
+
export function inboxPageProjection(request) {
|
|
69
|
+
if (request.kind !== 'page')
|
|
70
|
+
throw new Error(`request is not a page: ${request.request_id}`);
|
|
71
|
+
const revision = presentationDir(request);
|
|
72
|
+
const manifest = parsePage(revision);
|
|
73
|
+
const sourceDocument = readFileSync(pagePath(revision, manifest.dialect), 'utf8');
|
|
74
|
+
const document = manifest.dialect === 'jsx' ? readFileSync(pageModulePath(revision), 'utf8') : sourceDocument;
|
|
75
|
+
const progress = request.settleable ? readPageProgress(request.request_dir) : null;
|
|
76
|
+
return {
|
|
77
|
+
ticket_id: request.inbox_ticket_id,
|
|
78
|
+
kind: 'page',
|
|
79
|
+
state: state(request),
|
|
80
|
+
revision,
|
|
81
|
+
page: pageManifestToDTO(manifest),
|
|
82
|
+
document,
|
|
83
|
+
source_document: sourceDocument,
|
|
84
|
+
document_media_type: manifest.dialect === 'jsx' ? 'text/jsx' : 'text/html',
|
|
85
|
+
progress: progress === null ? null : { responses: progress },
|
|
86
|
+
result: result(request),
|
|
87
|
+
feedback: toPageFeedbackDTO(readPageFeedback(request.request_dir)),
|
|
88
|
+
};
|
|
89
|
+
}
|
|
@@ -1,65 +1,22 @@
|
|
|
1
1
|
// Ticket inbox handlers — crtrd `/v1/human/inbox` (Northlight crouter-inbox
|
|
2
2
|
// v1, inbox-contract.md §A). This public ticket-serving resource enumerates,
|
|
3
3
|
// reads, responds to, and cancels tickets while preserving its product DTOs.
|
|
4
|
-
import { createHash } from 'node:crypto';
|
|
5
|
-
import { existsSync, readdirSync, realpathSync, statSync } from 'node:fs';
|
|
6
|
-
import { basename, resolve } from 'node:path';
|
|
7
4
|
import { ApiError } from '../../../api/index.js';
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import { pageManifestPath, reviewPath } from '../../../core/human/convention.js';
|
|
5
|
+
import { inboxPageProjection } from './inbox-page.js';
|
|
6
|
+
import { getRequestByInboxTicket } from '../../../core/human/requests.js';
|
|
11
7
|
import { parsePage } from '../../../core/human/page.js';
|
|
12
|
-
import { ticketsRoot } from '../../../core/human/root.js';
|
|
13
8
|
import { scanInbox, scanPageHistory } from '../../../core/human/scan.js';
|
|
14
|
-
import { readPageTicket, readTicketResult, validatePageTicketResponses, writePageProgress, } from '../../../core/human/tickets.js';
|
|
9
|
+
import { readPageTicket, readTicketResult, selectedPageDir, validatePageTicketResponses, writePageProgress, } from '../../../core/human/tickets.js';
|
|
15
10
|
import { describePageAnswer } from '../../../core/human/answer.js';
|
|
16
11
|
import { cancelHumanTicket, resolvePageTicket } from '../../human/finish.js';
|
|
17
|
-
import { filterTerminalReviewTickets } from '../../../core/review/ticket-filter.js';
|
|
18
12
|
const DEFAULT_CANCEL_REASON = 'Canceled from the inbox.';
|
|
19
13
|
const CANCEL_REASON_MAX = 1000;
|
|
20
14
|
const TICKET_ID_PATTERN = /^[a-f0-9]{64}$/;
|
|
21
|
-
// Opaque ticket id resolution
|
|
22
|
-
function ticketHash(canonicalRoot, ticketBasename) {
|
|
23
|
-
return createHash('sha256').update(`${canonicalRoot}\0${ticketBasename}`, 'utf8').digest('hex');
|
|
24
|
-
}
|
|
25
15
|
/** Resolve one opaque inbox ticket id to its canonical directory. Shared with
|
|
26
16
|
* the feedback-comment routes, which address tickets by the same ids. */
|
|
27
17
|
export function resolveTicket(ticketId) {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
canonicalRoot = realpathSync(ticketsRoot());
|
|
31
|
-
}
|
|
32
|
-
catch {
|
|
33
|
-
return null;
|
|
34
|
-
}
|
|
35
|
-
let entries;
|
|
36
|
-
try {
|
|
37
|
-
entries = readdirSync(canonicalRoot);
|
|
38
|
-
}
|
|
39
|
-
catch {
|
|
40
|
-
return null;
|
|
41
|
-
}
|
|
42
|
-
for (const entry of entries) {
|
|
43
|
-
if (ticketHash(canonicalRoot, entry) !== ticketId)
|
|
44
|
-
continue;
|
|
45
|
-
const candidate = resolve(canonicalRoot, entry);
|
|
46
|
-
let canonicalDir;
|
|
47
|
-
try {
|
|
48
|
-
if (!statSync(candidate).isDirectory())
|
|
49
|
-
continue;
|
|
50
|
-
canonicalDir = realpathSync(candidate);
|
|
51
|
-
}
|
|
52
|
-
catch {
|
|
53
|
-
continue;
|
|
54
|
-
}
|
|
55
|
-
if (resolve(canonicalDir, '..') !== canonicalRoot || basename(canonicalDir) !== entry)
|
|
56
|
-
continue;
|
|
57
|
-
if (existsSync(pageManifestPath(canonicalDir)))
|
|
58
|
-
return { ticketId: entry, dir: canonicalDir, kind: 'page' };
|
|
59
|
-
if (existsSync(reviewPath(canonicalDir)))
|
|
60
|
-
return { ticketId: entry, dir: canonicalDir, kind: 'review' };
|
|
61
|
-
}
|
|
62
|
-
return null;
|
|
18
|
+
const request = getRequestByInboxTicket(ticketId);
|
|
19
|
+
return request === null ? null : { ticketId: request.request_id, dir: request.request_dir, kind: request.kind };
|
|
63
20
|
}
|
|
64
21
|
export function requireTicketId(params) {
|
|
65
22
|
const ticketId = params['ticket_id'];
|
|
@@ -69,49 +26,6 @@ export function requireTicketId(params) {
|
|
|
69
26
|
return ticketId;
|
|
70
27
|
}
|
|
71
28
|
// Projections — humanloop canonical shapes → wire DTOs
|
|
72
|
-
function pageSlotToDTO(slot) {
|
|
73
|
-
const dto = {
|
|
74
|
-
kind: slot.kind,
|
|
75
|
-
step: slot.step,
|
|
76
|
-
config: slot.config,
|
|
77
|
-
};
|
|
78
|
-
if (slot.id !== undefined)
|
|
79
|
-
dto.id = slot.id;
|
|
80
|
-
if (slot.unvalidated === true)
|
|
81
|
-
dto.unvalidated = true;
|
|
82
|
-
if (slot.display === true)
|
|
83
|
-
dto.display = true;
|
|
84
|
-
return dto;
|
|
85
|
-
}
|
|
86
|
-
function pageManifestToDTO(manifest) {
|
|
87
|
-
const dto = {
|
|
88
|
-
schema: 'crtr.page/v2',
|
|
89
|
-
dialect: manifest.dialect,
|
|
90
|
-
title: manifest.title,
|
|
91
|
-
delivery: manifest.delivery,
|
|
92
|
-
document: manifest.document,
|
|
93
|
-
steps: manifest.steps,
|
|
94
|
-
slots: manifest.slots.map(pageSlotToDTO),
|
|
95
|
-
};
|
|
96
|
-
if (manifest.subtitle !== undefined)
|
|
97
|
-
dto.subtitle = manifest.subtitle;
|
|
98
|
-
if (manifest.source !== undefined) {
|
|
99
|
-
const source = {};
|
|
100
|
-
if (manifest.source.sessionName !== undefined)
|
|
101
|
-
source.sessionName = manifest.source.sessionName;
|
|
102
|
-
if (manifest.source.askedBy !== undefined)
|
|
103
|
-
source.askedBy = manifest.source.askedBy;
|
|
104
|
-
if (manifest.source.emittedAt !== undefined)
|
|
105
|
-
source.emittedAt = manifest.source.emittedAt;
|
|
106
|
-
if (manifest.source.profileName !== undefined)
|
|
107
|
-
source.profileName = manifest.source.profileName;
|
|
108
|
-
if (manifest.source.nodeId !== undefined)
|
|
109
|
-
source.nodeId = manifest.source.nodeId;
|
|
110
|
-
if (Object.keys(source).length > 0)
|
|
111
|
-
dto.source = source;
|
|
112
|
-
}
|
|
113
|
-
return dto;
|
|
114
|
-
}
|
|
115
29
|
function isPlainObject(value) {
|
|
116
30
|
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
117
31
|
}
|
|
@@ -164,9 +78,11 @@ function isSlotValidationError(err) {
|
|
|
164
78
|
}
|
|
165
79
|
// GET /v1/human/inbox — enumerate
|
|
166
80
|
/** The one page-summary projection: the pending list and the per-node history differ only in which tickets they walk. */
|
|
167
|
-
function pageSummaryToDTO(item
|
|
81
|
+
function pageSummaryToDTO(item) {
|
|
168
82
|
const dto = {
|
|
169
|
-
|
|
83
|
+
request_id: item.id,
|
|
84
|
+
request_dir: item.dir,
|
|
85
|
+
ticket_id: item.inboxTicketId,
|
|
170
86
|
kind: 'page',
|
|
171
87
|
title: item.title,
|
|
172
88
|
placement: item.placement,
|
|
@@ -191,16 +107,15 @@ function pageSummaryToDTO(item, canonicalRoot) {
|
|
|
191
107
|
return dto;
|
|
192
108
|
}
|
|
193
109
|
function handleList() {
|
|
194
|
-
const
|
|
195
|
-
const filtered = filterTerminalReviewTickets(allItems);
|
|
196
|
-
const canonicalRoot = realpathSync(ticketsRoot());
|
|
197
|
-
const tickets = filtered.map((item) => {
|
|
110
|
+
const tickets = scanInbox().map((item) => {
|
|
198
111
|
if (item.kind === 'page') {
|
|
199
|
-
return pageSummaryToDTO(item
|
|
112
|
+
return pageSummaryToDTO(item);
|
|
200
113
|
}
|
|
201
114
|
else if (item.kind === 'review') {
|
|
202
115
|
return {
|
|
203
|
-
|
|
116
|
+
request_id: item.id,
|
|
117
|
+
request_dir: item.dir,
|
|
118
|
+
ticket_id: item.inboxTicketId,
|
|
204
119
|
kind: 'review',
|
|
205
120
|
title: item.title,
|
|
206
121
|
subtitle: item.subtitle,
|
|
@@ -224,8 +139,7 @@ function handleHistory(ctx) {
|
|
|
224
139
|
throw new ApiError(400, 'invalid_request', 'node_id must be nonempty when present');
|
|
225
140
|
}
|
|
226
141
|
const history = scanPageHistory(nodeId ?? undefined);
|
|
227
|
-
const
|
|
228
|
-
const tickets = history.map((item) => pageSummaryToDTO(item, canonicalRoot));
|
|
142
|
+
const tickets = history.map(pageSummaryToDTO);
|
|
229
143
|
return { status: 200, body: { tickets } };
|
|
230
144
|
}
|
|
231
145
|
// GET /v1/human/inbox/:ticket_id — read a page ticket
|
|
@@ -237,28 +151,15 @@ function handleGetPage(ctx) {
|
|
|
237
151
|
if (resolved.kind === 'review') {
|
|
238
152
|
throw new ApiError(409, 'ticket_kind_unsupported', 'review tickets have no page read operation');
|
|
239
153
|
}
|
|
240
|
-
|
|
154
|
+
const request = getRequestByInboxTicket(ticketId);
|
|
155
|
+
if (request === null || request.kind !== 'page')
|
|
156
|
+
throw new ApiError(404, 'ticket_not_found', 'no matching ticket');
|
|
241
157
|
try {
|
|
242
|
-
|
|
158
|
+
return { status: 200, body: inboxPageProjection(request) };
|
|
243
159
|
}
|
|
244
|
-
catch
|
|
160
|
+
catch {
|
|
245
161
|
throw new ApiError(500, 'internal', 'the ticket could not be read');
|
|
246
162
|
}
|
|
247
|
-
const progress = ticket.progress;
|
|
248
|
-
const progressDTO = progress === null ? null : { responses: progress };
|
|
249
|
-
return {
|
|
250
|
-
status: 200,
|
|
251
|
-
body: {
|
|
252
|
-
ticket_id: ticketId,
|
|
253
|
-
kind: 'page',
|
|
254
|
-
state: ticket.state,
|
|
255
|
-
page: pageManifestToDTO(ticket.manifest),
|
|
256
|
-
document: ticket.manifest.dialect === 'jsx' ? ticket.module : ticket.document,
|
|
257
|
-
document_media_type: ticket.manifest.dialect === 'jsx' ? 'text/jsx' : 'text/html',
|
|
258
|
-
progress: progressDTO,
|
|
259
|
-
feedback: toPageFeedbackDTO(readPageFeedback(resolved.dir)),
|
|
260
|
-
},
|
|
261
|
-
};
|
|
262
163
|
}
|
|
263
164
|
// POST /v1/human/inbox/:ticket_id/respond — submit
|
|
264
165
|
async function handleRespond(ctx) {
|
|
@@ -382,7 +283,7 @@ function handleGetResponse(ctx) {
|
|
|
382
283
|
throw new ApiError(409, 'ticket_kind_mismatch', 'unexpected result kind');
|
|
383
284
|
}
|
|
384
285
|
try {
|
|
385
|
-
const manifest = parsePage(resolved.dir);
|
|
286
|
+
const manifest = parsePage(selectedPageDir(resolved.dir));
|
|
386
287
|
return { status: 200, body: { ...result, answer: describePageAnswer(manifest, result.responses, { completedAt: result.completedAt }) } };
|
|
387
288
|
}
|
|
388
289
|
catch {
|
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
// inbox message now (201) or fresh-revives with no inbox entry. `{id}` is the
|
|
3
3
|
// target node.
|
|
4
4
|
import { join } from 'node:path';
|
|
5
|
-
import {
|
|
5
|
+
import { claimNodeMail, acknowledgeNodeMail } from '../../../core/canvas/deliveries.js';
|
|
6
|
+
import { nodeMailEntry } from '../../../core/feed/inbox.js';
|
|
7
|
+
import { enqueueNodeMail, cancelPendingNodeMail } from '../../../core/feed/messages.js';
|
|
6
8
|
import { reviveNode } from '../../../core/runtime/revive.js';
|
|
7
9
|
import { BrokerUnreachableError } from '../../../core/runtime/broker-request.js';
|
|
8
10
|
import { isBrokerLive } from '../../../core/runtime/model-swap.js';
|
|
@@ -319,23 +321,25 @@ async function handleMessage(ctx) {
|
|
|
319
321
|
const messageBody = hasBody
|
|
320
322
|
? req.body
|
|
321
323
|
: 'A one-off structured-output request has been granted. Submit a result matching the requested schema with `crtr push result` before you stop; after it is accepted, continue normally.';
|
|
322
|
-
return
|
|
323
|
-
from,
|
|
324
|
-
tier,
|
|
324
|
+
return enqueueNodeMail(id, {
|
|
325
|
+
senderNodeId: from,
|
|
326
|
+
urgency: tier,
|
|
327
|
+
wake: 1,
|
|
325
328
|
kind: 'message',
|
|
326
329
|
label: label(messageBody),
|
|
327
|
-
|
|
330
|
+
bodyJson: { body: messageBody, ...(hasSidecar ? { situational: true } : {}), ...cardData },
|
|
328
331
|
});
|
|
329
332
|
}
|
|
330
333
|
// Context-only: a hidden wake marker excluded from the visible digest. Its
|
|
331
334
|
// one-shot cards have no visible delivery to ride, so the watcher's context
|
|
332
335
|
// channel carries them.
|
|
333
|
-
return
|
|
334
|
-
from,
|
|
335
|
-
tier,
|
|
336
|
+
return enqueueNodeMail(id, {
|
|
337
|
+
senderNodeId: from,
|
|
338
|
+
urgency: tier,
|
|
339
|
+
wake: 1,
|
|
336
340
|
kind: 'message',
|
|
337
341
|
label: hasSidecar ? '(ambient context updated)' : '(context delivered)',
|
|
338
|
-
|
|
342
|
+
bodyJson: { ...(hasSidecar ? { situational: true } : {}), situationalOnly: true, ...cardData },
|
|
339
343
|
});
|
|
340
344
|
};
|
|
341
345
|
// Deferred guard: a done/canceled/finalized target has no natural
|
|
@@ -364,14 +368,14 @@ async function handleMessage(ctx) {
|
|
|
364
368
|
// Wake-capable durable mail wins the same park-completion boundary as a live
|
|
365
369
|
// broker input. A completion that won before this append is handled by the
|
|
366
370
|
// fresh row read below, which revives the now-parked node.
|
|
367
|
-
if (entry.
|
|
371
|
+
if (entry.urgency !== 'deferred')
|
|
368
372
|
withCanvasWrite(() => recordPendingParkActivity(id));
|
|
369
373
|
const current = getNode(id);
|
|
370
374
|
if (current === null)
|
|
371
375
|
throw notFound(`unknown node: ${id}`, { received: id });
|
|
372
376
|
// Deferred mail normally waits for a natural cycle, but a frozen row already
|
|
373
377
|
// owes a thaw; consume its deadline when that durable future wake arrives.
|
|
374
|
-
if (
|
|
378
|
+
if (meta.frozen_at !== null)
|
|
375
379
|
cancelCronsOnWake(id);
|
|
376
380
|
// A wake-capable entry for an active or idle target is admitted by the
|
|
377
381
|
// lifecycle tick. Reopen delivery preserves this handler's synchronous wake
|
|
@@ -380,7 +384,7 @@ async function handleMessage(ctx) {
|
|
|
380
384
|
let revived = false;
|
|
381
385
|
let frozen = false;
|
|
382
386
|
const needsSynchronousWake = req.reopen || current.lifecycle === 'terminal' || !wantsExecution(current);
|
|
383
|
-
if (needsSynchronousWake && entry.
|
|
387
|
+
if (needsSynchronousWake && entry.urgency !== 'deferred' && !paused && !isBrokerLive(current)) {
|
|
384
388
|
try {
|
|
385
389
|
// The entry is already durable, so a wake denied for capacity is only
|
|
386
390
|
// delayed: the row freezes and the tick relaunches it — at which point
|
|
@@ -398,8 +402,8 @@ async function handleMessage(ctx) {
|
|
|
398
402
|
delivered: true,
|
|
399
403
|
revived,
|
|
400
404
|
...(frozen ? { not_revived_reason: 'capacity_frozen' } : {}),
|
|
401
|
-
delivered_at: entry.
|
|
402
|
-
...(entry.
|
|
405
|
+
delivered_at: entry.createdAt,
|
|
406
|
+
...(entry.urgency === tier ? {} : { delivered_tier: entry.urgency }),
|
|
403
407
|
...(req.delivery === 'interactive' ? { delivered_via: 'inbox' } : {}),
|
|
404
408
|
};
|
|
405
409
|
return { status: 201, body };
|
|
@@ -417,7 +421,7 @@ async function handleInterrupt(ctx) {
|
|
|
417
421
|
// 1. Boot-window close: mark undelivered human-send inbox entries canceled so
|
|
418
422
|
// a send riding the durable path (dormant target / mid-revive fallback) is
|
|
419
423
|
// never injected after the Esc — the watcher skips canceled entries.
|
|
420
|
-
const canceled =
|
|
424
|
+
const canceled = cancelPendingNodeMail(id, { senderNodeId: 'human', kind: 'message' });
|
|
421
425
|
// 2. Abort whatever is live. The broker acks once processed; on its single
|
|
422
426
|
// frame loop that ack also implies every earlier-accepted deliver was
|
|
423
427
|
// already routed, so a just-started turn is caught, not missed.
|
|
@@ -442,6 +446,60 @@ async function handleInterrupt(ctx) {
|
|
|
442
446
|
};
|
|
443
447
|
return { status: 200, body };
|
|
444
448
|
}
|
|
449
|
+
function mailBody(ctx) {
|
|
450
|
+
if (typeof ctx.body !== 'object' || ctx.body === null || Array.isArray(ctx.body))
|
|
451
|
+
throw usage('mail requires an object body');
|
|
452
|
+
const body = ctx.body;
|
|
453
|
+
if (typeof body['execution_id'] !== 'string' || body['execution_id'].trim() === '')
|
|
454
|
+
throw usage('execution_id is required');
|
|
455
|
+
return body;
|
|
456
|
+
}
|
|
457
|
+
function handleMailClaim(ctx) {
|
|
458
|
+
const body = mailBody(ctx);
|
|
459
|
+
const channel = body['channel'];
|
|
460
|
+
if (channel !== 'wake' && channel !== 'passive')
|
|
461
|
+
throw usage('channel must be wake or passive');
|
|
462
|
+
const result = claimNodeMail(ctx.params['id'], body['execution_id'], channel);
|
|
463
|
+
const projected = {
|
|
464
|
+
action: result.action,
|
|
465
|
+
deliveries: result.deliveries.map((delivery) => ({
|
|
466
|
+
delivery_id: delivery.deliveryId,
|
|
467
|
+
attempts: delivery.attempts,
|
|
468
|
+
handoff: delivery.handoff,
|
|
469
|
+
entry: nodeMailEntry(delivery),
|
|
470
|
+
})),
|
|
471
|
+
};
|
|
472
|
+
return { status: 200, body: projected };
|
|
473
|
+
}
|
|
474
|
+
function handleMailAcknowledge(ctx) {
|
|
475
|
+
const body = mailBody(ctx);
|
|
476
|
+
if (!Array.isArray(body['deliveries']))
|
|
477
|
+
throw usage('deliveries must be an array');
|
|
478
|
+
const receipts = body['deliveries'].map((value) => {
|
|
479
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value))
|
|
480
|
+
throw usage('each delivery must be an object');
|
|
481
|
+
const receipt = value;
|
|
482
|
+
if (typeof receipt['delivery_id'] !== 'string' || receipt['delivery_id'] === '')
|
|
483
|
+
throw usage('delivery_id is required');
|
|
484
|
+
if (!Number.isSafeInteger(receipt['attempts']) || receipt['attempts'] < 1)
|
|
485
|
+
throw usage('attempts must be a positive integer');
|
|
486
|
+
if (receipt['disposition'] !== 'acknowledged' && receipt['disposition'] !== 'released')
|
|
487
|
+
throw usage('disposition must be acknowledged or released');
|
|
488
|
+
return { delivery_id: receipt['delivery_id'], attempts: receipt['attempts'], disposition: receipt['disposition'] };
|
|
489
|
+
});
|
|
490
|
+
const result = acknowledgeNodeMail(ctx.params['id'], body['execution_id'], receipts.map((receipt) => ({
|
|
491
|
+
deliveryId: receipt.delivery_id, attempts: receipt.attempts, disposition: receipt.disposition,
|
|
492
|
+
})));
|
|
493
|
+
const projected = {
|
|
494
|
+
action: result.action,
|
|
495
|
+
results: result.results.map((result) => ({ delivery_id: result.deliveryId, outcome: result.outcome })),
|
|
496
|
+
};
|
|
497
|
+
return { status: 200, body: projected };
|
|
498
|
+
}
|
|
499
|
+
export const brokerMailRoutes = [
|
|
500
|
+
{ method: 'POST', pattern: '/v1/nodes/:id/mail/claim', handler: handleMailClaim },
|
|
501
|
+
{ method: 'POST', pattern: '/v1/nodes/:id/mail/acknowledge', handler: handleMailAcknowledge },
|
|
502
|
+
];
|
|
445
503
|
export const messageRoutes = [
|
|
446
504
|
{ method: 'POST', pattern: '/v1/nodes/:id/messages', handler: handleMessage },
|
|
447
505
|
{ method: 'POST', pattern: '/v1/nodes/:id/interrupt', handler: handleInterrupt },
|