@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
|
@@ -2,8 +2,10 @@
|
|
|
2
2
|
import { setTimeout as sleep } from 'node:timers/promises';
|
|
3
3
|
import { ApiError } from '../../../api/errors.js';
|
|
4
4
|
import { getNode } from '../../../core/canvas/canvas.js';
|
|
5
|
-
import {
|
|
5
|
+
import { armExternalActionDelivery, activateArmedExternalActionDelivery, readExternalActionDelivery } from '../../../core/canvas/deliveries.js';
|
|
6
|
+
import { withCanvasWrite } from '../../../core/canvas/db.js';
|
|
6
7
|
import { OUTCOME_PAYLOAD_MAX_BYTES } from '../../../core/canvas/types.js';
|
|
8
|
+
import { composeNodeOutcomeDocument } from '../../../core/runtime/outcome-document.js';
|
|
7
9
|
import { HUMAN_ACTION_NAME_PATTERN } from '../../../core/human/action-binding.js';
|
|
8
10
|
import { resolveHumanAction } from '../../../core/human-actions.js';
|
|
9
11
|
import { toNodeOutcomeDTO, toOutcomeDeliveryDTO } from '../map.js';
|
|
@@ -82,6 +84,53 @@ function parseRegistration(body) {
|
|
|
82
84
|
}
|
|
83
85
|
return body['payload'] === undefined ? { action } : { action, payload: body['payload'] };
|
|
84
86
|
}
|
|
87
|
+
function outcomeKey(nodeId) { return `node-outcome:${nodeId}`; }
|
|
88
|
+
function outcomeView(row) {
|
|
89
|
+
const adapter = row.adapter;
|
|
90
|
+
if (adapter?.adapter !== 'subprocess' || !Array.isArray(adapter.argv) || !adapter.argv.every((arg) => typeof arg === 'string') || typeof adapter.cwd !== 'string')
|
|
91
|
+
throw new Error(`outcome delivery ${row.deliveryId} has an invalid subprocess adapter`);
|
|
92
|
+
return { nodeId: row.idempotencyKey?.slice('node-outcome:'.length) ?? '', state: row.state === 'handed_off' ? 'running' : row.state === 'acknowledged' ? 'accepted' : row.state, attempt: row.attempts, actionName: row.destinationId, argv: adapter.argv, cwd: adapter.cwd, configOrigin: typeof adapter.config_origin === 'string' ? adapter.config_origin : '', payload: adapter.payload ?? null, document: null, nextAttemptAt: row.nextAttemptAt ?? 0, claimedAt: row.claimedAt, claimOwner: row.claimOwner, acceptedAt: row.acknowledgedAt, permanentFailedAt: row.failedAt, lastFailure: row.lastFailure, createdAt: row.createdAt, updatedAt: row.updatedAt };
|
|
93
|
+
}
|
|
94
|
+
function nodeAtOutcome(node) {
|
|
95
|
+
const reason = node.outcome_reason;
|
|
96
|
+
let status;
|
|
97
|
+
let intent;
|
|
98
|
+
if (node.outcome_kind === 'result' || reason === 'finished' || reason === 'declined') {
|
|
99
|
+
status = 'done';
|
|
100
|
+
intent = 'done';
|
|
101
|
+
}
|
|
102
|
+
else if (reason === 'parked') {
|
|
103
|
+
status = 'done';
|
|
104
|
+
intent = 'parked';
|
|
105
|
+
}
|
|
106
|
+
else if (reason === 'closed' || reason === 'retired' || reason === 'stranded' || reason === 'deadline_exceeded') {
|
|
107
|
+
status = 'canceled';
|
|
108
|
+
intent = null;
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
status = 'dead';
|
|
112
|
+
intent = null;
|
|
113
|
+
}
|
|
114
|
+
return { ...node, status, intent, terminal_reason: reason };
|
|
115
|
+
}
|
|
116
|
+
function armOutcomeExternalAction(node, target, payload) {
|
|
117
|
+
return withCanvasWrite((db) => {
|
|
118
|
+
const existing = readExternalActionDelivery(outcomeKey(node.node_id));
|
|
119
|
+
if (existing !== null && existing.state !== 'armed')
|
|
120
|
+
return null;
|
|
121
|
+
armExternalActionDelivery(db, { destinationId: target.action, adapter: { adapter: 'subprocess', argv: target.argv, cwd: target.cwd, config_origin: target.configOrigin, payload: payload ?? null }, idempotencyKey: outcomeKey(node.node_id) });
|
|
122
|
+
if (node.outcome_at !== null) {
|
|
123
|
+
if (node.outcome_kind === null || node.outcome_reason === null)
|
|
124
|
+
throw new Error(`outcome latch is incomplete for node ${node.node_id}`);
|
|
125
|
+
const document = JSON.stringify(composeNodeOutcomeDocument({ node: nodeAtOutcome(node), outcome: { kind: node.outcome_kind, reason: node.outcome_reason, at: node.outcome_at, revision: node.outcome_revision, detailJson: node.outcome_detail_json ?? null }, action: { name: target.action, payload: payload ?? null }, finalReport: node.final_report }));
|
|
126
|
+
activateArmedExternalActionDelivery(db, { idempotencyKey: outcomeKey(node.node_id), label: node.node_id, bodyJson: document, supersede: false });
|
|
127
|
+
}
|
|
128
|
+
const delivery = readExternalActionDelivery(outcomeKey(node.node_id));
|
|
129
|
+
if (delivery === null)
|
|
130
|
+
throw new Error(`outcome delivery was not registered for ${node.node_id}`);
|
|
131
|
+
return outcomeView(delivery);
|
|
132
|
+
});
|
|
133
|
+
}
|
|
85
134
|
function resolveAction(action, cwd) {
|
|
86
135
|
const resolution = resolveHumanAction(action, cwd);
|
|
87
136
|
if (!('kind' in resolution))
|
|
@@ -97,14 +146,7 @@ function handlePutDelivery(ctx) {
|
|
|
97
146
|
const node = requireNode(id);
|
|
98
147
|
const request = parseRegistration(ctx.body);
|
|
99
148
|
const target = resolveAction(request.action, node.cwd);
|
|
100
|
-
const delivery =
|
|
101
|
-
nodeId: node.node_id,
|
|
102
|
-
actionName: request.action,
|
|
103
|
-
argv: target.argv,
|
|
104
|
-
cwd: target.cwd,
|
|
105
|
-
configOrigin: target.configOrigin,
|
|
106
|
-
...(request.payload === undefined ? {} : { payload: request.payload }),
|
|
107
|
-
});
|
|
149
|
+
const delivery = armOutcomeExternalAction(node, { action: request.action, ...target }, request.payload);
|
|
108
150
|
if (delivery === null) {
|
|
109
151
|
throw new ApiError(409, 'outcome_delivery_settled', 'outcome delivery has already started or settled');
|
|
110
152
|
}
|
|
@@ -113,19 +155,22 @@ function handlePutDelivery(ctx) {
|
|
|
113
155
|
/** GET /v1/nodes/:id/outcome-delivery — inspect the one durable registration. */
|
|
114
156
|
function handleGetDelivery(ctx) {
|
|
115
157
|
const id = ctx.params['id'] ?? '';
|
|
116
|
-
const delivery =
|
|
158
|
+
const delivery = readExternalActionDelivery(outcomeKey(id));
|
|
117
159
|
if (delivery === null)
|
|
118
160
|
throw new ApiError(404, 'outcome_delivery_not_found', `no outcome delivery for node ${id}`);
|
|
119
|
-
return { status: 200, body: toOutcomeDeliveryDTO(delivery) };
|
|
161
|
+
return { status: 200, body: toOutcomeDeliveryDTO(outcomeView(delivery)) };
|
|
120
162
|
}
|
|
121
163
|
/** DELETE /v1/nodes/:id/outcome-delivery — disarm only before delivery begins. */
|
|
122
164
|
function handleDeleteDelivery(ctx) {
|
|
123
165
|
const id = ctx.params['id'] ?? '';
|
|
124
|
-
const current =
|
|
166
|
+
const current = readExternalActionDelivery(outcomeKey(id));
|
|
125
167
|
if (current !== null && current.state !== 'armed') {
|
|
126
168
|
throw new ApiError(409, 'outcome_delivery_settled', 'outcome delivery has already started or settled');
|
|
127
169
|
}
|
|
128
|
-
|
|
170
|
+
if (current !== null)
|
|
171
|
+
withCanvasWrite((db) => {
|
|
172
|
+
db.prepare("DELETE FROM deliveries WHERE delivery_id = ? AND state = 'armed'").run(current.deliveryId);
|
|
173
|
+
});
|
|
129
174
|
return { status: 204 };
|
|
130
175
|
}
|
|
131
176
|
export const nodeOutcomeRoutes = [
|
|
@@ -6,6 +6,7 @@ interface NodeHandlerDeps {
|
|
|
6
6
|
export { resolveCreateKind } from '../../../core/runtime/launch-target.js';
|
|
7
7
|
export declare function handleCreate(ctx: RequestContext, deps?: NodeHandlerDeps): Promise<HandlerResult>;
|
|
8
8
|
export declare function handleList(ctx: RequestContext): HandlerResult;
|
|
9
|
+
export declare function handleFork(ctx: RequestContext): Promise<HandlerResult>;
|
|
9
10
|
export declare function handlePromote(ctx: RequestContext, deps?: NodeHandlerDeps): Promise<HandlerResult>;
|
|
10
11
|
export declare function handleYield(ctx: RequestContext, deps?: NodeHandlerDeps): Promise<HandlerResult>;
|
|
11
12
|
export declare function handleConfig(ctx: RequestContext, deps?: NodeHandlerDeps): Promise<HandlerResult>;
|
|
@@ -13,9 +13,11 @@ import { appendSituationalContext, formatSituationalProse } from '../../../core/
|
|
|
13
13
|
import { closeNode } from '../../../core/runtime/close.js';
|
|
14
14
|
import { reviveNode } from '../../../core/runtime/revive.js';
|
|
15
15
|
import { nowIso } from '../../../core/fs-utils.js';
|
|
16
|
-
import { assertLaunchModelRegistered, forkNode,
|
|
16
|
+
import { assertLaunchModelRegistered, forkNode, spawnChildPrepared } from '../../../core/runtime/spawn.js';
|
|
17
17
|
import { childrenOf, getNode, listNodes, subscribersOf, subscriptionsOf, setMessageWait, updateNode } from '../../../core/canvas/canvas.js';
|
|
18
18
|
import { subtreeIds } from '../../../core/canvas/nav-model.js';
|
|
19
|
+
import { withCanvasWrite } from '../../../core/canvas/db.js';
|
|
20
|
+
import { unbindSession } from '../../../core/canvas/sessions.js';
|
|
19
21
|
import { ticketCountsForNodes } from '../../../core/canvas/attention.js';
|
|
20
22
|
import { contextDir, reportsDir } from '../../../core/canvas/paths.js';
|
|
21
23
|
import { nodeArtifacts } from '../../../core/canvas/history.js';
|
|
@@ -32,8 +34,6 @@ import { renameWindow } from '../../../core/runtime/placement.js';
|
|
|
32
34
|
import { buildLaunchSpecAsync, isProviderPinnedModelToken, normalizeModel, readMergedLaunchConfigAsync } from '../../../core/runtime/launch.js';
|
|
33
35
|
import { modelRequestFromConfig } from '../../../core/model-routes.js';
|
|
34
36
|
import { BrokerUnreachableError } from '../../../core/runtime/broker-request.js';
|
|
35
|
-
import { readFault } from '../../../core/runtime/fault.js';
|
|
36
|
-
import { activeFaultForDisplay } from '../../../core/canvas/render-source.js';
|
|
37
37
|
import { isBrokerLive, persistDormantModel, setModelLive } from '../../../core/runtime/model-swap.js';
|
|
38
38
|
import { boundFleet } from '../../../core/runtime/fleet.js';
|
|
39
39
|
import { writeOutputSchema } from '../../../core/runtime/structured-output.js';
|
|
@@ -72,16 +72,7 @@ function edgesFor(id) {
|
|
|
72
72
|
/** Re-read a node fresh and project its detail DTO (post-action response). */
|
|
73
73
|
function detailOf(id) {
|
|
74
74
|
const meta = requireMeta(id);
|
|
75
|
-
|
|
76
|
-
return {
|
|
77
|
-
...toNodeDetailDTO(meta, edgesFor(id)),
|
|
78
|
-
fault: fault === null ? null : {
|
|
79
|
-
link: fault.link,
|
|
80
|
-
kind: fault.kind,
|
|
81
|
-
retry: { disposition: fault.retry.disposition },
|
|
82
|
-
since: fault.since,
|
|
83
|
-
},
|
|
84
|
-
};
|
|
75
|
+
return toNodeDetailDTO(meta, edgesFor(id));
|
|
85
76
|
}
|
|
86
77
|
/** Count context + report files under a node (the context-roster `files`). */
|
|
87
78
|
function countFiles(id) {
|
|
@@ -298,32 +289,39 @@ export async function handleCreate(ctx, deps = {}) {
|
|
|
298
289
|
const resolvedReq = { ...req, kind };
|
|
299
290
|
const resolvedOutcomeDelivery = outcomeDelivery === undefined ? undefined : resolveOutcomeDelivery(outcomeDelivery, cwd);
|
|
300
291
|
await assertLaunchModelRegistered(requestFromLaunch(launch), { cwd, profileId }, deps.modelRegistry);
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
const
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
if (
|
|
313
|
-
|
|
314
|
-
|
|
292
|
+
let warmRefill = null;
|
|
293
|
+
{
|
|
294
|
+
// --- Warm path: hand out an already-booted spare instead of paying a full
|
|
295
|
+
// engine boot. A miss is not a failure — it falls through to the cold
|
|
296
|
+
// spawn below and mints the spare that serves the NEXT create. ---
|
|
297
|
+
const warm = warmRequestFor(resolvedReq, cwd, profileId);
|
|
298
|
+
if (warm !== null) {
|
|
299
|
+
const claimed = await claimWarmNode(warm, {
|
|
300
|
+
...(deadline === undefined ? {} : { deadlineAt: deadline }),
|
|
301
|
+
...(resolvedOutcomeDelivery === undefined ? {} : { outcomeDelivery: resolvedOutcomeDelivery }),
|
|
302
|
+
});
|
|
303
|
+
if (claimed !== null) {
|
|
304
|
+
refillWarmPool(warm);
|
|
305
|
+
if (schema !== null)
|
|
306
|
+
writeOutputSchema(claimed, 'terminal', schema);
|
|
307
|
+
return { status: 201, body: detailOf(claimed) };
|
|
308
|
+
}
|
|
309
|
+
warmRefill = warm;
|
|
315
310
|
}
|
|
311
|
+
const recipe = buildRecipe(resolvedReq, parent, cwd);
|
|
312
|
+
if (deadline !== undefined)
|
|
313
|
+
recipe.deadlineAt = deadline;
|
|
314
|
+
if (resolvedOutcomeDelivery !== undefined)
|
|
315
|
+
recipe.outcomeDelivery = resolvedOutcomeDelivery;
|
|
316
|
+
recipe.readiness = req.root === true ? 'await' : 'launch';
|
|
317
|
+
const result = await spawnChildPrepared(recipe, undefined, () => {
|
|
318
|
+
if (warmRefill !== null)
|
|
319
|
+
refillWarmPool(warmRefill);
|
|
320
|
+
});
|
|
321
|
+
if (schema !== null)
|
|
322
|
+
writeOutputSchema(result.node.node_id, 'terminal', schema);
|
|
323
|
+
return { status: 201, body: detailOf(result.node.node_id) };
|
|
316
324
|
}
|
|
317
|
-
const recipe = buildRecipe(resolvedReq, parent, cwd);
|
|
318
|
-
if (deadline !== undefined)
|
|
319
|
-
recipe.deadlineAt = deadline;
|
|
320
|
-
if (resolvedOutcomeDelivery !== undefined)
|
|
321
|
-
recipe.outcomeDelivery = resolvedOutcomeDelivery;
|
|
322
|
-
recipe.readiness = req.root === true ? 'await' : 'launch';
|
|
323
|
-
const result = await spawnChild(recipe);
|
|
324
|
-
if (schema !== null)
|
|
325
|
-
writeOutputSchema(result.node.node_id, 'terminal', schema);
|
|
326
|
-
return { status: 201, body: detailOf(result.node.node_id) };
|
|
327
325
|
}
|
|
328
326
|
// GET /v1/nodes — list (filters) ; GET /v1/nodes/{id} — detail
|
|
329
327
|
function singleQueryValue(ctx, name) {
|
|
@@ -557,10 +555,8 @@ function handleArtifacts(ctx) {
|
|
|
557
555
|
return { status: 200, body };
|
|
558
556
|
}
|
|
559
557
|
// Lifecycle verbs
|
|
560
|
-
async function handleFork(ctx) {
|
|
561
|
-
const
|
|
562
|
-
requireMeta(id);
|
|
563
|
-
const result = await forkNode(id);
|
|
558
|
+
export async function handleFork(ctx) {
|
|
559
|
+
const result = await forkNode(ctx.params['id']);
|
|
564
560
|
return { status: 201, body: detailOf(result.node.node_id) };
|
|
565
561
|
}
|
|
566
562
|
async function handleRevive(ctx) {
|
|
@@ -831,7 +827,10 @@ export async function handleConfig(ctx, deps = {}) {
|
|
|
831
827
|
next: 'Create the replacement directory or send an existing absolute directory.',
|
|
832
828
|
});
|
|
833
829
|
}
|
|
834
|
-
|
|
830
|
+
withCanvasWrite(() => {
|
|
831
|
+
updateNode(id, { cwd: resolved });
|
|
832
|
+
unbindSession(id);
|
|
833
|
+
});
|
|
835
834
|
return { status: 200, body: detailOf(id) };
|
|
836
835
|
}
|
|
837
836
|
let meta = requireMeta(id);
|
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
// Canonical daemon-owned review lifecycle routes. Handlers validate the full
|
|
2
2
|
// wire request, delegate lifecycle work to review services, and project only
|
|
3
3
|
// committed daemon state.
|
|
4
|
-
import { isSafeNodeId
|
|
5
|
-
import { responsePath } from '../../../core/human/convention.js';
|
|
6
|
-
import { ticketDir } from '../../../core/human/root.js';
|
|
4
|
+
import { isSafeNodeId } from '../../../core/canvas/paths.js';
|
|
7
5
|
import { createReview } from '../../../core/review/birth.js';
|
|
8
|
-
import { readAnchorBase,
|
|
9
|
-
import { ReviewOperationError } from '../../../core/review/types.js';
|
|
6
|
+
import { readAnchorBase, listReviews, requireVisibleReview } from '../../../core/review/store.js';
|
|
10
7
|
import { cancelReview, submitReviewApproval } from '../../review/finish.js';
|
|
11
8
|
import { toFeedbackResultDTO, toReviewDTO } from '../map.js';
|
|
12
9
|
import { invalidRequest as rejectRequest, objectBody, optionalString, requireParam, requiredString, } from './validate.js';
|
|
@@ -19,20 +16,9 @@ function invalidRequest(violations) {
|
|
|
19
16
|
function requireReviewId(ctx, violations) {
|
|
20
17
|
return requireParam(ctx, 'review_id', 'must be a safe review id', isSafeNodeId, violations);
|
|
21
18
|
}
|
|
22
|
-
function requireBridgeNodeId(ctx, violations) {
|
|
23
|
-
return requireParam(ctx, 'bridge_node_id', 'must be a safe node id', isSafeNodeId, violations);
|
|
24
|
-
}
|
|
25
|
-
function approvedResultPath(review) {
|
|
26
|
-
if (review.origin_kind === 'inline')
|
|
27
|
-
return reviewResultPath(review.review_id);
|
|
28
|
-
if (review.bridge_node_id === null)
|
|
29
|
-
throw new Error(`approved ticket review lacks its bridge node: ${review.review_id}`);
|
|
30
|
-
return responsePath(ticketDir(review.bridge_node_id));
|
|
31
|
-
}
|
|
32
19
|
function toReviewResponseDTO(review) {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
: toReviewDTO(review);
|
|
20
|
+
const dto = toReviewDTO(review, review.state === 'approved' ? { result_path: `${review.review_dir}/result.json` } : {});
|
|
21
|
+
return { ...dto, review_dir: review.review_dir };
|
|
36
22
|
}
|
|
37
23
|
function parseCreate(ctx) {
|
|
38
24
|
const violations = [];
|
|
@@ -158,16 +144,6 @@ function handleRead(ctx) {
|
|
|
158
144
|
invalidRequest(violations);
|
|
159
145
|
return { status: 200, body: toReviewResponseDTO(requireVisibleReview(reviewId)) };
|
|
160
146
|
}
|
|
161
|
-
function handleByBridge(ctx) {
|
|
162
|
-
const violations = [];
|
|
163
|
-
const bridgeNodeId = requireBridgeNodeId(ctx, violations);
|
|
164
|
-
if (violations.length > 0 || bridgeNodeId === undefined)
|
|
165
|
-
invalidRequest(violations);
|
|
166
|
-
const review = getReviewByBridge(bridgeNodeId);
|
|
167
|
-
if (review !== null)
|
|
168
|
-
return { status: 200, body: toReviewResponseDTO(review) };
|
|
169
|
-
throw new ReviewOperationError('unknown_review', 'review was not found', { received: bridgeNodeId });
|
|
170
|
-
}
|
|
171
147
|
async function handleSubmit(ctx) {
|
|
172
148
|
const violations = [];
|
|
173
149
|
const reviewId = requireReviewId(ctx, violations);
|
|
@@ -217,7 +193,6 @@ function handleDocument(ctx) {
|
|
|
217
193
|
export const reviewRoutes = [
|
|
218
194
|
{ method: 'POST', pattern: '/v1/human/reviews', handler: handleCreate },
|
|
219
195
|
{ method: 'GET', pattern: '/v1/human/reviews', handler: handleList },
|
|
220
|
-
{ method: 'GET', pattern: '/v1/human/reviews/by-bridge/:bridge_node_id', handler: handleByBridge },
|
|
221
196
|
{ method: 'GET', pattern: '/v1/human/reviews/:review_id', handler: handleRead },
|
|
222
197
|
{ method: 'POST', pattern: '/v1/human/reviews/:review_id/submit', handler: handleSubmit },
|
|
223
198
|
{ method: 'POST', pattern: '/v1/human/reviews/:review_id/cancel', handler: handleCancel },
|
package/dist/daemon/api/map.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type { ManagedWorktree, NodeMeta, NodeRow, NodeRuntime, SubscriptionRef } from '../../core/canvas/types.js';
|
|
2
|
-
import type { OutcomeDeliveryRecord } from '../../core/canvas/node-outcome-deliveries.js';
|
|
3
2
|
import type { ReviewComment, ReviewCommentEvent, ReviewErrorCode, ReviewRecord, ReviewResult } from '../../core/review/types.js';
|
|
4
3
|
import { type Cron, type CronRunRecord } from '../../core/canvas/crons.js';
|
|
5
4
|
import type { ProfileEntry } from '../../core/profiles/manifest.js';
|
|
@@ -7,11 +6,34 @@ import type { ReviveResult } from '../../core/runtime/revive.js';
|
|
|
7
6
|
import type { CloseNodeResult } from '../../core/runtime/close.js';
|
|
8
7
|
import { type PushResult } from '../../core/feed/feed.js';
|
|
9
8
|
import type { PageFeedback, PageFeedbackComment } from '../../core/human/feedback.js';
|
|
10
|
-
import type {
|
|
9
|
+
import type { OnDiskMigrationRunResult } from '../../migrations/runner.js';
|
|
10
|
+
import type { CloseResultDTO, CronDTO, CronRunDTO, ErrorBody, NodeEdgesDTO, NodeOutcomeDTO, NodePathsDTO, NodeStatusDTO, OutcomeDeliveryDTO, NodeSummaryDTO, NodeDetailDTO, NodeWorktreeDTO, ProfileDTO, ReviewCommentDTO, ReviewCommentEventDTO, ReviewDTO, FeedbackResultDTO, PageFeedbackCommentDTO, PageFeedbackDTO, PushReportResultDTO, ReviveResultDTO, MigrateStateDTO, SubscriptionDTO } from '../../api/index.js';
|
|
11
|
+
export declare function toMigrateStateDTO(result: OnDiskMigrationRunResult, options: {
|
|
12
|
+
resumed: boolean;
|
|
13
|
+
resumeError?: string;
|
|
14
|
+
}): MigrateStateDTO;
|
|
11
15
|
/** Project a latched outcome, or null while this node remains unsettled. */
|
|
12
16
|
export declare function toNodeOutcomeDTO(node: Pick<NodeMeta, 'node_id' | 'final_report'> & NodeRuntime): NodeOutcomeDTO | null;
|
|
17
|
+
/** The outcome-delivery fields exposed by the API. The delivery store supplies this projection directly. */
|
|
18
|
+
export interface OutcomeDeliveryDTOInput {
|
|
19
|
+
nodeId: string;
|
|
20
|
+
state: 'armed' | 'pending' | 'running' | 'accepted' | 'permanent_failed';
|
|
21
|
+
actionName: string;
|
|
22
|
+
attempt: number;
|
|
23
|
+
nextAttemptAt: number;
|
|
24
|
+
acceptedAt: number | null;
|
|
25
|
+
permanentFailedAt: number | null;
|
|
26
|
+
lastFailure: {
|
|
27
|
+
kind: 'exit' | 'signal' | 'timeout' | 'spawn_error';
|
|
28
|
+
exitCode?: number;
|
|
29
|
+
signal?: string;
|
|
30
|
+
message?: string;
|
|
31
|
+
} | null;
|
|
32
|
+
createdAt: number;
|
|
33
|
+
updatedAt: number;
|
|
34
|
+
}
|
|
13
35
|
/** Project a durable delivery row without exposing its execution coordinates or stderr tail. */
|
|
14
|
-
export declare function toOutcomeDeliveryDTO(row:
|
|
36
|
+
export declare function toOutcomeDeliveryDTO(row: OutcomeDeliveryDTOInput): OutcomeDeliveryDTO;
|
|
15
37
|
/** Project the queryable row (what `listNodes` yields) into a summary DTO. */
|
|
16
38
|
export declare function toNodeSummaryDTO(row: NodeRow): NodeSummaryDTO;
|
|
17
39
|
/** The subscription/child edges a detail projection needs. The handler gathers
|
package/dist/daemon/api/map.js
CHANGED
|
@@ -10,11 +10,12 @@
|
|
|
10
10
|
// reasonable projections; this module is what makes them concrete, so any DTO
|
|
11
11
|
// field that projection proves wrong is corrected here at the source.
|
|
12
12
|
import { existsSync, readFileSync } from 'node:fs';
|
|
13
|
+
import { join } from 'node:path';
|
|
13
14
|
import { outputResultPath } from '../../core/runtime/structured-output.js';
|
|
14
15
|
import { ReviewOperationError as ReviewOperationErrorClass } from '../../core/review/types.js';
|
|
15
16
|
import { cronSinkDisplay } from '../../core/canvas/crons.js';
|
|
16
17
|
import { isProfilePaused, sanitizeProfileMetadata } from '../../core/profiles/manifest.js';
|
|
17
|
-
import { contextDir,
|
|
18
|
+
import { contextDir, nodeDir, nodeMetaPath, reportsDir, transcriptPath, viewSocketPath, } from '../../core/canvas/paths.js';
|
|
18
19
|
import { FinalizationError } from '../../core/feed/feed.js';
|
|
19
20
|
import { NodeIdConflictError } from '../../core/runtime/nodes.js';
|
|
20
21
|
import { readContextTokens } from '../../core/canvas/telemetry.js';
|
|
@@ -22,8 +23,82 @@ import { CrtrError } from '../../core/errors.js';
|
|
|
22
23
|
import { WorktreeError } from '../../core/worktree.js';
|
|
23
24
|
import { ApiError } from '../../api/errors.js';
|
|
24
25
|
import { ExitCode } from '../../types.js';
|
|
25
|
-
|
|
26
|
-
|
|
26
|
+
export function toMigrateStateDTO(result, options) {
|
|
27
|
+
const { discovery, snapshots } = result;
|
|
28
|
+
return {
|
|
29
|
+
profiles: result.profiles,
|
|
30
|
+
stores: discovery.stores.length,
|
|
31
|
+
changed: result.changed,
|
|
32
|
+
applied: result.applied,
|
|
33
|
+
skipped: result.skipped,
|
|
34
|
+
blockers: result.blockers.map((blocker) => ({
|
|
35
|
+
kind: blocker.kind,
|
|
36
|
+
message: blocker.message,
|
|
37
|
+
...(blocker.storeRoot === undefined ? {} : { store: blocker.storeRoot }),
|
|
38
|
+
...(blocker.targetId === undefined ? {} : { target: blocker.targetId }),
|
|
39
|
+
...(blocker.path === undefined ? {} : { path: blocker.path }),
|
|
40
|
+
...(blocker.name === undefined ? {} : { name: blocker.name }),
|
|
41
|
+
...(blocker.paths === undefined ? {} : { paths: blocker.paths }),
|
|
42
|
+
})),
|
|
43
|
+
discovery_roots: discovery.roots.map((row) => ({
|
|
44
|
+
reason: row.reason,
|
|
45
|
+
root: row.root,
|
|
46
|
+
boundary: row.boundary,
|
|
47
|
+
...(row.detail === undefined ? {} : { detail: row.detail }),
|
|
48
|
+
})),
|
|
49
|
+
discovered_stores: discovery.stores.map((store) => ({
|
|
50
|
+
store: store.key,
|
|
51
|
+
scope: store.descriptor.scope,
|
|
52
|
+
namespace: store.descriptor.namespace,
|
|
53
|
+
mount_status: store.descriptor.mountStatus,
|
|
54
|
+
writable: store.writable,
|
|
55
|
+
reasons: [...new Set(store.discovery.map((row) => row.reason))],
|
|
56
|
+
targets: store.targets,
|
|
57
|
+
docs: snapshots.get(store.key)?.docs.length ?? 0,
|
|
58
|
+
})),
|
|
59
|
+
discovered_targets: discovery.targets.map((target) => ({
|
|
60
|
+
id: target.id,
|
|
61
|
+
kind: target.kind,
|
|
62
|
+
origin: target.origin,
|
|
63
|
+
cwd: target.target.cwd,
|
|
64
|
+
profile_id: target.target.profileId,
|
|
65
|
+
node_id: target.target.nodeId,
|
|
66
|
+
stores: target.storeKeys,
|
|
67
|
+
})),
|
|
68
|
+
repository_namespaces: result.repositories.map((row) => ({
|
|
69
|
+
repository_root: row.repositoryRoot,
|
|
70
|
+
repository_key: row.repositoryKey,
|
|
71
|
+
declaration_path: row.declarationPath,
|
|
72
|
+
namespace: row.namespace,
|
|
73
|
+
source: row.source,
|
|
74
|
+
action: row.action,
|
|
75
|
+
})),
|
|
76
|
+
store_prefixes: result.storePrefixes.map((row) => ({
|
|
77
|
+
store_root: row.storeRoot,
|
|
78
|
+
owner_dir: row.ownerDir,
|
|
79
|
+
repository_root: row.repositoryRoot,
|
|
80
|
+
owner_relative_path: row.ownerRelativePath,
|
|
81
|
+
old_prefix: row.oldPrefix,
|
|
82
|
+
old_rule: row.oldRule,
|
|
83
|
+
effective_prefix: row.effectivePrefix,
|
|
84
|
+
nested_declaration_action: row.nestedDeclarationAction,
|
|
85
|
+
front_door_action: row.frontDoorAction,
|
|
86
|
+
})),
|
|
87
|
+
renames: result.renames.map((row) => ({ store_root: row.storeRoot, path: row.path, from: row.from, to: row.to })),
|
|
88
|
+
references: result.references.map((row) => ({ store_root: row.storeRoot, path: row.path, kind: row.kind, from: row.from, to: row.to })),
|
|
89
|
+
dryRun: result.dryRun,
|
|
90
|
+
blocked: result.blocked,
|
|
91
|
+
corpus_phase: result.corpusPhase,
|
|
92
|
+
wrote: {
|
|
93
|
+
profile_manifests: result.wrote.profileManifests,
|
|
94
|
+
documents: result.wrote.documents,
|
|
95
|
+
corpus_consumers: result.wrote.corpusConsumers,
|
|
96
|
+
corpus_identities: result.wrote.corpusIdentities,
|
|
97
|
+
},
|
|
98
|
+
resumed: options.resumed,
|
|
99
|
+
...(options.resumeError === undefined ? {} : { resume_error: options.resumeError }),
|
|
100
|
+
};
|
|
101
|
+
}
|
|
27
102
|
// Node projections
|
|
28
103
|
/** Read the optional machine result without letting a missing or malformed sidecar obscure the durable outcome row. */
|
|
29
104
|
function readStructuredResult(nodeId) {
|
|
@@ -122,6 +197,8 @@ export function toNodeSummaryDTO(row) {
|
|
|
122
197
|
finalized_at: row.finalized_at ?? null,
|
|
123
198
|
deadline_at: row.deadline_at ?? null,
|
|
124
199
|
outcome: toNodeOutcomeDTO(row),
|
|
200
|
+
fault: row.fault && row.fault.link !== 'broker↔crtrd' ? { ...row.fault, link: row.fault.link } : null,
|
|
201
|
+
streaming: row.streaming ?? false,
|
|
125
202
|
};
|
|
126
203
|
}
|
|
127
204
|
/** Project a node's spine + subscription edges (absorbs `managers`/`paths`). */
|
|
@@ -142,7 +219,6 @@ export function toNodePathsDTO(nodeId) {
|
|
|
142
219
|
context_dir: contextDir(nodeId),
|
|
143
220
|
reports_dir: reportsDir(nodeId),
|
|
144
221
|
meta_path: nodeMetaPath(nodeId),
|
|
145
|
-
inbox_path: inboxPath(nodeId),
|
|
146
222
|
transcript_path: transcriptPath(nodeId),
|
|
147
223
|
view_socket: viewSocketPath(nodeId),
|
|
148
224
|
};
|
|
@@ -197,6 +273,8 @@ export function toNodeDetailDTO(meta, edges) {
|
|
|
197
273
|
finalized_at: meta.finalized_at ?? null,
|
|
198
274
|
deadline_at: meta.deadline_at ?? null,
|
|
199
275
|
outcome: toNodeOutcomeDTO(meta),
|
|
276
|
+
fault: meta.fault && meta.fault.link !== 'broker↔crtrd' ? { ...meta.fault, link: meta.fault.link } : null,
|
|
277
|
+
streaming: meta.streaming ?? false,
|
|
200
278
|
creator: meta.creator ?? null,
|
|
201
279
|
edges: toNodeEdgesDTO(meta, edges),
|
|
202
280
|
paths: toNodePathsDTO(meta.node_id),
|
|
@@ -363,7 +441,7 @@ export function toReviewDTO(row, extras = {}) {
|
|
|
363
441
|
review_id: row.review_id,
|
|
364
442
|
origin_kind: row.origin_kind,
|
|
365
443
|
origin_node_id: row.origin_node_id,
|
|
366
|
-
|
|
444
|
+
review_dir: row.review_dir,
|
|
367
445
|
companion_node_id: row.companion_node_id,
|
|
368
446
|
file: row.file,
|
|
369
447
|
state: row.state,
|
|
@@ -601,15 +679,7 @@ function reviewErrorDetails(err) {
|
|
|
601
679
|
function terminalConflictReviewDTO(review) {
|
|
602
680
|
if (review.state !== 'approved')
|
|
603
681
|
return toReviewDTO(review);
|
|
604
|
-
|
|
605
|
-
? reviewResultPath(review.review_id)
|
|
606
|
-
: responsePath(ticketDir(requireBridgeNodeId(review)));
|
|
607
|
-
return toReviewDTO(review, { result_path });
|
|
608
|
-
}
|
|
609
|
-
function requireBridgeNodeId(review) {
|
|
610
|
-
if (review.bridge_node_id === null)
|
|
611
|
-
throw new Error(`approved ticket review lacks its bridge node: ${review.review_id}`);
|
|
612
|
-
return review.bridge_node_id;
|
|
682
|
+
return toReviewDTO(review, { result_path: join(review.review_dir, 'result.json') });
|
|
613
683
|
}
|
|
614
684
|
function statusForExitCode(exitCode) {
|
|
615
685
|
switch (exitCode) {
|
|
@@ -24,21 +24,22 @@ import { emitEvent } from '../../core/events/emit.js';
|
|
|
24
24
|
import { envCrtrdTcp, envCrtrdToken } from '../../shared/env.js';
|
|
25
25
|
import { Router } from './router.js';
|
|
26
26
|
import { handleAttachUpgrade } from './bridge.js';
|
|
27
|
+
import { boundDaemonControl } from '../control.js';
|
|
27
28
|
import { attachRoutes } from './handlers/attach.js';
|
|
28
29
|
import { bashJobRoutes } from './handlers/bash-jobs.js';
|
|
29
30
|
import { brokerOperationRoutes } from './handlers/broker-ops.js';
|
|
31
|
+
import { brokerRecoveryRoutes, nodeFaultRoutes } from './handlers/broker-recovery.js';
|
|
30
32
|
import { canvasRoutes } from './handlers/canvas.js';
|
|
31
33
|
import { chatInventoryRoutes } from './handlers/chat-inventory.js';
|
|
32
34
|
import { daemonRoutes } from './handlers/daemon.js';
|
|
33
35
|
import { fileRoutes } from './handlers/files.js';
|
|
34
36
|
import { focusRoutes } from './handlers/focus.js';
|
|
35
37
|
import { healthRoutes } from './handlers/health.js';
|
|
36
|
-
import { humanRoutes } from './handlers/human.js';
|
|
37
38
|
import { humanRequestRoutes } from './handlers/human-requests.js';
|
|
38
39
|
import { inboxRoutes } from './handlers/inbox.js';
|
|
39
40
|
import { feedbackCommentRoutes } from './handlers/feedback-comments.js';
|
|
40
41
|
import { memoryRoutes } from './handlers/memory.js';
|
|
41
|
-
import { messageRoutes } from './handlers/messages.js';
|
|
42
|
+
import { brokerMailRoutes, messageRoutes } from './handlers/messages.js';
|
|
42
43
|
import { modelAuthRoutes } from './handlers/modelauth.js';
|
|
43
44
|
import { modelConfigRoutes } from './handlers/model-config.js';
|
|
44
45
|
import { nodeRoutes } from './handlers/nodes.js';
|
|
@@ -62,7 +63,10 @@ function buildRouter() {
|
|
|
62
63
|
.registerAll(nodeOutcomeRoutes)
|
|
63
64
|
.registerAll(bashJobRoutes)
|
|
64
65
|
.registerAll(brokerOperationRoutes)
|
|
66
|
+
.registerAll(brokerRecoveryRoutes)
|
|
67
|
+
.registerAll(nodeFaultRoutes)
|
|
65
68
|
.registerAll(worktreeRoutes)
|
|
69
|
+
.registerAll(brokerMailRoutes)
|
|
66
70
|
.registerAll(messageRoutes)
|
|
67
71
|
.registerAll(reportRoutes)
|
|
68
72
|
.registerAll(attachRoutes)
|
|
@@ -75,7 +79,6 @@ function buildRouter() {
|
|
|
75
79
|
.registerAll(profileRoutes)
|
|
76
80
|
.registerAll(modelAuthRoutes)
|
|
77
81
|
.registerAll(modelConfigRoutes)
|
|
78
|
-
.registerAll(humanRoutes)
|
|
79
82
|
.registerAll(reviewRoutes)
|
|
80
83
|
.registerAll(reviewCommentRoutes)
|
|
81
84
|
.registerAll(inboxRoutes)
|
|
@@ -135,6 +138,20 @@ function writeUnauthorized(res) {
|
|
|
135
138
|
res.writeHead(401, { 'content-type': 'application/json; charset=utf-8' });
|
|
136
139
|
res.end(payload);
|
|
137
140
|
}
|
|
141
|
+
function writeStartupBlocked(res, message) {
|
|
142
|
+
res.writeHead(503, { 'content-type': 'application/json; charset=utf-8' });
|
|
143
|
+
res.end(JSON.stringify({ error: { code: 'startup_blocked', message } }));
|
|
144
|
+
}
|
|
145
|
+
function destroyUpgradeStartupBlocked(socket, message) {
|
|
146
|
+
const payload = JSON.stringify({ error: { code: 'startup_blocked', message } });
|
|
147
|
+
const response = `HTTP/1.1 503 Service Unavailable\r\ncontent-type: application/json; charset=utf-8\r\ncontent-length: ${Buffer.byteLength(payload)}\r\nconnection: close\r\n\r\n${payload}`;
|
|
148
|
+
try {
|
|
149
|
+
socket.end(response);
|
|
150
|
+
}
|
|
151
|
+
catch {
|
|
152
|
+
socket.destroy();
|
|
153
|
+
}
|
|
154
|
+
}
|
|
138
155
|
/** Reject an unauthorized TCP WS-upgrade attempt: this is a raw pre-upgrade
|
|
139
156
|
* socket (no `ServerResponse`), so the 401 is written as a literal HTTP
|
|
140
157
|
* response — mirroring `bridge.ts`'s `refuseUpgrade` (`end()`, not
|
|
@@ -180,13 +197,25 @@ function closeServer(server) {
|
|
|
180
197
|
* servers route into identical state. */
|
|
181
198
|
export function createApiServer(opts = {}) {
|
|
182
199
|
const router = buildRouter();
|
|
200
|
+
const brokerLaunchRoutes = new Router()
|
|
201
|
+
.registerAll(brokerOperationRoutes)
|
|
202
|
+
.registerAll(brokerRecoveryRoutes)
|
|
203
|
+
.registerAll(brokerMailRoutes);
|
|
204
|
+
const startupBlockFor = (method, pathname) => {
|
|
205
|
+
const block = boundDaemonControl()?.startupBlock() ?? null;
|
|
206
|
+
if (block === null)
|
|
207
|
+
return null;
|
|
208
|
+
const admitted = (method === 'GET' && (pathname === '/healthz' || pathname === '/v1/status'))
|
|
209
|
+
|| (method === 'POST' && (pathname === '/v1/daemon/migrate' || pathname === '/v1/daemon/admit'))
|
|
210
|
+
|| (block.phase === 'recovering' && brokerLaunchRoutes.match(method, pathname) !== null);
|
|
211
|
+
return admitted ? null : block;
|
|
212
|
+
};
|
|
183
213
|
const sockPath = apiSocketPath();
|
|
184
|
-
// Shared request handler.
|
|
185
|
-
//
|
|
186
|
-
//
|
|
187
|
-
// unexpected rejection.
|
|
214
|
+
// Shared request handler. It owns the request boundary, including URL
|
|
215
|
+
// parsing before the router can take over, so malformed wire input cannot
|
|
216
|
+
// escape Node's request listener and terminate the daemon.
|
|
188
217
|
const onRequest = (req, res) => {
|
|
189
|
-
|
|
218
|
+
const internalFailure = (err) => {
|
|
190
219
|
emitEvent({
|
|
191
220
|
event: 'api.request.failed',
|
|
192
221
|
level: 'error',
|
|
@@ -201,7 +230,32 @@ export function createApiServer(opts = {}) {
|
|
|
201
230
|
catch {
|
|
202
231
|
/* response already gone */
|
|
203
232
|
}
|
|
204
|
-
}
|
|
233
|
+
};
|
|
234
|
+
let url;
|
|
235
|
+
try {
|
|
236
|
+
url = new URL(req.url ?? '/', 'http://127.0.0.1');
|
|
237
|
+
}
|
|
238
|
+
catch {
|
|
239
|
+
try {
|
|
240
|
+
res.writeHead(400, { 'content-type': 'application/json; charset=utf-8' });
|
|
241
|
+
res.end(JSON.stringify({ error: { code: 'invalid_request', message: 'request URL is invalid' } }));
|
|
242
|
+
}
|
|
243
|
+
catch {
|
|
244
|
+
/* response already gone */
|
|
245
|
+
}
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
try {
|
|
249
|
+
const block = startupBlockFor((req.method ?? 'GET').toUpperCase(), url.pathname);
|
|
250
|
+
if (block !== null) {
|
|
251
|
+
writeStartupBlocked(res, block.message);
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
void router.handle(req, res).catch(internalFailure);
|
|
255
|
+
}
|
|
256
|
+
catch (err) {
|
|
257
|
+
internalFailure(err);
|
|
258
|
+
}
|
|
205
259
|
};
|
|
206
260
|
// Shared upgrade handler: only `GET /v1/nodes/:id/attach` is served; every
|
|
207
261
|
// other upgrade path destroys the socket, and an unhandled error destroys the
|
|
@@ -214,6 +268,11 @@ export function createApiServer(opts = {}) {
|
|
|
214
268
|
});
|
|
215
269
|
try {
|
|
216
270
|
const url = new URL(req.url ?? '/', 'http://127.0.0.1');
|
|
271
|
+
const block = startupBlockFor((req.method ?? 'GET').toUpperCase(), url.pathname);
|
|
272
|
+
if (block !== null) {
|
|
273
|
+
destroyUpgradeStartupBlocked(socket, block.message);
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
217
276
|
const nodeId = attachNodeId(req.method ?? 'GET', url.pathname);
|
|
218
277
|
if (nodeId === null) {
|
|
219
278
|
// Not an attach upgrade — no other upgrade path is served.
|