@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
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
import { ApiError } from '../../../api/errors.js';
|
|
2
|
+
import { getNode } from '../../../core/canvas/canvas.js';
|
|
3
|
+
import { liveExecutionForNode } from '../../../core/canvas/executions.js';
|
|
4
|
+
import { admitEpisode, clearEpisode, clearFault, closeTurn, invalidateEpisode, openTurn, parseProviderError, readEpisode, readFault, recordFault, recordPendingEpisode, recordTransportPoisonVerdict, recordTurnProgress, reopenEpisode, } from '../../../core/canvas/recovery.js';
|
|
5
|
+
import { notFound, usage } from '../../../core/errors.js';
|
|
6
|
+
const FAULT_LINKS = new Set(['pi→provider', 'viewer↔broker', 'relay↔broker', 'viewer↔crtrd', 'daemon→node', 'crtr→pi']);
|
|
7
|
+
const FAULT_KINDS = new Set(['rate-limit', 'overloaded', 'connection', 'auth', 'protocol', 'context-overflow', 'other', 'wedged', 'model-not-found']);
|
|
8
|
+
const RETRY_DISPOSITIONS = new Set(['auto', 'manual', 'fatal']);
|
|
9
|
+
const RETRY_OWNERS = new Set(['sdk', 'daemon', 'client']);
|
|
10
|
+
function objectBody(body, operation) {
|
|
11
|
+
if (typeof body !== 'object' || body === null || Array.isArray(body))
|
|
12
|
+
throw usage(`${operation} requires a JSON object`);
|
|
13
|
+
return body;
|
|
14
|
+
}
|
|
15
|
+
function requireNode(nodeId) {
|
|
16
|
+
if (getNode(nodeId) === null)
|
|
17
|
+
throw notFound(`unknown node: ${nodeId}`, { received: nodeId });
|
|
18
|
+
}
|
|
19
|
+
export function requireCurrentExecution(nodeId, expectedExecutionId) {
|
|
20
|
+
if (typeof expectedExecutionId !== 'string' || expectedExecutionId === '')
|
|
21
|
+
throw usage('expected_execution_id must be a non-empty string');
|
|
22
|
+
const execution = liveExecutionForNode(nodeId);
|
|
23
|
+
if (execution === null || execution.executionId !== expectedExecutionId) {
|
|
24
|
+
throw new ApiError(409, 'stale_execution', 'broker execution is no longer current');
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function parseRetry(value) {
|
|
28
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value))
|
|
29
|
+
throw usage('retry must be an object');
|
|
30
|
+
const retry = value;
|
|
31
|
+
if (!RETRY_DISPOSITIONS.has(retry['disposition']))
|
|
32
|
+
throw usage('retry.disposition must be auto, manual, or fatal');
|
|
33
|
+
if (retry['by'] !== undefined && !RETRY_OWNERS.has(retry['by']))
|
|
34
|
+
throw usage('retry.by must be sdk, daemon, or client');
|
|
35
|
+
for (const key of ['attempt', 'max'])
|
|
36
|
+
if (retry[key] !== undefined && (!Number.isSafeInteger(retry[key]) || retry[key] < 0))
|
|
37
|
+
throw usage(`retry.${key} must be a non-negative safe integer`);
|
|
38
|
+
if (retry['nextAt'] !== undefined && typeof retry['nextAt'] !== 'string')
|
|
39
|
+
throw usage('retry.nextAt must be a string');
|
|
40
|
+
return retry;
|
|
41
|
+
}
|
|
42
|
+
function parseFaultInput(value) {
|
|
43
|
+
const input = objectBody(value, 'fault input');
|
|
44
|
+
if (!FAULT_LINKS.has(input['link']))
|
|
45
|
+
throw usage('fault link is invalid');
|
|
46
|
+
if (typeof input['op'] !== 'string' || input['op'] === '')
|
|
47
|
+
throw usage('fault op must be a non-empty string');
|
|
48
|
+
if (!FAULT_KINDS.has(input['kind']))
|
|
49
|
+
throw usage('fault kind is invalid');
|
|
50
|
+
if (typeof input['message'] !== 'string')
|
|
51
|
+
throw usage('fault message must be a string');
|
|
52
|
+
if (input['operation_id'] !== undefined && (typeof input['operation_id'] !== 'string' || input['operation_id'] === ''))
|
|
53
|
+
throw usage('operation_id must be a non-empty string');
|
|
54
|
+
if (input['since'] !== undefined && typeof input['since'] !== 'string')
|
|
55
|
+
throw usage('since must be a string');
|
|
56
|
+
if (input['anchor_entry_id'] !== undefined && (typeof input['anchor_entry_id'] !== 'string' || input['anchor_entry_id'] === ''))
|
|
57
|
+
throw usage('anchor_entry_id must be a non-empty string');
|
|
58
|
+
const providerError = input['provider_error'] === undefined ? undefined : parseProviderError(input['provider_error']);
|
|
59
|
+
if (input['provider_error'] !== undefined && providerError === undefined)
|
|
60
|
+
throw usage('provider_error is invalid');
|
|
61
|
+
return { ...input, ...(providerError === undefined ? {} : { provider_error: providerError }), retry: parseRetry(input['retry']) };
|
|
62
|
+
}
|
|
63
|
+
function faultInput(input) {
|
|
64
|
+
return {
|
|
65
|
+
link: input.link,
|
|
66
|
+
op: input.op,
|
|
67
|
+
kind: input.kind,
|
|
68
|
+
retry: input.retry,
|
|
69
|
+
message: input.message,
|
|
70
|
+
...(input.operation_id === undefined ? {} : { operation_id: input.operation_id }),
|
|
71
|
+
...(input.since === undefined ? {} : { since: input.since }),
|
|
72
|
+
...(input.anchor_entry_id === undefined ? {} : { anchorEntryId: input.anchor_entry_id }),
|
|
73
|
+
...(input.provider_error === undefined ? {} : { providerError: input.provider_error }),
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
function faultDto(fault) {
|
|
77
|
+
return {
|
|
78
|
+
fault_id: fault.faultId,
|
|
79
|
+
link: fault.link,
|
|
80
|
+
op: fault.op,
|
|
81
|
+
kind: fault.kind,
|
|
82
|
+
retry: fault.retry,
|
|
83
|
+
message: fault.message,
|
|
84
|
+
since: fault.since,
|
|
85
|
+
operation_id: fault.operation_id,
|
|
86
|
+
...(fault.anchorEntryId === undefined ? {} : { anchor_entry_id: fault.anchorEntryId }),
|
|
87
|
+
...(fault.providerError === undefined ? {} : { provider_error: fault.providerError }),
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
function recoveryState(nodeId) {
|
|
91
|
+
const fault = readFault(nodeId);
|
|
92
|
+
const episode = readEpisode(nodeId);
|
|
93
|
+
return {
|
|
94
|
+
fault: fault === null ? null : faultDto(fault),
|
|
95
|
+
episode: episode === null ? null : { state: episode.state, session_id: episode.sessionId, fault: faultDto(episode.fault) },
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
function parseTurn(body) {
|
|
99
|
+
const request = objectBody(body, 'broker turn');
|
|
100
|
+
const event = request['event'];
|
|
101
|
+
if (event !== 'started' && event !== 'progress' && event !== 'closed' && event !== 'interrupted' && event !== 'exit-diagnostic')
|
|
102
|
+
throw usage('event is invalid');
|
|
103
|
+
if (typeof request['expected_execution_id'] !== 'string' || request['expected_execution_id'] === '')
|
|
104
|
+
throw usage('expected_execution_id must be a non-empty string');
|
|
105
|
+
if (event === 'closed') {
|
|
106
|
+
if (request['end_reason'] !== 'settled' && request['end_reason'] !== 'teardown-aborted')
|
|
107
|
+
throw usage('closed turn requires end_reason settled or teardown-aborted');
|
|
108
|
+
}
|
|
109
|
+
else if (request['end_reason'] !== undefined)
|
|
110
|
+
throw usage('end_reason is valid only for closed turns');
|
|
111
|
+
if (event === 'exit-diagnostic') {
|
|
112
|
+
const diagnostic = objectBody(request['exit_diagnostic'], 'exit_diagnostic');
|
|
113
|
+
const poison = objectBody(diagnostic['transport_poison'], 'exit_diagnostic.transport_poison');
|
|
114
|
+
if (diagnostic['schema'] !== 'crtr.execution-exit-diagnostic/v1' || !Number.isSafeInteger(poison['consecutive_passes']) || poison['consecutive_passes'] < 1 || !Array.isArray(poison['routes']) || poison['routes'].length === 0 || !poison['routes'].every((route) => typeof route === 'string' && route !== ''))
|
|
115
|
+
throw usage('exit_diagnostic is invalid');
|
|
116
|
+
}
|
|
117
|
+
else if (request['exit_diagnostic'] !== undefined)
|
|
118
|
+
throw usage('exit_diagnostic is valid only for exit-diagnostic turns');
|
|
119
|
+
return request;
|
|
120
|
+
}
|
|
121
|
+
function handleTurn(ctx) {
|
|
122
|
+
const nodeId = ctx.params['id'];
|
|
123
|
+
requireNode(nodeId);
|
|
124
|
+
const request = parseTurn(ctx.body);
|
|
125
|
+
requireCurrentExecution(nodeId, request.expected_execution_id);
|
|
126
|
+
let applied;
|
|
127
|
+
switch (request.event) {
|
|
128
|
+
case 'started':
|
|
129
|
+
applied = openTurn(request.expected_execution_id, { reason: 'agent-start' });
|
|
130
|
+
break;
|
|
131
|
+
case 'interrupted':
|
|
132
|
+
applied = openTurn(request.expected_execution_id, { reason: 'prompt-unsettled' });
|
|
133
|
+
break;
|
|
134
|
+
case 'progress':
|
|
135
|
+
applied = recordTurnProgress(request.expected_execution_id);
|
|
136
|
+
break;
|
|
137
|
+
case 'closed':
|
|
138
|
+
applied = closeTurn(request.expected_execution_id, { endReason: request.end_reason });
|
|
139
|
+
break;
|
|
140
|
+
case 'exit-diagnostic': {
|
|
141
|
+
const poison = request.exit_diagnostic.transport_poison;
|
|
142
|
+
applied = recordTransportPoisonVerdict(request.expected_execution_id, { consecutivePasses: poison.consecutive_passes, routes: poison.routes });
|
|
143
|
+
break;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
const body = { applied };
|
|
147
|
+
return { status: 200, body };
|
|
148
|
+
}
|
|
149
|
+
function parseProviderRetry(body) {
|
|
150
|
+
const request = objectBody(body, 'provider retry');
|
|
151
|
+
if (typeof request['expected_execution_id'] !== 'string' || request['expected_execution_id'] === '')
|
|
152
|
+
throw usage('expected_execution_id must be a non-empty string');
|
|
153
|
+
if (!['record-pending', 'admit', 'reopen', 'invalidate', 'clear'].includes(request['op']))
|
|
154
|
+
throw usage('provider retry op is invalid');
|
|
155
|
+
if (typeof request['session_id'] !== 'string' || request['session_id'] === '')
|
|
156
|
+
throw usage('session_id must be a non-empty string');
|
|
157
|
+
if (request['op'] === 'record-pending')
|
|
158
|
+
request['input'] = parseFaultInput(request['input']);
|
|
159
|
+
if (request['op'] === 'admit') {
|
|
160
|
+
if (typeof request['fault_id'] !== 'string' || request['fault_id'] === '')
|
|
161
|
+
throw usage('admit requires fault_id');
|
|
162
|
+
request['retry'] = parseRetry(request['retry']);
|
|
163
|
+
}
|
|
164
|
+
return request;
|
|
165
|
+
}
|
|
166
|
+
function handleProviderRetry(ctx) {
|
|
167
|
+
const nodeId = ctx.params['id'];
|
|
168
|
+
requireNode(nodeId);
|
|
169
|
+
const request = parseProviderRetry(ctx.body);
|
|
170
|
+
requireCurrentExecution(nodeId, request.expected_execution_id);
|
|
171
|
+
let applied;
|
|
172
|
+
switch (request.op) {
|
|
173
|
+
case 'record-pending':
|
|
174
|
+
applied = recordPendingEpisode(nodeId, { sessionId: request.session_id, input: faultInput(request.input) }) !== null;
|
|
175
|
+
break;
|
|
176
|
+
case 'admit':
|
|
177
|
+
applied = admitEpisode(nodeId, { sessionId: request.session_id, faultId: request.fault_id, retry: request.retry });
|
|
178
|
+
break;
|
|
179
|
+
case 'reopen':
|
|
180
|
+
applied = reopenEpisode(nodeId, { sessionId: request.session_id });
|
|
181
|
+
break;
|
|
182
|
+
case 'invalidate':
|
|
183
|
+
applied = invalidateEpisode(nodeId, { sessionId: request.session_id });
|
|
184
|
+
break;
|
|
185
|
+
case 'clear':
|
|
186
|
+
applied = clearEpisode(nodeId, { sessionId: request.session_id });
|
|
187
|
+
break;
|
|
188
|
+
}
|
|
189
|
+
const body = { applied, episode: recoveryState(nodeId).episode };
|
|
190
|
+
return { status: 200, body };
|
|
191
|
+
}
|
|
192
|
+
function parseBrokerFault(body) {
|
|
193
|
+
const request = objectBody(body, 'broker fault');
|
|
194
|
+
if (typeof request['expected_execution_id'] !== 'string' || request['expected_execution_id'] === '')
|
|
195
|
+
throw usage('expected_execution_id must be a non-empty string');
|
|
196
|
+
if (request['op'] !== 'record' && request['op'] !== 'clear')
|
|
197
|
+
throw usage('fault op must be record or clear');
|
|
198
|
+
if (request['op'] === 'record')
|
|
199
|
+
request['input'] = parseFaultInput(request['input']);
|
|
200
|
+
if (request['op'] === 'clear' && request['link'] !== undefined && !FAULT_LINKS.has(request['link']))
|
|
201
|
+
throw usage('fault link is invalid');
|
|
202
|
+
if (request['preserve_episode'] !== undefined && typeof request['preserve_episode'] !== 'boolean')
|
|
203
|
+
throw usage('preserve_episode must be boolean');
|
|
204
|
+
return request;
|
|
205
|
+
}
|
|
206
|
+
function handleBrokerFault(ctx) {
|
|
207
|
+
const nodeId = ctx.params['id'];
|
|
208
|
+
requireNode(nodeId);
|
|
209
|
+
const request = parseBrokerFault(ctx.body);
|
|
210
|
+
requireCurrentExecution(nodeId, request.expected_execution_id);
|
|
211
|
+
const fault = request.op === 'record'
|
|
212
|
+
? recordFault(nodeId, faultInput(request.input))
|
|
213
|
+
: (clearFault(nodeId, { ...(request.link === undefined ? {} : { link: request.link }), ...(request.preserve_episode === undefined ? {} : { preserveEpisode: request.preserve_episode }) }), readFault(nodeId));
|
|
214
|
+
const body = { fault: fault === null ? null : faultDto(fault) };
|
|
215
|
+
return { status: 200, body };
|
|
216
|
+
}
|
|
217
|
+
function handleRecovery(ctx) {
|
|
218
|
+
const nodeId = ctx.params['id'];
|
|
219
|
+
requireNode(nodeId);
|
|
220
|
+
requireCurrentExecution(nodeId, ctx.query.get('expected_execution_id'));
|
|
221
|
+
return { status: 200, body: recoveryState(nodeId) };
|
|
222
|
+
}
|
|
223
|
+
function handleNodeFaultRecord(ctx) {
|
|
224
|
+
const nodeId = ctx.params['id'];
|
|
225
|
+
requireNode(nodeId);
|
|
226
|
+
const fault = recordFault(nodeId, faultInput(parseFaultInput(ctx.body)));
|
|
227
|
+
const body = { fault: fault === null ? null : faultDto(fault) };
|
|
228
|
+
return { status: 200, body };
|
|
229
|
+
}
|
|
230
|
+
function handleNodeFaultClear(ctx) {
|
|
231
|
+
const nodeId = ctx.params['id'];
|
|
232
|
+
requireNode(nodeId);
|
|
233
|
+
const link = ctx.query.get('link');
|
|
234
|
+
if (link !== null && !FAULT_LINKS.has(link))
|
|
235
|
+
throw usage('fault link is invalid');
|
|
236
|
+
const preserve = ctx.query.get('preserve_episode');
|
|
237
|
+
if (preserve !== null && preserve !== 'true' && preserve !== 'false')
|
|
238
|
+
throw usage('preserve_episode must be true or false');
|
|
239
|
+
const body = { cleared: clearFault(nodeId, { ...(link === null ? {} : { link: link }), ...(preserve === null ? {} : { preserveEpisode: preserve === 'true' }) }) };
|
|
240
|
+
return { status: 200, body };
|
|
241
|
+
}
|
|
242
|
+
export const brokerRecoveryRoutes = [
|
|
243
|
+
{ method: 'POST', pattern: '/v1/broker/:id/turn', handler: handleTurn },
|
|
244
|
+
{ method: 'POST', pattern: '/v1/broker/:id/provider-retry', handler: handleProviderRetry },
|
|
245
|
+
{ method: 'POST', pattern: '/v1/broker/:id/fault', handler: handleBrokerFault },
|
|
246
|
+
{ method: 'GET', pattern: '/v1/broker/:id/recovery', handler: handleRecovery },
|
|
247
|
+
];
|
|
248
|
+
export const nodeFaultRoutes = [
|
|
249
|
+
{ method: 'POST', pattern: '/v1/nodes/:id/fault', handler: handleNodeFaultRecord },
|
|
250
|
+
{ method: 'DELETE', pattern: '/v1/nodes/:id/fault', handler: handleNodeFaultClear },
|
|
251
|
+
];
|
|
@@ -1,17 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
// are cross-canvas reads; prune/rebuild-index are the maintenance verbs backing
|
|
3
|
-
// `crtr canvas prune` / `crtr canvas rebuild-index`.
|
|
4
|
-
//
|
|
5
|
-
// The CLI leaves (Stage B-6) are pure clients: every canvas.db touch these verbs
|
|
6
|
-
// had — pruneNodes/pruneToLimit/reapEmptyNodes, the rebuild + fail-loud check,
|
|
7
|
-
// the enriched snapshot roster, and the whole
|
|
8
|
-
// buildCorpus/resolveRef search corpus — runs HERE, server-side. map.ts carries
|
|
9
|
-
// no projector for these readers (frozen under concurrency with the sibling
|
|
10
|
-
// handler author), so the field-mapping is inlined \u2014 a server-side projection,
|
|
11
|
-
// the sanctioned place for it.
|
|
12
|
-
import { existsSync, readdirSync } from 'node:fs';
|
|
13
|
-
import { join } from 'node:path';
|
|
14
|
-
import { listNodes, pruneNodes, pruneToLimit, rebuildIndex, rosterEdges, rosterNodes } from '../../../core/canvas/canvas.js';
|
|
1
|
+
import { pruneNodes, pruneToLimit, rosterEdges, rosterNodes } from '../../../core/canvas/canvas.js';
|
|
15
2
|
import { activeBackgroundBashJobs } from '../../../core/bash-jobs.js';
|
|
16
3
|
import { contextDir } from '../../../core/canvas/paths.js';
|
|
17
4
|
import { nowIso } from '../../../core/fs-utils.js';
|
|
@@ -21,9 +8,8 @@ import { localCanvasSource } from '../../../core/canvas/source.js';
|
|
|
21
8
|
import { listFocuses } from '../../../core/canvas/focuses.js';
|
|
22
9
|
import { ticketCountsForNodes, ticketsAcrossCanvas } from '../../../core/canvas/attention.js';
|
|
23
10
|
import { buildCorpus, groupCorpus, resolveRef, } from '../../../core/canvas/history.js';
|
|
24
|
-
import { nodeDir, nodesRoot } from '../../../core/canvas/paths.js';
|
|
25
11
|
import { reapEmptyNodes } from '../../../core/runtime/placement.js';
|
|
26
|
-
import {
|
|
12
|
+
import { notFound, usage } from '../../../core/errors.js';
|
|
27
13
|
function handleAttention() {
|
|
28
14
|
const body = {
|
|
29
15
|
items: ticketsAcrossCanvas().map((t) => ({
|
|
@@ -319,8 +305,6 @@ async function handleSnapshot(ctx) {
|
|
|
319
305
|
const asks = ticketCountsForNodes(rows.map((r) => r.node_id));
|
|
320
306
|
await enrichRowsFromSource(localCanvasSource, rows, asks);
|
|
321
307
|
const nodes = rows.map((row) => {
|
|
322
|
-
// Every field here comes from the NodeRow listNodes already fetched (stashed
|
|
323
|
-
// on the row as srcRow) — this handler opens no meta.json at all.
|
|
324
308
|
const src = row.srcRow;
|
|
325
309
|
const hostKind = src?.host_kind ?? 'tmux';
|
|
326
310
|
return {
|
|
@@ -493,31 +477,6 @@ function handlePrune(ctx) {
|
|
|
493
477
|
const body = { pruned, dry_run: dryRun, ttl_days: ttlDays };
|
|
494
478
|
return { status: 200, body };
|
|
495
479
|
}
|
|
496
|
-
// rebuild-index \u2014 re-derive rows from on-disk metas + the fail-loud guard.
|
|
497
|
-
// Lifted from `commands/canvas-rebuild-index.ts` (countOnDiskMetas + throw).
|
|
498
|
-
function countOnDiskMetas() {
|
|
499
|
-
const root = nodesRoot();
|
|
500
|
-
if (!existsSync(root))
|
|
501
|
-
return 0;
|
|
502
|
-
let n = 0;
|
|
503
|
-
for (const id of readdirSync(root)) {
|
|
504
|
-
if (existsSync(join(nodeDir(id), 'meta.json')))
|
|
505
|
-
n++;
|
|
506
|
-
}
|
|
507
|
-
return n;
|
|
508
|
-
}
|
|
509
|
-
function handleRebuildIndex() {
|
|
510
|
-
const metas = countOnDiskMetas();
|
|
511
|
-
rebuildIndex();
|
|
512
|
-
const rows = listNodes().length;
|
|
513
|
-
if (metas > 0 && rows === 0) {
|
|
514
|
-
// A non-500 CrtrError so the specific diagnostic survives the error body
|
|
515
|
-
// (toErrorBody scrubs 500 messages for hygiene).
|
|
516
|
-
throw general(`rebuild-index found ${metas} on-disk meta.json file(s) under ${nodesRoot()} but produced 0 node rows in canvas.db \u2014 rebuild failed; refusing to leave an empty index`);
|
|
517
|
-
}
|
|
518
|
-
const body = { metas, rows };
|
|
519
|
-
return { status: 200, body };
|
|
520
|
-
}
|
|
521
480
|
export const canvasRoutes = [
|
|
522
481
|
{ method: 'GET', pattern: '/v1/canvas/attention', handler: handleAttention },
|
|
523
482
|
{ method: 'POST', pattern: '/v1/canvas/attention/counts', handler: handleAttentionCounts },
|
|
@@ -528,5 +487,4 @@ export const canvasRoutes = [
|
|
|
528
487
|
{ method: 'GET', pattern: '/v1/canvas/snapshot', handler: handleSnapshot },
|
|
529
488
|
{ method: 'GET', pattern: '/v1/canvas/roster', handler: handleRoster },
|
|
530
489
|
{ method: 'POST', pattern: '/v1/canvas/prune', handler: handlePrune },
|
|
531
|
-
{ method: 'POST', pattern: '/v1/canvas/rebuild-index', handler: handleRebuildIndex },
|
|
532
490
|
];
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
// success, and the resumed agent sees an aborted tool call and re-runs it. Here
|
|
9
9
|
// the daemon answers FIRST and hands over afterwards, so the ack is a settled
|
|
10
10
|
// tool result in the caller's transcript before the SIGTERM lands.
|
|
11
|
+
import { toMigrateStateDTO } from '../map.js';
|
|
11
12
|
import { boundDaemonControl } from '../../control.js';
|
|
12
13
|
function handleRestart() {
|
|
13
14
|
const control = boundDaemonControl();
|
|
@@ -30,6 +31,46 @@ function handleRestart() {
|
|
|
30
31
|
// 202: accepted, not yet performed — the handover happens after this response.
|
|
31
32
|
return { status: 202, body };
|
|
32
33
|
}
|
|
34
|
+
async function handleAdmit(ctx) {
|
|
35
|
+
if (ctx.body !== undefined) {
|
|
36
|
+
throw { status: 400, code: 'invalid_request', message: 'admission request must not include a body' };
|
|
37
|
+
}
|
|
38
|
+
const control = boundDaemonControl();
|
|
39
|
+
if (control === null) {
|
|
40
|
+
throw {
|
|
41
|
+
status: 503,
|
|
42
|
+
code: 'daemon_control_unavailable',
|
|
43
|
+
message: 'this API server is not hosted by a live daemon and cannot admit normal work',
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
const body = await control.admitStartup();
|
|
47
|
+
return { status: 200, body };
|
|
48
|
+
}
|
|
49
|
+
async function handleMigrate(ctx) {
|
|
50
|
+
const control = boundDaemonControl();
|
|
51
|
+
if (control === null) {
|
|
52
|
+
throw {
|
|
53
|
+
status: 503,
|
|
54
|
+
code: 'daemon_control_unavailable',
|
|
55
|
+
message: 'this API server is not hosted by a live daemon and cannot migrate its corpus',
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
const body = ctx.body;
|
|
59
|
+
if (body !== undefined && (typeof body !== 'object' || body === null || Array.isArray(body))) {
|
|
60
|
+
throw { status: 400, code: 'invalid_request', message: 'migration request body must be an object' };
|
|
61
|
+
}
|
|
62
|
+
const raw = (body ?? {});
|
|
63
|
+
if (raw.dry_run !== undefined && typeof raw.dry_run !== 'boolean') {
|
|
64
|
+
throw { status: 400, code: 'invalid_request', message: 'dry_run must be a boolean' };
|
|
65
|
+
}
|
|
66
|
+
if (raw.dirs !== undefined && (!Array.isArray(raw.dirs) || raw.dirs.some((dir) => typeof dir !== 'string'))) {
|
|
67
|
+
throw { status: 400, code: 'invalid_request', message: 'dirs must be an array of strings' };
|
|
68
|
+
}
|
|
69
|
+
const result = await control.repairMigrations({ dryRun: raw.dry_run === true, dirs: (raw.dirs ?? []) });
|
|
70
|
+
return { status: 200, body: toMigrateStateDTO(result.result, { resumed: result.resumed, resumeError: result.resumeError }) };
|
|
71
|
+
}
|
|
33
72
|
export const daemonRoutes = [
|
|
34
73
|
{ method: 'POST', pattern: '/v1/daemon/restart', handler: (_ctx) => handleRestart() },
|
|
74
|
+
{ method: 'POST', pattern: '/v1/daemon/migrate', handler: handleMigrate },
|
|
75
|
+
{ method: 'POST', pattern: '/v1/daemon/admit', handler: handleAdmit },
|
|
35
76
|
];
|
|
@@ -12,7 +12,7 @@ import { ApiError } from '../../../api/index.js';
|
|
|
12
12
|
import { createPageFeedbackComment, readPageFeedback, resolvePageFeedbackComment, PageFeedbackCommentAlreadyResolvedError, PageTicketTerminalError, UnknownPageFeedbackCommentError, } from '../../../core/human/feedback.js';
|
|
13
13
|
import { discardFeedbackCompanion, pageDocumentSha256, realizeFeedbackCompanion } from '../../../core/human/feedback-companion.js';
|
|
14
14
|
import { parsePage } from '../../../core/human/page.js';
|
|
15
|
-
import { pageTicketState } from '../../../core/human/tickets.js';
|
|
15
|
+
import { pageTicketState, selectedPageDir } from '../../../core/human/tickets.js';
|
|
16
16
|
import { deliverNodeMessage } from '../../messaging/node-message.js';
|
|
17
17
|
import { requireTicketId, resolveTicket } from './inbox.js';
|
|
18
18
|
import { invalidRequest, objectBody, optionalString, requiredString } from './validate.js';
|
|
@@ -90,7 +90,7 @@ function parseCreate(ctx) {
|
|
|
90
90
|
async function handleCreate(ctx) {
|
|
91
91
|
const request = parseCreate(ctx);
|
|
92
92
|
const resolved = requireMutablePageTicket(ctx);
|
|
93
|
-
const manifest = parsePage(resolved.dir);
|
|
93
|
+
const manifest = parsePage(selectedPageDir(resolved.dir));
|
|
94
94
|
if (manifest.dialect !== 'jsx') {
|
|
95
95
|
throw new ApiError(409, 'page_dialect_unsupported', 'feedback comments exist only on TSX pages');
|
|
96
96
|
}
|
|
@@ -13,7 +13,8 @@ import { API_VERSION } from '../../../api/index.js';
|
|
|
13
13
|
import { DEFAULT_INTERVAL_MS } from '../../supervise-cadence.js';
|
|
14
14
|
import { envCrtrdTcp } from '../../../shared/env.js';
|
|
15
15
|
import { isPidAlive } from '../../../core/canvas/pid.js';
|
|
16
|
-
import {
|
|
16
|
+
import { readLiveTurn } from '../../../core/canvas/recovery.js';
|
|
17
|
+
import { boundDaemonControl } from '../../control.js';
|
|
17
18
|
// The daemon's supervise-loop cadence, echoed as an informational field; the
|
|
18
19
|
// loop itself is unchanged (hard constraint). Derived from the single shared
|
|
19
20
|
// constant so it can never drift from crtrd's actual interval.
|
|
@@ -35,13 +36,16 @@ function nodeCounts(rows) {
|
|
|
35
36
|
}
|
|
36
37
|
function handleHealthz() {
|
|
37
38
|
const storeAccessible = canvasRows() !== null;
|
|
39
|
+
const startup = boundDaemonControl()?.startupBlock() ?? null;
|
|
38
40
|
const body = {
|
|
39
|
-
ok: storeAccessible,
|
|
41
|
+
ok: storeAccessible && startup === null,
|
|
40
42
|
daemon_up: true,
|
|
41
43
|
store_accessible: storeAccessible,
|
|
42
|
-
brokers_reconciled:
|
|
44
|
+
brokers_reconciled: startup === null,
|
|
45
|
+
startup_phase: startup?.phase ?? 'ready',
|
|
46
|
+
...(startup === null ? {} : { startup_blocked: startup.message }),
|
|
43
47
|
};
|
|
44
|
-
return { status:
|
|
48
|
+
return { status: body.ok ? 200 : 503, body };
|
|
45
49
|
}
|
|
46
50
|
function handleStatus() {
|
|
47
51
|
const rows = canvasRows();
|
|
@@ -49,7 +53,7 @@ function handleStatus() {
|
|
|
49
53
|
// The store is unreachable — spec §8 store_unavailable.
|
|
50
54
|
throw { status: 503, code: 'store_unavailable', message: 'canvas store is inaccessible' };
|
|
51
55
|
}
|
|
52
|
-
const busyNodeCount = rows.filter((row) => row.kind !== 'human' &&
|
|
56
|
+
const busyNodeCount = rows.filter((row) => row.kind !== 'human' && readLiveTurn(row.node_id)?.busy === true && isPidAlive(row.pi_pid)).length;
|
|
53
57
|
const tcp = envCrtrdTcp();
|
|
54
58
|
const body = {
|
|
55
59
|
daemon_pid: process.pid,
|
|
@@ -62,6 +66,7 @@ function handleStatus() {
|
|
|
62
66
|
},
|
|
63
67
|
runtime_version: currentVersion(),
|
|
64
68
|
api_version: API_VERSION,
|
|
69
|
+
startup_phase: boundDaemonControl()?.startupBlock()?.phase ?? 'ready',
|
|
65
70
|
};
|
|
66
71
|
return { status: 200, body };
|
|
67
72
|
}
|