@north-light/crouter 0.3.312 → 0.3.314
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 +757 -746
- 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 +13 -1
- 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/fresh-home-commands.test.js +49 -0
- package/dist/core/__tests__/integration/host-teardown-process-group.test.js +9 -5
- package/dist/core/__tests__/integration/lifecycle-hooks.test.js +16 -3
- 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 +51 -8
- 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 +2 -1
- package/dist/core/__tests__/on-read-dedup-resume.test.js +2 -1
- package/dist/core/__tests__/on-read-nested-store.test.js +2 -1
- 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 +4 -1
- 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 +2 -1
- 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 +18 -4
- 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.js +11 -0
- package/dist/core/config.d.ts +17 -12
- package/dist/core/config.js +106 -155
- 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 +3 -2
- 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/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/placement.js +2 -2
- package/dist/core/runtime/recycle.js +8 -2
- package/dist/core/runtime/reset.js +22 -6
- package/dist/core/runtime/revive.js +226 -218
- package/dist/core/runtime/spawn.js +14 -3
- package/dist/core/scoped-state/db.d.ts +18 -0
- package/dist/core/scoped-state/db.js +135 -0
- package/dist/core/scoped-state/migrate.d.ts +8 -0
- package/dist/core/scoped-state/migrate.js +181 -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 +39 -15
- 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 +4 -1
- 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 +27 -41
- 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 -151
- 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.js +7 -13
- 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/index.d.ts +2 -1
- 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.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
- /package/dist/core/__tests__/{human-deliver.test.d.ts → integration/fresh-home-commands.test.d.ts} +0 -0
|
@@ -35,9 +35,11 @@ import { createAttachKit } from '../../../../core/__tests__/helpers/broker-clien
|
|
|
35
35
|
import { ApiError, CrtrClient } from '../../../../api/index.js';
|
|
36
36
|
import { createApiServer } from '../../server.js';
|
|
37
37
|
import { createNode } from '../../../../core/canvas/canvas.js';
|
|
38
|
-
import { apiSocketPath
|
|
38
|
+
import { apiSocketPath } from '../../../../core/canvas/paths.js';
|
|
39
|
+
import { beginExecution, recordExecutionPid } from '../../../../core/canvas/executions.js';
|
|
40
|
+
import { closeTurn, openTurn } from '../../../../core/canvas/recovery.js';
|
|
39
41
|
import { isPidAlive } from '../../../../core/canvas/pid.js';
|
|
40
|
-
import {
|
|
42
|
+
import { initializeFreshScopedStore } from '../../../../core/scoped-state/migrate.js';
|
|
41
43
|
let h;
|
|
42
44
|
let server;
|
|
43
45
|
let client;
|
|
@@ -64,17 +66,6 @@ function seedAssistantSession(sessionFile) {
|
|
|
64
66
|
mkdirSync(dirname(sessionFile), { recursive: true });
|
|
65
67
|
writeFileSync(sessionFile, JSON.stringify({ type: 'message', message: { role: 'assistant', content: [{ type: 'text', text: 'hi' }] } }) + '\n');
|
|
66
68
|
}
|
|
67
|
-
// Count non-empty lines in a jsonl file (raw, cursor-independent — the live
|
|
68
|
-
// broker's inbox-watcher advances a SEPARATE cursor sidecar, so reading the
|
|
69
|
-
// append-only file directly is stable regardless of consumption).
|
|
70
|
-
function countLines(path) {
|
|
71
|
-
try {
|
|
72
|
-
return readFileSync(path, 'utf8').split('\n').filter((l) => l.trim() !== '').length;
|
|
73
|
-
}
|
|
74
|
-
catch {
|
|
75
|
-
return 0;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
69
|
// A1 — /healthz ok + socket mode 0600
|
|
79
70
|
test('A1: /healthz is ok and the unix socket is bound mode 0600', async () => {
|
|
80
71
|
const health = await client.healthz();
|
|
@@ -83,10 +74,10 @@ test('A1: /healthz is ok and the unix socket is bound mode 0600', async () => {
|
|
|
83
74
|
assert.equal(mode, 0o600, `socket mode is 0600 (fs-perms-as-auth), got 0o${mode.toString(8)}`);
|
|
84
75
|
});
|
|
85
76
|
test('status counts only live, busy non-human engine rows', async () => {
|
|
86
|
-
const agent = h.fabricateBrokerNode(
|
|
77
|
+
const agent = h.fabricateBrokerNode();
|
|
87
78
|
const deadPid = spawnSync(process.execPath, ['-e', '']).pid;
|
|
88
79
|
assert.ok(deadPid !== undefined, 'dead-pid fixture process started');
|
|
89
|
-
const deadAgent = h.fabricateBrokerNode(
|
|
80
|
+
const deadAgent = h.fabricateBrokerNode();
|
|
90
81
|
const bridge = `human-status-${process.pid}`;
|
|
91
82
|
createNode({
|
|
92
83
|
node_id: bridge,
|
|
@@ -101,16 +92,21 @@ test('status counts only live, busy non-human engine rows', async () => {
|
|
|
101
92
|
pi_pid: process.pid,
|
|
102
93
|
});
|
|
103
94
|
const baseline = (await client.status()).busy_node_count;
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
95
|
+
const executions = [agent, deadAgent, bridge].map((nodeId) => beginExecution(nodeId, { daemonEpoch: null }));
|
|
96
|
+
for (const [executionId, nodeId, pid] of [
|
|
97
|
+
[executions[0], agent, process.pid],
|
|
98
|
+
[executions[1], deadAgent, deadPid],
|
|
99
|
+
[executions[2], bridge, process.pid],
|
|
100
|
+
]) {
|
|
101
|
+
recordExecutionPid(executionId, nodeId, pid);
|
|
102
|
+
openTurn(executionId, { reason: 'agent-start' });
|
|
103
|
+
}
|
|
107
104
|
try {
|
|
108
105
|
assert.equal((await client.status()).busy_node_count, baseline + 1);
|
|
109
106
|
}
|
|
110
107
|
finally {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
clearBusy(bridge);
|
|
108
|
+
for (const executionId of executions)
|
|
109
|
+
closeTurn(executionId, { endReason: 'settled' });
|
|
114
110
|
}
|
|
115
111
|
});
|
|
116
112
|
test('attention counts reads only the requested node slice', async () => {
|
|
@@ -172,18 +168,15 @@ process.stdin.on('end', () => {
|
|
|
172
168
|
chmodSync(executable, 0o755);
|
|
173
169
|
return { started, release };
|
|
174
170
|
}
|
|
175
|
-
// A3 — POST .../messages
|
|
171
|
+
// A3 — POST .../messages creates a durable SQL delivery; POST .../reports {tier:'final'}
|
|
176
172
|
// writes the report, notifies subscribers, transitions the row
|
|
177
|
-
test('A3: messages
|
|
173
|
+
test('A3: messages create SQL deliveries; final report writes + notifies subscriber + transitions row', async () => {
|
|
178
174
|
const A = h.spawnRoot('a3 mgr');
|
|
179
175
|
const B = (await client.createNode({ kind: 'developer', parent: A, prompt: 'a3 worker' })).node_id;
|
|
180
176
|
await h.awaitBoot(B);
|
|
181
|
-
// messages append inbox.jsonl (raw line count is cursor-independent)
|
|
182
|
-
const inboxFile = inboxPath(B);
|
|
183
|
-
const before = countLines(inboxFile);
|
|
184
177
|
const msg = await client.sendMessage(B, { body: 'hello inbox' });
|
|
185
178
|
assert.equal(msg.delivered, true, 'message reports delivered');
|
|
186
|
-
await h.waitFor(() =>
|
|
179
|
+
await h.waitFor(() => h.inbox(B).some((entry) => entry.data?.['body'] === 'hello inbox'), { label: 'durable SQL delivery', timeoutMs: 10_000 });
|
|
187
180
|
// final report: file written + subscriber notified + row transitioned
|
|
188
181
|
const res = await client.pushReport(B, { tier: 'final', body: 'a3 done result' });
|
|
189
182
|
assert.ok(existsSync(res.report_path), `report file written at ${res.report_path}`);
|
|
@@ -195,12 +188,10 @@ test('A3: messages append inbox.jsonl; final report writes + notifies subscriber
|
|
|
195
188
|
test('A3b: a durable send acknowledges while the lifecycle tick is blocked launching its idle target', async () => {
|
|
196
189
|
const target = h.fabricateBrokerNode({ lifecycle: 'resident', status: 'idle', intent: 'idle-release' });
|
|
197
190
|
const hook = installBlockedStartHook(target);
|
|
198
|
-
const inboxFile = inboxPath(target);
|
|
199
|
-
const before = countLines(inboxFile);
|
|
200
191
|
const sending = client.sendMessage(target, { body: 'wake after durable acknowledgment' });
|
|
201
192
|
let tick;
|
|
202
193
|
try {
|
|
203
|
-
await h.waitFor(() =>
|
|
194
|
+
await h.waitFor(() => h.inbox(target).some((entry) => entry.data?.['body'] === 'wake after durable acknowledgment'), { label: 'durable SQL delivery' });
|
|
204
195
|
assert.equal(h.node(target)?.cycles ?? 0, 0, 'the send has not launched the target');
|
|
205
196
|
tick = h.tick();
|
|
206
197
|
await h.waitFor(() => existsSync(hook.started), { label: 'blocked lifecycle launch' });
|
|
@@ -210,11 +201,11 @@ test('A3b: a durable send acknowledges while the lifecycle tick is blocked launc
|
|
|
210
201
|
]);
|
|
211
202
|
assert.equal(acknowledged.delivered, true, 'the API acknowledges the durable append');
|
|
212
203
|
assert.equal(acknowledged.revived, false, 'the response honestly reports no synchronous revive');
|
|
213
|
-
assert.equal(
|
|
204
|
+
assert.equal(h.inbox(target).filter((entry) => entry.data?.['body'] === 'wake after durable acknowledgment').length, 1, 'exactly one SQL delivery is durable while launch is blocked');
|
|
214
205
|
writeFileSync(hook.release, 'release');
|
|
215
206
|
await tick;
|
|
216
207
|
assert.equal(h.node(target)?.cycles, 1, 'the one queued entry drove lifecycle revival');
|
|
217
|
-
assert.equal(
|
|
208
|
+
assert.equal(h.inbox(target).filter((entry) => entry.data?.['body'] === 'wake after durable acknowledgment').length, 1, 'revival did not append a second SQL delivery');
|
|
218
209
|
}
|
|
219
210
|
finally {
|
|
220
211
|
if (!existsSync(hook.release))
|
|
@@ -383,6 +374,7 @@ test('A6b: PUT /model-auth/{provider} writes auth.json (reload fan asserted as f
|
|
|
383
374
|
const savedPiDir = process.env['PI_CODING_AGENT_DIR'];
|
|
384
375
|
const piDir = mkdtempSync(join(tmpdir(), 'crtr-apisrv-pi-'));
|
|
385
376
|
process.env['PI_CODING_AGENT_DIR'] = piDir;
|
|
377
|
+
initializeFreshScopedStore({ kind: 'provider', root: piDir });
|
|
386
378
|
try {
|
|
387
379
|
const res = await client.installCredential('anthropic', { kind: 'api_key', api_key: 'sk-test-xyz' });
|
|
388
380
|
assert.equal(res.installed, true, 'credential reports installed');
|
|
@@ -35,6 +35,7 @@ import { tmpdir } from 'node:os';
|
|
|
35
35
|
import { join } from 'node:path';
|
|
36
36
|
import { readAuthCredentials, setAuthCredential } from '../../../../core/auth-file.js';
|
|
37
37
|
import { readSubscriptionPool, writeSubscriptionPool } from '../../../../core/subscription-state.js';
|
|
38
|
+
import { initializeFreshScopedStore } from '../../../../core/scoped-state/migrate.js';
|
|
38
39
|
import { createHeadlessHarness } from '../../../../core/__tests__/helpers/harness.js';
|
|
39
40
|
import { createAttachKit } from '../../../../core/__tests__/helpers/broker-clients.js';
|
|
40
41
|
import { CrtrClient } from '../../../../api/index.js';
|
|
@@ -118,6 +119,7 @@ test('B2-modelauth: installCredential writes auth.json and the reload fan acks a
|
|
|
118
119
|
const savedPiDir = process.env['PI_CODING_AGENT_DIR'];
|
|
119
120
|
const apiDir = mkdtempSync(join(tmpdir(), 'crtr-b10-api-'));
|
|
120
121
|
process.env['PI_CODING_AGENT_DIR'] = apiDir;
|
|
122
|
+
initializeFreshScopedStore({ kind: 'provider', root: apiDir });
|
|
121
123
|
let liveId;
|
|
122
124
|
try {
|
|
123
125
|
// A live broker to receive the fan.
|
|
@@ -190,8 +192,9 @@ test('B2-modelauth-oauth: installCredential(oauth) preserves extra fields (enter
|
|
|
190
192
|
// clears exactly its provider's durable store.
|
|
191
193
|
test('B2-modelauth-status: list is sanitized and delete clears only the selected provider', async () => {
|
|
192
194
|
const savedPiDir = process.env['PI_CODING_AGENT_DIR'];
|
|
193
|
-
const apiDir = mkdtempSync(join(
|
|
195
|
+
const apiDir = mkdtempSync(join(h.agentHome, 'crtr-b10-status-'));
|
|
194
196
|
process.env['PI_CODING_AGENT_DIR'] = apiDir;
|
|
197
|
+
initializeFreshScopedStore({ kind: 'provider', root: apiDir });
|
|
195
198
|
const expires = 1_900_000_000_000;
|
|
196
199
|
const cooldown = 1_900_000_100_000;
|
|
197
200
|
try {
|
|
@@ -30,7 +30,7 @@ import { registerPush } from '../../../../commands/push.js';
|
|
|
30
30
|
import { registerNode } from '../../../../commands/node.js';
|
|
31
31
|
import { createNode, getNode } from '../../../../core/canvas/canvas.js';
|
|
32
32
|
import { branchIsPushedAtCurrentTip, createManagedWorktree } from '../../../../core/worktree.js';
|
|
33
|
-
import {
|
|
33
|
+
import { openDb } from '../../../../core/canvas/db.js';
|
|
34
34
|
import { gitSync } from '../../../../core/git.js';
|
|
35
35
|
import { InputError } from '../../../../core/io.js';
|
|
36
36
|
// A terminal fabricated node (no broker needed) that OWNS a managed worktree —
|
|
@@ -161,9 +161,10 @@ test('`crtr push update --tier deferred` fans a deferred pointer while preservin
|
|
|
161
161
|
await h.awaitBoot(child);
|
|
162
162
|
const out = await runPushAs(child, 'update', 'deferred progress', { tier: 'deferred' });
|
|
163
163
|
assert.ok(out['notified'].includes(parent), 'the subscribed parent receives the report pointer');
|
|
164
|
-
const entry =
|
|
165
|
-
|
|
166
|
-
assert.equal(entry?.
|
|
164
|
+
const entry = openDb().prepare(`SELECT m.kind, d.urgency FROM deliveries d JOIN messages m ON m.message_id = d.message_id
|
|
165
|
+
WHERE d.destination_kind = 'node_inbox' AND d.destination_id = ? AND m.sender_node_id = ? AND m.label = ?`).get(parent, child, 'deferred progress');
|
|
166
|
+
assert.equal(entry?.kind, 'update', 'the stored SQL message remains an update');
|
|
167
|
+
assert.equal(entry?.urgency, 'deferred', 'the requested delivery urgency reaches the parent');
|
|
167
168
|
});
|
|
168
169
|
// Re-homed worktree guard/auto-drop (ambiguity-2 follow-up): the pre-B-5 CLI
|
|
169
170
|
// `push final` worktree behavior now lives SERVER-side in handlers/reports.ts,
|
|
@@ -11,10 +11,12 @@ import { createHeadlessHarness } from '../../../../core/__tests__/helpers/harnes
|
|
|
11
11
|
import { updateNode } from '../../../../core/canvas/canvas.js';
|
|
12
12
|
import { armCron, getCron } from '../../../../core/canvas/crons.js';
|
|
13
13
|
import { closeDb } from '../../../../core/canvas/db.js';
|
|
14
|
+
import { closeWorktree, openWorktree } from '../../../../core/canvas/worktrees.js';
|
|
14
15
|
import { getDefaultProfileId, setDefaultProfileId, } from '../../../../core/profiles/default-binding.js';
|
|
15
16
|
import { loadProfileManifest } from '../../../../core/profiles/manifest.js';
|
|
16
17
|
import { createComment, getComment, listReviewEvents } from '../../../../core/review/comments.js';
|
|
17
|
-
import {
|
|
18
|
+
import { commitBindingRequest, openRequest } from '../../../../core/human/requests.js';
|
|
19
|
+
import { getReview } from '../../../../core/review/store.js';
|
|
18
20
|
import { apiSocketPath, nodeDir, nodesRoot, reviewDir, } from '../../../../core/canvas/paths.js';
|
|
19
21
|
import { isPidAlive } from '../../../../core/canvas/pid.js';
|
|
20
22
|
import { spawnNode } from '../../../../core/runtime/nodes.js';
|
|
@@ -66,47 +68,32 @@ function seedTicket(dir, sourceNodeId) {
|
|
|
66
68
|
writeFileSync(join(dir, 'page.json'), JSON.stringify({ source: { nodeId: sourceNodeId } }));
|
|
67
69
|
writeFileSync(join(dir, 'reply-route.json'), JSON.stringify({ nodeId: sourceNodeId }));
|
|
68
70
|
}
|
|
69
|
-
function
|
|
71
|
+
function reviewRequest(reviewId, originNodeId, sourceFile) {
|
|
70
72
|
const dir = reviewDir(reviewId);
|
|
71
73
|
return {
|
|
72
|
-
|
|
74
|
+
request_id: reviewId,
|
|
73
75
|
idempotency_key: `request-${reviewId}`,
|
|
74
|
-
|
|
75
|
-
origin_node_id: originNodeId,
|
|
76
|
-
bridge_node_id: null,
|
|
76
|
+
requester_node_id: originNodeId,
|
|
77
77
|
companion_node_id: `companion-${reviewId}`,
|
|
78
|
-
|
|
78
|
+
request_dir: dir,
|
|
79
79
|
file: sourceFile,
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
80
|
+
specification: {
|
|
81
|
+
origin_kind: 'inline',
|
|
82
|
+
origin_session_file: join(h.agentHome, `${reviewId}-origin.jsonl`),
|
|
83
|
+
origin_session_id: `session-${reviewId}`,
|
|
84
|
+
origin_leaf_id: `leaf-${reviewId}`,
|
|
85
|
+
model_spec: 'anthropic/sonnet',
|
|
86
|
+
branch_file: join(dir, 'branch-point.jsonl'),
|
|
87
|
+
baseline_sha256: 'baseline',
|
|
88
|
+
baseline_bytes: 6,
|
|
89
|
+
captured_at: new Date().toISOString(),
|
|
90
|
+
output_path: null,
|
|
91
|
+
},
|
|
87
92
|
anchor_base_sha256: 'anchor',
|
|
88
93
|
anchor_base_bytes: Buffer.from('source'),
|
|
89
|
-
|
|
90
|
-
created: new Date().toISOString(),
|
|
91
|
-
captured_at: new Date().toISOString(),
|
|
92
|
-
opened_at: null,
|
|
93
|
-
submit_requested_at: null,
|
|
94
|
-
output_path: null,
|
|
94
|
+
created_at: new Date().toISOString(),
|
|
95
95
|
subtitle: null,
|
|
96
|
-
|
|
97
|
-
approved_sha256: null,
|
|
98
|
-
changed: null,
|
|
99
|
-
comments_total: null,
|
|
100
|
-
comments_unresolved: null,
|
|
101
|
-
result_json: null,
|
|
102
|
-
canceled_at: null,
|
|
103
|
-
cancel_reason: null,
|
|
104
|
-
cancel_actor: null,
|
|
105
|
-
delivery_entry_id: null,
|
|
106
|
-
delivered_at: null,
|
|
107
|
-
delivery_error: null,
|
|
108
|
-
projected_at: null,
|
|
109
|
-
projection_error: null,
|
|
96
|
+
inbox_listed: false,
|
|
110
97
|
};
|
|
111
98
|
}
|
|
112
99
|
function seedReview(reviewId, originNodeId) {
|
|
@@ -115,7 +102,8 @@ function seedReview(reviewId, originNodeId) {
|
|
|
115
102
|
writeFileSync(sourceFile, 'source\n');
|
|
116
103
|
mkdirSync(dir, { recursive: true });
|
|
117
104
|
writeFileSync(join(dir, 'branch-point.jsonl'), '{}\n');
|
|
118
|
-
|
|
105
|
+
commitBindingRequest(reviewRequest(reviewId, originNodeId, sourceFile));
|
|
106
|
+
assert.equal(openRequest(reviewId, new Date().toISOString()), true, 'fixture review becomes visible before its comment is created');
|
|
119
107
|
const { comment } = createComment({
|
|
120
108
|
review_id: reviewId,
|
|
121
109
|
text: 'keep or delete with its review',
|
|
@@ -167,10 +155,8 @@ test('forced profile deletion owns the complete daemon lifecycle', { timeout: 90
|
|
|
167
155
|
// An open managed worktree blocks before any profile-owned state mutates.
|
|
168
156
|
const blockedProfile = await client.ensureProfile('delete-blocked');
|
|
169
157
|
const blockedNode = h.spawnRoot('profile delete blocker', { id: 'blocked-profile-deadbeef' });
|
|
170
|
-
updateNode(blockedNode, {
|
|
171
|
-
|
|
172
|
-
managed_worktree: managedWorktree(),
|
|
173
|
-
});
|
|
158
|
+
updateNode(blockedNode, { profile_id: blockedProfile.id });
|
|
159
|
+
openWorktree(blockedNode, managedWorktree());
|
|
174
160
|
const blockedPin = join(h.agentHome, 'blocked-pin');
|
|
175
161
|
mkdirSync(blockedPin, { recursive: true });
|
|
176
162
|
setDefaultProfileId(blockedPin, blockedProfile.id);
|
|
@@ -368,12 +354,12 @@ test('forced profile deletion owns the complete daemon lifecycle', { timeout: 90
|
|
|
368
354
|
});
|
|
369
355
|
assert.equal(h.node(selfNode)?.profile_id, selfProfile.id, 'the 202 response settles before node mutation');
|
|
370
356
|
assert.equal(isPidAlive(selfPid), true, 'the 202 response settles before broker teardown');
|
|
371
|
-
|
|
357
|
+
openWorktree(selfNode, managedWorktree());
|
|
372
358
|
const repeatedAccepted = await rawDelete(selfProfile.id, {
|
|
373
359
|
force: true,
|
|
374
360
|
caller_node_id: selfNode,
|
|
375
361
|
});
|
|
376
|
-
|
|
362
|
+
closeWorktree(selfNode, { cleanup: 'complete', closedAt: new Date().toISOString() });
|
|
377
363
|
assert.equal(repeatedAccepted.status, 202, 'a retry returns the accepted result before observing new blockers');
|
|
378
364
|
assert.deepEqual(repeatedAccepted.body, accepted.body, 'a pending self-deletion is idempotent by profile identity');
|
|
379
365
|
await h.waitFor(() => h.node(selfNode) === null, {
|
|
@@ -7,8 +7,8 @@ import { after, before, beforeEach, test } from 'node:test';
|
|
|
7
7
|
import assert from 'node:assert/strict';
|
|
8
8
|
import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
|
|
9
9
|
import { dirname } from 'node:path';
|
|
10
|
-
import { createNode, getNode
|
|
11
|
-
import { closeDb } from '../../../core/canvas/db.js';
|
|
10
|
+
import { createNode, getNode } from '../../../core/canvas/index.js';
|
|
11
|
+
import { closeDb, migrate, openDb } from '../../../core/canvas/db.js';
|
|
12
12
|
import { InputError } from '../../../core/io.js';
|
|
13
13
|
import { outputResultPath, outputSchemaPath, writeOutputSchema, } from '../../../core/runtime/structured-output.js';
|
|
14
14
|
import { reportRoutes } from '../handlers/reports.js';
|
|
@@ -23,6 +23,7 @@ before(() => {
|
|
|
23
23
|
beforeEach(() => {
|
|
24
24
|
closeDb();
|
|
25
25
|
rmSync(home, { recursive: true, force: true });
|
|
26
|
+
migrate(openDb());
|
|
26
27
|
});
|
|
27
28
|
after(() => {
|
|
28
29
|
closeDb();
|
|
@@ -25,7 +25,7 @@ import { isSafeNodeId, viewSocketPath } from '../../core/canvas/paths.js';
|
|
|
25
25
|
import { getNode } from '../../core/canvas/index.js';
|
|
26
26
|
import { BROKER_READ_CAPS, CLIENT_READ_CAPS, FrameDecoder, FrameOverflowError, } from '../../core/runtime/broker-protocol.js';
|
|
27
27
|
import { classify } from '../../core/fault-classifier.js';
|
|
28
|
-
import { clearFault, recordFault } from '../../core/
|
|
28
|
+
import { clearFault, recordFault } from '../../core/canvas/recovery.js';
|
|
29
29
|
import { decideAttachRevive } from '../../core/runtime/revive.js';
|
|
30
30
|
import { probeViewSocket, waitForBrokerViewSocket } from '../../core/runtime/view-socket.js';
|
|
31
31
|
/** Our own noServer WS server: A-9 routes matched attach upgrades to
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
// Daemon-owned read and stop surfaces for one node's file-backed background
|
|
2
2
|
// bash jobs. The attach roster continues to read the same directory directly;
|
|
3
3
|
// these routes exist for remote presenters that cannot see the node host.
|
|
4
|
-
import {
|
|
4
|
+
import { enqueueNodeMail } from '../../../core/feed/messages.js';
|
|
5
5
|
import { contextDir, isSafeNodeId } from '../../../core/canvas/paths.js';
|
|
6
6
|
import { getNode } from '../../../core/canvas/canvas.js';
|
|
7
|
-
import { cancelCronsOnWake } from '../../../core/canvas/crons.js';
|
|
8
7
|
import { isBrokerLive } from '../../../core/runtime/model-swap.js';
|
|
9
8
|
import { assertNotFinalized } from '../../../core/runtime/reopen.js';
|
|
10
9
|
import { reviveNode } from '../../../core/runtime/revive.js';
|
|
@@ -68,14 +67,14 @@ async function handleStop(ctx) {
|
|
|
68
67
|
assertNotFinalized(nodeId);
|
|
69
68
|
const paths = bashJobPaths(dir, jobId);
|
|
70
69
|
const body = `Background bash job ${jobId} was stopped by the user before it finished. Log: ${paths.jobLog} Command: ${paths.cmdSh}`;
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
70
|
+
enqueueNodeMail(nodeId, {
|
|
71
|
+
senderNodeId: null,
|
|
72
|
+
urgency: 'urgent',
|
|
73
|
+
wake: 1,
|
|
74
74
|
kind: 'message',
|
|
75
75
|
label: body.split('\n')[0].slice(0, 120),
|
|
76
|
-
|
|
76
|
+
bodyJson: { body },
|
|
77
77
|
});
|
|
78
|
-
cancelCronsOnWake(nodeId);
|
|
79
78
|
const node = getNode(nodeId);
|
|
80
79
|
if (node !== null && !isBrokerLive(node)) {
|
|
81
80
|
try {
|
|
@@ -1,26 +1,28 @@
|
|
|
1
1
|
// Broker-originated canvas operations. The broker sends Pi lifecycle facts;
|
|
2
2
|
// crtrd validates and commits their durable effects while the handler stays
|
|
3
3
|
// strictly canvas-write-only — no broker launch, kill, or view.sock round trip.
|
|
4
|
-
import { canonicalSessionFile, findNodeBySessionFile, getNode, isWarmSpare, listNodeIdentities,
|
|
4
|
+
import { canonicalSessionFile, findNodeBySessionFile, getNode, isWarmSpare, listNodeIdentities, recordSettledTurn, setPresence, subscriptionsOf, updateNode } from '../../../core/canvas/canvas.js';
|
|
5
|
+
import { recordExecutionPid } from '../../../core/canvas/executions.js';
|
|
6
|
+
import { bindSession, readLiveSession, transferSession } from '../../../core/canvas/sessions.js';
|
|
5
7
|
import { isSafeNodeId } from '../../../core/canvas/paths.js';
|
|
6
8
|
import { isPidAlive } from '../../../core/canvas/pid.js';
|
|
7
9
|
import { editorLabel } from '../../../core/canvas/labels.js';
|
|
8
10
|
import { assembleNodeSubject } from '../../../core/substrate/subject.js';
|
|
9
11
|
import { withCanvasWrite } from '../../../core/canvas/db.js';
|
|
10
12
|
import { notFound, usage } from '../../../core/errors.js';
|
|
11
|
-
import { hasUnseenWakeMail
|
|
13
|
+
import { hasUnseenWakeMail } from '../../../core/canvas/deliveries.js';
|
|
12
14
|
import { clearYieldMessage } from '../../../core/runtime/kickoff.js';
|
|
13
15
|
import { transition } from '../../../core/runtime/lifecycle.js';
|
|
14
16
|
import { focusOf, tearDownNode } from '../../../core/runtime/placement.js';
|
|
15
17
|
import { hasAttachedBrokerViewers } from '../../../core/runtime/broker/client-registry.js';
|
|
16
|
-
import { handleNewSession } from '../../../core/runtime/reset.js';
|
|
17
18
|
import { evaluateStop } from '../../../core/runtime/stop-guard.js';
|
|
18
|
-
import { clearFault, recordFault } from '../../../core/
|
|
19
|
+
import { clearFault, recordFault } from '../../../core/canvas/recovery.js';
|
|
19
20
|
import { updateModelRecipe } from '../../../core/runtime/model-swap.js';
|
|
20
21
|
import { completeCompanionRequestedSubmit } from '../../review/finish.js';
|
|
21
22
|
import { emitEvent } from '../../../core/events/emit.js';
|
|
22
23
|
import { consumePendingPark, recordPendingParkActivity } from '../../park-pending.js';
|
|
23
24
|
import { shouldParkAfterSummary } from '../../park-activity.js';
|
|
25
|
+
import { requireCurrentExecution } from './broker-recovery.js';
|
|
24
26
|
function objectBody(body, operation) {
|
|
25
27
|
if (typeof body !== 'object' || body === null || Array.isArray(body)) {
|
|
26
28
|
throw usage(`${operation} requires a JSON body`);
|
|
@@ -29,6 +31,9 @@ function objectBody(body, operation) {
|
|
|
29
31
|
}
|
|
30
32
|
function parseSessionBoundBody(body) {
|
|
31
33
|
const value = objectBody(body, 'broker session-bound');
|
|
34
|
+
if (typeof value['executionId'] !== 'string' || value['executionId'] === '') {
|
|
35
|
+
throw usage('executionId must be a non-empty string');
|
|
36
|
+
}
|
|
32
37
|
if (typeof value['piSessionId'] !== 'string' || value['piSessionId'] === '') {
|
|
33
38
|
throw usage('piSessionId must be a non-empty string');
|
|
34
39
|
}
|
|
@@ -64,18 +69,6 @@ function parseParkCompleteBody(body) {
|
|
|
64
69
|
}
|
|
65
70
|
return value;
|
|
66
71
|
}
|
|
67
|
-
function parseInboxCursorBody(body) {
|
|
68
|
-
const value = objectBody(body, 'broker inbox-cursor');
|
|
69
|
-
const throughEntryId = value['throughEntryId'];
|
|
70
|
-
if (typeof throughEntryId !== 'string' || !/^(?!0{32}$)[0-9a-f]{32}$/.test(throughEntryId)) {
|
|
71
|
-
throw usage('throughEntryId must be a non-zero 32-character lowercase hexadecimal inbox entry id');
|
|
72
|
-
}
|
|
73
|
-
const brokerPid = value['brokerPid'];
|
|
74
|
-
if (!Number.isSafeInteger(brokerPid) || brokerPid <= 0) {
|
|
75
|
-
throw usage('brokerPid must be a positive safe integer');
|
|
76
|
-
}
|
|
77
|
-
return { throughEntryId, brokerPid: brokerPid };
|
|
78
|
-
}
|
|
79
72
|
function parseModelCommitBody(body) {
|
|
80
73
|
const value = objectBody(body, 'broker model');
|
|
81
74
|
if (typeof value['spec'] !== 'string' || value['spec'].trim() === '')
|
|
@@ -167,14 +160,14 @@ function parseGeneratedNameBody(body) {
|
|
|
167
160
|
throw usage('description, title, and icon must be strings');
|
|
168
161
|
}
|
|
169
162
|
if (value['kind'] === 'initial') {
|
|
170
|
-
return
|
|
163
|
+
return value;
|
|
171
164
|
}
|
|
172
165
|
const expected = value['expected'];
|
|
173
166
|
if (typeof expected !== 'object' || expected === null || Array.isArray(expected)
|
|
174
167
|
|| ['name', 'description', 'title', 'icon', 'kind'].some((key) => typeof expected[key] !== 'string')) {
|
|
175
168
|
throw usage('recap expected must contain name, description, title, icon, and kind strings');
|
|
176
169
|
}
|
|
177
|
-
return
|
|
170
|
+
return value;
|
|
178
171
|
}
|
|
179
172
|
function parsePersonaAckBody(body) {
|
|
180
173
|
const value = objectBody(body, 'broker persona-ack');
|
|
@@ -188,7 +181,7 @@ function parsePersonaAckBody(body) {
|
|
|
188
181
|
}
|
|
189
182
|
return persona;
|
|
190
183
|
};
|
|
191
|
-
return { from: parse('from'), to: parse('to') };
|
|
184
|
+
return { expected_execution_id: value['expected_execution_id'], from: parse('from'), to: parse('to') };
|
|
192
185
|
}
|
|
193
186
|
function handleSessionBound(ctx) {
|
|
194
187
|
const nodeId = ctx.params['id'];
|
|
@@ -196,9 +189,18 @@ function handleSessionBound(ctx) {
|
|
|
196
189
|
const sessionFile = request.sessionFile === null ? null : canonicalSessionFile(request.sessionFile);
|
|
197
190
|
const result = withCanvasWrite(() => {
|
|
198
191
|
const before = requireNode(nodeId);
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
192
|
+
if (recordExecutionPid(request.executionId, nodeId, request.pid) === 'shutdown') {
|
|
193
|
+
return { action: 'shutdown' };
|
|
194
|
+
}
|
|
195
|
+
const reviewId = before.review_binding?.review_id;
|
|
196
|
+
if (reviewId !== undefined && !request.reviewBoundaryIds.includes(reviewId)) {
|
|
197
|
+
return { action: 'shutdown' };
|
|
198
|
+
}
|
|
199
|
+
if (request.reason === 'new' && before.parent == null)
|
|
200
|
+
return { action: 'relaunch_root' };
|
|
201
|
+
if (request.reason !== 'new' && before.fork_from != null && before.pi_session_id == null && sessionFile === null) {
|
|
202
|
+
return { action: 'shutdown' };
|
|
203
|
+
}
|
|
202
204
|
const owner = sessionFile === null ? null : findNodeBySessionFile(sessionFile);
|
|
203
205
|
if (owner !== null && owner.node_id !== nodeId) {
|
|
204
206
|
if (isPidAlive(owner.pi_pid)) {
|
|
@@ -211,46 +213,29 @@ function handleSessionBound(ctx) {
|
|
|
211
213
|
});
|
|
212
214
|
return { action: 'shutdown' };
|
|
213
215
|
}
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
216
|
+
const source = readLiveSession(owner.node_id);
|
|
217
|
+
if (source === null || transferSession({
|
|
218
|
+
fromNodeId: owner.node_id,
|
|
219
|
+
fromBindingId: source.bindingId,
|
|
220
|
+
toNodeId: nodeId,
|
|
221
|
+
executionId: request.executionId,
|
|
222
|
+
sessionId: request.piSessionId,
|
|
223
|
+
transcriptPath: sessionFile,
|
|
224
|
+
}) !== 'transferred')
|
|
225
|
+
return { action: 'shutdown' };
|
|
217
226
|
}
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
227
|
+
else if (bindSession(nodeId, {
|
|
228
|
+
executionId: request.executionId,
|
|
229
|
+
sessionId: request.piSessionId,
|
|
230
|
+
transcriptPath: sessionFile,
|
|
231
|
+
}) === 'shutdown')
|
|
222
232
|
return { action: 'shutdown' };
|
|
223
|
-
|
|
224
|
-
let action = 'none';
|
|
225
|
-
if (request.reason === 'new') {
|
|
226
|
-
if (before.parent == null) {
|
|
227
|
-
// Root relaunch launches and tears down brokers. Return a directive for
|
|
228
|
-
// the calling extension rather than re-entering that broker here.
|
|
229
|
-
action = 'relaunch_root';
|
|
230
|
-
}
|
|
231
|
-
else {
|
|
232
|
-
handleNewSession(nodeId, request.piSessionId, sessionFile);
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
else if (before.fork_from != null && before.pi_session_id == null && sessionFile === null) {
|
|
236
|
-
// Pi has not exposed complete writable coordinates for this ordinary fork.
|
|
237
|
-
// Leave it unbound so recovery cannot fork provenance twice.
|
|
238
|
-
action = 'shutdown';
|
|
239
|
-
}
|
|
240
|
-
else {
|
|
241
|
-
// Confirmed boot: consume the one-shot yield note, bind the new Pi session
|
|
242
|
-
// coordinates, stamp broker liveness, and commit any pending refresh.
|
|
233
|
+
if (request.reason !== 'new') {
|
|
243
234
|
clearYieldMessage(nodeId);
|
|
244
|
-
updateNode(nodeId, {
|
|
245
|
-
pi_session_id: request.piSessionId,
|
|
246
|
-
pi_session_file: sessionFile,
|
|
247
|
-
cycle_pending: false,
|
|
248
|
-
});
|
|
249
|
-
recordPid(nodeId, request.pid);
|
|
250
235
|
if (before.intent === 'refresh')
|
|
251
236
|
transition(nodeId, 'revive');
|
|
252
237
|
}
|
|
253
|
-
return { action };
|
|
238
|
+
return { action: 'none' };
|
|
254
239
|
});
|
|
255
240
|
return { status: 200, body: result };
|
|
256
241
|
}
|
|
@@ -324,6 +309,7 @@ function settleBroker(nodeId, request) {
|
|
|
324
309
|
function handleSettle(ctx) {
|
|
325
310
|
const nodeId = ctx.params['id'];
|
|
326
311
|
const request = parseSettleBody(ctx.body);
|
|
312
|
+
requireCurrentExecution(nodeId, request.expected_execution_id);
|
|
327
313
|
const directive = withCanvasWrite(() => settleBroker(nodeId, request));
|
|
328
314
|
// A review companion that just went quiet releases any submit the human left
|
|
329
315
|
// waiting on it. A reprompt is not going quiet, so it waits for the turn that
|
|
@@ -340,6 +326,7 @@ function handleSettle(ctx) {
|
|
|
340
326
|
function handleParkComplete(ctx) {
|
|
341
327
|
const nodeId = ctx.params['id'];
|
|
342
328
|
const request = parseParkCompleteBody(ctx.body);
|
|
329
|
+
requireCurrentExecution(nodeId, request.expected_execution_id);
|
|
343
330
|
const directive = withCanvasWrite(() => {
|
|
344
331
|
const pending = consumePendingPark(nodeId);
|
|
345
332
|
if (pending === undefined)
|
|
@@ -367,41 +354,16 @@ function handleParkComplete(ctx) {
|
|
|
367
354
|
* never terminalize a viewer or live-delivery input that won admission. */
|
|
368
355
|
function handleParkActivity(ctx) {
|
|
369
356
|
const nodeId = ctx.params['id'];
|
|
357
|
+
requireCurrentExecution(nodeId, objectBody(ctx.body, 'broker park-activity')['expected_execution_id']);
|
|
370
358
|
const result = withCanvasWrite(() => ({
|
|
371
359
|
activity: recordPendingParkActivity(nodeId) ? 'recorded' : 'none',
|
|
372
360
|
}));
|
|
373
361
|
return { status: 200, body: result };
|
|
374
362
|
}
|
|
375
|
-
/** Commit a watcher cursor only while this broker generation remains current.
|
|
376
|
-
* A refresh or a replacement binding must leave the cursor untouched so the
|
|
377
|
-
* replacement replays every handoff that may have reached the discarded Pi
|
|
378
|
-
* conversation. */
|
|
379
|
-
function handleInboxCursor(ctx) {
|
|
380
|
-
const nodeId = ctx.params['id'];
|
|
381
|
-
const request = parseInboxCursorBody(ctx.body);
|
|
382
|
-
const directive = withCanvasWrite(() => {
|
|
383
|
-
const node = requireNode(nodeId);
|
|
384
|
-
if (node.intent === 'refresh' || node.pi_pid !== request.brokerPid)
|
|
385
|
-
return { action: 'hold_refresh' };
|
|
386
|
-
const entries = readInboxSince(nodeId);
|
|
387
|
-
const throughIndex = entries.findIndex((entry) => entry.entry_id === request.throughEntryId);
|
|
388
|
-
if (throughIndex < 0)
|
|
389
|
-
throw usage('throughEntryId must identify an entry in this node inbox');
|
|
390
|
-
const cursor = readCursor(nodeId);
|
|
391
|
-
const cursorIndex = cursor === undefined ? -1 : entries.findIndex((entry) => entry.entry_id === cursor);
|
|
392
|
-
if (cursor !== undefined && cursorIndex < 0)
|
|
393
|
-
throw new Error(`inbox cursor entry_id not found: ${cursor}`);
|
|
394
|
-
if (throughIndex < cursorIndex)
|
|
395
|
-
throw usage('throughEntryId must not precede the durable inbox cursor');
|
|
396
|
-
if (throughIndex > cursorIndex)
|
|
397
|
-
writeCursor(nodeId, request.throughEntryId);
|
|
398
|
-
return { action: 'advanced' };
|
|
399
|
-
});
|
|
400
|
-
return { status: 200, body: directive };
|
|
401
|
-
}
|
|
402
363
|
function handleModelCommit(ctx) {
|
|
403
364
|
const nodeId = ctx.params['id'];
|
|
404
365
|
const request = parseModelCommitBody(ctx.body);
|
|
366
|
+
requireCurrentExecution(nodeId, request.expected_execution_id);
|
|
405
367
|
const updated = withCanvasWrite(() => updateModelRecipe(requireNode(nodeId), request.spec, request.pinnedOverride, request.userSelected));
|
|
406
368
|
return { status: 200, body: { modelOverride: updated.model_override } };
|
|
407
369
|
}
|
|
@@ -414,6 +376,7 @@ function handleExtensionState(ctx) {
|
|
|
414
376
|
function handleGeneratedName(ctx) {
|
|
415
377
|
const nodeId = ctx.params['id'];
|
|
416
378
|
const request = parseGeneratedNameBody(ctx.body);
|
|
379
|
+
requireCurrentExecution(nodeId, request.expected_execution_id);
|
|
417
380
|
const result = withCanvasWrite(() => {
|
|
418
381
|
const node = requireNode(nodeId);
|
|
419
382
|
if (request.kind === 'initial') {
|
|
@@ -457,6 +420,7 @@ function handleGeneratedName(ctx) {
|
|
|
457
420
|
function handlePersonaAck(ctx) {
|
|
458
421
|
const nodeId = ctx.params['id'];
|
|
459
422
|
const request = parsePersonaAckBody(ctx.body);
|
|
423
|
+
requireCurrentExecution(nodeId, request.expected_execution_id);
|
|
460
424
|
const result = withCanvasWrite(() => {
|
|
461
425
|
const node = requireNode(nodeId);
|
|
462
426
|
const current = { kind: node.kind, mode: node.mode, lifecycle: node.lifecycle };
|
|
@@ -476,7 +440,6 @@ export const brokerOperationRoutes = [
|
|
|
476
440
|
{ method: 'POST', pattern: '/v1/nodes/:id/broker/settle', handler: handleSettle },
|
|
477
441
|
{ method: 'POST', pattern: '/v1/nodes/:id/broker/park-complete', handler: handleParkComplete },
|
|
478
442
|
{ method: 'POST', pattern: '/v1/nodes/:id/broker/park-activity', handler: handleParkActivity },
|
|
479
|
-
{ method: 'POST', pattern: '/v1/nodes/:id/broker/inbox-cursor', handler: handleInboxCursor },
|
|
480
443
|
{ method: 'POST', pattern: '/v1/nodes/:id/broker/model', handler: handleModelCommit },
|
|
481
444
|
{ method: 'GET', pattern: '/v1/nodes/:id/broker/extension-state', handler: handleExtensionState },
|
|
482
445
|
{ method: 'POST', pattern: '/v1/nodes/:id/broker/generated-name', handler: handleGeneratedName },
|