@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
|
@@ -5,27 +5,26 @@
|
|
|
5
5
|
import { test, before, after, beforeEach, afterEach } from 'node:test';
|
|
6
6
|
import assert from 'node:assert/strict';
|
|
7
7
|
import { existsSync, mkdtempSync, mkdirSync, realpathSync, rmSync, writeFileSync } from 'node:fs';
|
|
8
|
-
import { createServer } from 'node:http';
|
|
9
8
|
import { tmpdir } from 'node:os';
|
|
10
9
|
import { join } from 'node:path';
|
|
11
10
|
import { registerCanvasContextIntro, CONTEXT_INTRO_CUSTOM_TYPE, } from '../canvas-context-intro.js';
|
|
12
11
|
import { registerCanvasDocSubstrate } from '../canvas-doc-substrate.js';
|
|
13
12
|
import { buildContextBearings as buildContextIntro } from '../../core/runtime/bearings.js';
|
|
14
13
|
import { installPersonaTransitionGate } from '../../core/runtime/broker-persona-guidance.js';
|
|
15
|
-
import { FaultRetry } from '../../core/runtime/broker/fault-retry.js';
|
|
16
|
-
import { readFault } from '../../core/runtime/fault.js';
|
|
17
|
-
import { ApiError } from '../../api/errors.js';
|
|
18
14
|
import { createNode, deleteNode, getNode, updateNode } from '../../core/canvas/canvas.js';
|
|
19
15
|
import { apiSocketPath } from '../../core/canvas/paths.js';
|
|
20
16
|
import { createApiServer } from '../../daemon/api/server.js';
|
|
21
|
-
import { closeDb } from '../../core/canvas/db.js';
|
|
17
|
+
import { closeDb, migrate, openDb } from '../../core/canvas/db.js';
|
|
18
|
+
import { beginExecution } from '../../core/canvas/executions.js';
|
|
22
19
|
import { resetScopeCache } from '../../core/scope.js';
|
|
20
|
+
import { initializeFreshScopedStore } from '../../core/scoped-state/migrate.js';
|
|
23
21
|
import { clearSessionCache } from '../../core/substrate/session-cache.js';
|
|
24
22
|
import { emptyContextExposureState, exposureTarget, initializeForkContextExposure, loadContextExposureState, registerExposure, saveContextExposureState, } from '../../core/substrate/injected-store.js';
|
|
25
23
|
let home;
|
|
26
24
|
let origCwd;
|
|
27
25
|
let origHome;
|
|
28
26
|
let origNode;
|
|
27
|
+
let origExecution;
|
|
29
28
|
let origProfile;
|
|
30
29
|
let server;
|
|
31
30
|
async function waitForSocket(path) {
|
|
@@ -36,22 +35,9 @@ async function waitForSocket(path) {
|
|
|
36
35
|
}
|
|
37
36
|
throw new Error(`api socket never bound at ${path}`);
|
|
38
37
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
response.end(JSON.stringify({ error: { code: 'daemon_unavailable', message: 'local daemon connection refused' } }));
|
|
43
|
-
});
|
|
44
|
-
await new Promise((resolve, reject) => {
|
|
45
|
-
unavailable.once('error', reject);
|
|
46
|
-
unavailable.listen(path, () => {
|
|
47
|
-
unavailable.off('error', reject);
|
|
48
|
-
resolve();
|
|
49
|
-
});
|
|
50
|
-
});
|
|
51
|
-
return unavailable;
|
|
52
|
-
}
|
|
53
|
-
function closeHttpServer(server) {
|
|
54
|
-
return new Promise((resolve, reject) => server.close((error) => error === undefined ? resolve() : reject(error)));
|
|
38
|
+
function activateBroker(id) {
|
|
39
|
+
process.env['CRTR_NODE_ID'] = id;
|
|
40
|
+
process.env['CRTR_EXECUTION_ID'] = beginExecution(id, { daemonEpoch: null });
|
|
55
41
|
}
|
|
56
42
|
function node(id, over = {}) {
|
|
57
43
|
return {
|
|
@@ -102,6 +88,7 @@ before(() => {
|
|
|
102
88
|
origCwd = process.cwd();
|
|
103
89
|
origHome = process.env['HOME'];
|
|
104
90
|
origNode = process.env['CRTR_NODE_ID'];
|
|
91
|
+
origExecution = process.env['CRTR_EXECUTION_ID'];
|
|
105
92
|
origProfile = process.env['CRTR_PROFILE_ID'];
|
|
106
93
|
});
|
|
107
94
|
beforeEach(async () => {
|
|
@@ -116,9 +103,12 @@ beforeEach(async () => {
|
|
|
116
103
|
process.env['HOME'] = userHome;
|
|
117
104
|
process.env['CRTR_HOME'] = home;
|
|
118
105
|
delete process.env['CRTR_NODE_ID'];
|
|
106
|
+
delete process.env['CRTR_EXECUTION_ID'];
|
|
119
107
|
delete process.env['CRTR_PROFILE_ID'];
|
|
120
108
|
resetScopeCache();
|
|
121
109
|
clearSessionCache();
|
|
110
|
+
initializeFreshScopedStore({ kind: 'user', root: join(userHome, '.crouter') });
|
|
111
|
+
migrate(openDb());
|
|
122
112
|
server = createApiServer();
|
|
123
113
|
await waitForSocket(apiSocketPath());
|
|
124
114
|
});
|
|
@@ -146,6 +136,10 @@ after(() => {
|
|
|
146
136
|
delete process.env['CRTR_NODE_ID'];
|
|
147
137
|
else
|
|
148
138
|
process.env['CRTR_NODE_ID'] = origNode;
|
|
139
|
+
if (origExecution === undefined)
|
|
140
|
+
delete process.env['CRTR_EXECUTION_ID'];
|
|
141
|
+
else
|
|
142
|
+
process.env['CRTR_EXECUTION_ID'] = origExecution;
|
|
149
143
|
if (origProfile === undefined)
|
|
150
144
|
delete process.env['CRTR_PROFILE_ID'];
|
|
151
145
|
else
|
|
@@ -167,7 +161,7 @@ test('session_start appends compact fork bearings after an inherited source base
|
|
|
167
161
|
const forkExposure = loadContextExposureState('forkB');
|
|
168
162
|
assert.deepEqual(forkExposure.exposures.get('inherited-source-document'), { transcript: 3 }, 'a pre-bind retry preserves the transcript exposure seed after its source disappears');
|
|
169
163
|
assert.equal(forkExposure.exposures.has('source-system-only'), false, 'a fork never inherits source system exposure');
|
|
170
|
-
|
|
164
|
+
activateBroker('forkB');
|
|
171
165
|
const pi = makeFakePi();
|
|
172
166
|
registerCanvasContextIntro(pi);
|
|
173
167
|
await pi.fireSessionStart([inheritedSourceBlock]);
|
|
@@ -184,7 +178,7 @@ test('session_start appends compact fork bearings after an inherited source base
|
|
|
184
178
|
const unknownPreState = loadContextExposureState('unknownF');
|
|
185
179
|
assert.equal(unknownPreState.exposures.size, 0);
|
|
186
180
|
assert.equal(unknownPreState.preferenceSnapshot, null);
|
|
187
|
-
|
|
181
|
+
activateBroker('unknownF');
|
|
188
182
|
const unknownPi = makeFakePi();
|
|
189
183
|
registerCanvasContextIntro(unknownPi);
|
|
190
184
|
await unknownPi.fireSessionStart([inheritedSourceBlock]);
|
|
@@ -202,7 +196,7 @@ test('root /new leaves baseline assembly to the replacement broker', async () =>
|
|
|
202
196
|
exposure.preferenceSnapshot = 'ORIGINAL-SNAPSHOT';
|
|
203
197
|
registerExposure(exposureTarget(exposure, 'transcript'), 'original-transcript', 'content');
|
|
204
198
|
saveContextExposureState('root-new', exposure);
|
|
205
|
-
|
|
199
|
+
activateBroker('root-new');
|
|
206
200
|
const pi = makeFakePi();
|
|
207
201
|
registerCanvasContextIntro(pi);
|
|
208
202
|
await pi.fireSessionStart([], 'new');
|
|
@@ -240,7 +234,7 @@ test('child /new commits its baseline before ack and the provider gate delivers
|
|
|
240
234
|
persona_ack: oldPersona,
|
|
241
235
|
}));
|
|
242
236
|
mkdirSync(join(home, 'nodes', 'new-child'), { recursive: true });
|
|
243
|
-
|
|
237
|
+
activateBroker('new-child');
|
|
244
238
|
const sessionStartHandlers = [];
|
|
245
239
|
const sent = [];
|
|
246
240
|
const branch = [];
|
|
@@ -343,68 +337,6 @@ test('child /new commits its baseline before ack and the provider gate delivers
|
|
|
343
337
|
process.env['CRTR_PROFILE_ID'] = previousProfile;
|
|
344
338
|
}
|
|
345
339
|
});
|
|
346
|
-
test('a typed local API error remains a retryable broker-to-daemon fault after settlement', async () => {
|
|
347
|
-
createNode(node('persona-transport', {
|
|
348
|
-
persona_ack: { kind: 'review', mode: 'base', lifecycle: 'terminal' },
|
|
349
|
-
}));
|
|
350
|
-
await server.close();
|
|
351
|
-
let unavailable;
|
|
352
|
-
try {
|
|
353
|
-
unavailable = await listenUnavailableApi(apiSocketPath());
|
|
354
|
-
const messages = [];
|
|
355
|
-
const agent = {
|
|
356
|
-
state: { messages },
|
|
357
|
-
transformContext: async (context) => context,
|
|
358
|
-
};
|
|
359
|
-
installPersonaTransitionGate('persona-transport', {
|
|
360
|
-
agent,
|
|
361
|
-
sessionManager: {
|
|
362
|
-
appendCustomMessageEntry: () => undefined,
|
|
363
|
-
},
|
|
364
|
-
});
|
|
365
|
-
await assert.rejects(() => agent.transformContext([{ role: 'user', content: 'continue' }]), (error) => error instanceof ApiError && error.status === 503 && error.code === 'daemon_unavailable');
|
|
366
|
-
assert.deepEqual(readFault('persona-transport'), {
|
|
367
|
-
link: 'broker↔crtrd',
|
|
368
|
-
op: 'persona transition',
|
|
369
|
-
kind: 'connection',
|
|
370
|
-
retry: { disposition: 'manual' },
|
|
371
|
-
message: 'local daemon connection refused',
|
|
372
|
-
since: readFault('persona-transport')?.since,
|
|
373
|
-
operation_id: readFault('persona-transport')?.operation_id,
|
|
374
|
-
}, 'the typed daemon transport error is recorded before Pi turns it into a generic agent error');
|
|
375
|
-
const session = {
|
|
376
|
-
sessionManager: { getLeafId: () => 'persona-transport-leaf' },
|
|
377
|
-
model: undefined,
|
|
378
|
-
};
|
|
379
|
-
const generation = {
|
|
380
|
-
id: 1,
|
|
381
|
-
session,
|
|
382
|
-
fallback: { blocked: false },
|
|
383
|
-
stagedProviderAgentEnd: {
|
|
384
|
-
messages: [{ role: 'assistant', stopReason: 'error', errorMessage: 'local daemon connection refused' }],
|
|
385
|
-
},
|
|
386
|
-
stagedWatchdogAbort: false,
|
|
387
|
-
stagedRefreshAbort: false,
|
|
388
|
-
stagedOverflowFailure: null,
|
|
389
|
-
executingTools: new Set(),
|
|
390
|
-
};
|
|
391
|
-
new FaultRetry({
|
|
392
|
-
nodeId: 'persona-transport',
|
|
393
|
-
currentSession: () => session,
|
|
394
|
-
installedGeneration: () => generation,
|
|
395
|
-
}).publishSettledProviderFault(generation);
|
|
396
|
-
const fault = readFault('persona-transport');
|
|
397
|
-
assert.equal(fault?.link, 'broker↔crtrd');
|
|
398
|
-
assert.equal(fault?.kind, 'connection');
|
|
399
|
-
assert.equal(fault?.retry.disposition, 'manual');
|
|
400
|
-
}
|
|
401
|
-
finally {
|
|
402
|
-
if (unavailable !== undefined)
|
|
403
|
-
await closeHttpServer(unavailable);
|
|
404
|
-
server = createApiServer();
|
|
405
|
-
await waitForSocket(apiSocketPath());
|
|
406
|
-
}
|
|
407
|
-
});
|
|
408
340
|
test('resume idempotency uses the exact details stamp independent of block text', async () => {
|
|
409
341
|
createNode(node('stampD'));
|
|
410
342
|
// The exact node-id stamp is authoritative even when prose carries no id.
|
|
@@ -414,7 +346,7 @@ test('resume idempotency uses the exact details stamp independent of block text'
|
|
|
414
346
|
content: '<crtr-context dir="/elsewhere">bearings with no id in the text</crtr-context>',
|
|
415
347
|
details: { nodeId: 'stampD' },
|
|
416
348
|
};
|
|
417
|
-
|
|
349
|
+
activateBroker('stampD');
|
|
418
350
|
const pi = makeFakePi();
|
|
419
351
|
registerCanvasContextIntro(pi);
|
|
420
352
|
await pi.fireSessionStart([stampedNoIdInText]);
|
|
@@ -424,7 +356,7 @@ test('session_start stays idempotent on a genuine resume', async () => {
|
|
|
424
356
|
createNode(node('resumeC'));
|
|
425
357
|
// A resume restores this node's already-stamped bearings.
|
|
426
358
|
const ownBlock = introEntry(buildContextIntro('resumeC'));
|
|
427
|
-
|
|
359
|
+
activateBroker('resumeC');
|
|
428
360
|
const pi = makeFakePi();
|
|
429
361
|
registerCanvasContextIntro(pi);
|
|
430
362
|
await pi.fireSessionStart([ownBlock]);
|
|
@@ -22,9 +22,10 @@ import { tmpdir } from 'node:os';
|
|
|
22
22
|
import { join } from 'node:path';
|
|
23
23
|
import registerCanvasGoalCapture from '../canvas-goal-capture.js';
|
|
24
24
|
import { createNode } from '../../core/canvas/canvas.js';
|
|
25
|
-
import { closeDb } from '../../core/canvas/db.js';
|
|
25
|
+
import { closeDb, migrate, openDb } from '../../core/canvas/db.js';
|
|
26
26
|
import { apiSocketPath } from '../../core/canvas/paths.js';
|
|
27
27
|
import { buildReviveKickoff, drainBearings } from '../../core/runtime/kickoff.js';
|
|
28
|
+
import { beginExecution } from '../../core/canvas/executions.js';
|
|
28
29
|
let home;
|
|
29
30
|
let socket;
|
|
30
31
|
/** Every request line the extension's naming path sent to the daemon socket. */
|
|
@@ -62,6 +63,7 @@ async function waitForRequestMentioning(id) {
|
|
|
62
63
|
before(async () => {
|
|
63
64
|
home = mkdtempSync(join(tmpdir(), 'crtr-goal-capture-'));
|
|
64
65
|
process.env['CRTR_HOME'] = home;
|
|
66
|
+
migrate(openDb());
|
|
65
67
|
// A stub daemon: it records the request and answers a typed error, so the
|
|
66
68
|
// naming path fails fast (and silently, as it must) without any model call.
|
|
67
69
|
// It must ANSWER rather than hang up — the api client reads a mid-request
|
|
@@ -89,7 +91,7 @@ after(async () => {
|
|
|
89
91
|
});
|
|
90
92
|
test('a fresh-revive kickoff seeds no mandate and no name; a human first message seeds both', async () => {
|
|
91
93
|
const revived = createNode(node('revived-node'));
|
|
92
|
-
const kickoff = buildReviveKickoff(revived, drainBearings(revived));
|
|
94
|
+
const kickoff = buildReviveKickoff(revived, drainBearings(revived, beginExecution(revived.node_id, { daemonEpoch: 'test' })));
|
|
93
95
|
process.env['CRTR_NODE_ID'] = revived.node_id;
|
|
94
96
|
handler()({ type: 'input', text: kickoff, source: 'interactive' });
|
|
95
97
|
const bare = createNode(node('bare-root'));
|
|
@@ -17,20 +17,26 @@ import { join } from 'node:path';
|
|
|
17
17
|
import registerCanvasStophook from '../canvas-stophook.js';
|
|
18
18
|
import { createNode, subscribe, getNode, setStatus } from '../../core/canvas/canvas.js';
|
|
19
19
|
import { openFocusRow, getFocusByNode, getFocusById, listFocuses } from '../../core/canvas/focuses.js';
|
|
20
|
-
import { closeDb } from '../../core/canvas/db.js';
|
|
20
|
+
import { closeDb, migrate, openDb } from '../../core/canvas/db.js';
|
|
21
21
|
import { apiSocketPath } from '../../core/canvas/paths.js';
|
|
22
22
|
import { createApiServer } from '../../daemon/api/server.js';
|
|
23
23
|
import { CrtrClient } from '../../api/client.js';
|
|
24
24
|
import { reportsDir } from '../../core/canvas/paths.js';
|
|
25
|
-
import {
|
|
25
|
+
import { enqueueNodeMail } from '../../core/feed/messages.js';
|
|
26
|
+
import { hasUnseenWakeMail } from '../../core/canvas/deliveries.js';
|
|
26
27
|
import { STALL_REPROMPT } from '../../core/runtime/stop-guard.js';
|
|
27
28
|
import { markStopSignal } from '../../core/runtime/stop-signals.js';
|
|
28
|
-
import {
|
|
29
|
-
import {
|
|
29
|
+
import { readFault, readLiveTurn, recordFault } from '../../core/canvas/recovery.js';
|
|
30
|
+
import { beginExecution } from '../../core/canvas/executions.js';
|
|
30
31
|
let home;
|
|
31
32
|
let server;
|
|
32
33
|
let origNode;
|
|
34
|
+
let origExecution;
|
|
33
35
|
let origPane;
|
|
36
|
+
function activateBroker(nodeId) {
|
|
37
|
+
process.env['CRTR_NODE_ID'] = nodeId;
|
|
38
|
+
process.env['CRTR_EXECUTION_ID'] = beginExecution(nodeId, { daemonEpoch: null });
|
|
39
|
+
}
|
|
34
40
|
function node(id, over = {}) {
|
|
35
41
|
return {
|
|
36
42
|
node_id: id,
|
|
@@ -54,6 +60,9 @@ function makeFakePi() {
|
|
|
54
60
|
};
|
|
55
61
|
}
|
|
56
62
|
async function settle(pi, event, ctx) {
|
|
63
|
+
const nodeId = process.env['CRTR_NODE_ID'];
|
|
64
|
+
if (nodeId !== undefined && process.env['CRTR_EXECUTION_ID'] === undefined && getNode(nodeId) !== null)
|
|
65
|
+
activateBroker(nodeId);
|
|
57
66
|
await pi.fire('agent_end', event, ctx);
|
|
58
67
|
await pi.fire('agent_settled', { type: 'agent_settled' }, ctx);
|
|
59
68
|
}
|
|
@@ -68,6 +77,7 @@ function reportCount(id) {
|
|
|
68
77
|
}
|
|
69
78
|
before(() => {
|
|
70
79
|
origNode = process.env['CRTR_NODE_ID'];
|
|
80
|
+
origExecution = process.env['CRTR_EXECUTION_ID'];
|
|
71
81
|
origPane = process.env['TMUX_PANE'];
|
|
72
82
|
});
|
|
73
83
|
async function waitForSocket() {
|
|
@@ -92,11 +102,13 @@ beforeEach(async () => {
|
|
|
92
102
|
rmSync(home, { recursive: true, force: true });
|
|
93
103
|
home = mkdtempSync(join(tmpdir(), 'crtr-stophook-end-'));
|
|
94
104
|
process.env['CRTR_HOME'] = home;
|
|
105
|
+
migrate(openDb());
|
|
95
106
|
server = createApiServer();
|
|
96
107
|
await waitForSocket();
|
|
97
108
|
// Force the clean-shutdown path (no in-place respawn) so the refresh test is
|
|
98
109
|
// deterministic even when the suite runs inside a tmux pane.
|
|
99
110
|
delete process.env['TMUX_PANE'];
|
|
111
|
+
delete process.env['CRTR_EXECUTION_ID'];
|
|
100
112
|
});
|
|
101
113
|
afterEach(async () => {
|
|
102
114
|
await server?.close();
|
|
@@ -112,6 +124,10 @@ after(() => {
|
|
|
112
124
|
delete process.env['CRTR_NODE_ID'];
|
|
113
125
|
else
|
|
114
126
|
process.env['CRTR_NODE_ID'] = origNode;
|
|
127
|
+
if (origExecution === undefined)
|
|
128
|
+
delete process.env['CRTR_EXECUTION_ID'];
|
|
129
|
+
else
|
|
130
|
+
process.env['CRTR_EXECUTION_ID'] = origExecution;
|
|
115
131
|
if (origPane === undefined)
|
|
116
132
|
delete process.env['TMUX_PANE'];
|
|
117
133
|
else
|
|
@@ -123,7 +139,7 @@ test('natural stop commits idle-release only at agent_settled', { timeout: 1_000
|
|
|
123
139
|
createNode(node('worker', { parent: 'mgr', lifecycle: 'terminal', status: 'active' }));
|
|
124
140
|
subscribe('root', 'mgr', true); // root would receive any push mgr emits
|
|
125
141
|
subscribe('mgr', 'worker', true); // mgr holds an active live subscription → "awaiting"
|
|
126
|
-
|
|
142
|
+
activateBroker('mgr');
|
|
127
143
|
const pi = makeFakePi();
|
|
128
144
|
registerCanvasStophook(pi);
|
|
129
145
|
let shutdown = false;
|
|
@@ -131,51 +147,50 @@ test('natural stop commits idle-release only at agent_settled', { timeout: 1_000
|
|
|
131
147
|
await pi.fire('agent_start', { type: 'agent_start' }, ctx);
|
|
132
148
|
await pi.fire('agent_end', stopEvent('still waiting on the worker'), ctx);
|
|
133
149
|
assert.equal(getNode('mgr')?.status, 'active', 'agent_end is staging-only');
|
|
134
|
-
assert.equal(
|
|
150
|
+
assert.equal(readLiveTurn('mgr')?.busy, true, 'agent_end cannot close the active turn');
|
|
135
151
|
assert.equal(shutdown, false, 'agent_end cannot route a natural stop');
|
|
136
152
|
await pi.fire('agent_settled', { type: 'agent_settled' }, ctx);
|
|
137
153
|
const m = getNode('mgr');
|
|
138
|
-
assert.equal(
|
|
154
|
+
assert.equal(readLiveTurn('mgr')?.busy, false, 'agent_settled closes the active turn');
|
|
139
155
|
assert.equal(m?.intent, 'idle-release', 'mgr idle-released');
|
|
140
156
|
assert.equal(m?.status, 'idle', 'mgr marked idle');
|
|
141
157
|
assert.equal(shutdown, true, 'pi shut down');
|
|
142
158
|
assert.equal(reportCount('mgr'), 0, 'NO report file written');
|
|
143
|
-
assert.equal(
|
|
159
|
+
assert.equal(hasUnseenWakeMail('root'), false, 'NO SQL inbox delivery fanned to subscriber');
|
|
144
160
|
assert.equal(pi.injected.length, 0, 'no reprompt on a legitimate idle-release');
|
|
145
161
|
// §5.1 case 6 (awaiting + UNFOCUSED → idle-release, no focus): the awaiting
|
|
146
162
|
// branch must never create/touch a focus row. Non-vacuous: an impl that ran
|
|
147
163
|
// the done-branch handoff/openFocus on an idle-release would leave a row here.
|
|
148
164
|
assert.equal(listFocuses().length, 0, 'awaiting+unfocused leaves the focuses table empty');
|
|
149
165
|
});
|
|
150
|
-
test('gh-451: idle-release does NOT release while a non-deferred
|
|
166
|
+
test('gh-451: idle-release does NOT release while a non-deferred SQL delivery is pending', { timeout: 1_000 }, async () => {
|
|
151
167
|
// Reproduces the #451 race: a subscriber's push landed in mgr's inbox but the
|
|
152
|
-
// in-process watcher has not yet
|
|
153
|
-
//
|
|
154
|
-
//
|
|
168
|
+
// in-process watcher has not yet claimed and acknowledged its SQL delivery.
|
|
169
|
+
// If this settle released anyway, the daemon would immediately re-wake mgr on
|
|
170
|
+
// the delivery the watcher was mid-handoff on.
|
|
155
171
|
createNode(node('root', { parent: null, lifecycle: 'resident' }));
|
|
156
172
|
createNode(node('mgr', { parent: 'root', lifecycle: 'terminal', mode: 'orchestrator' }));
|
|
157
173
|
createNode(node('worker', { parent: 'mgr', lifecycle: 'terminal', status: 'active' }));
|
|
158
174
|
subscribe('root', 'mgr', true);
|
|
159
175
|
subscribe('mgr', 'worker', true); // mgr awaits a live worker → would idle-release once caught up
|
|
160
|
-
// A push landed in mgr's
|
|
161
|
-
|
|
162
|
-
appendInbox('mgr', { from: 'worker', tier: 'normal', kind: 'update', label: 'worker made progress' });
|
|
176
|
+
// A push landed in mgr's SQL inbox delivery set, before the watcher claims it.
|
|
177
|
+
enqueueNodeMail('mgr', { senderNodeId: 'worker', kind: 'update', label: 'worker made progress', urgency: 'normal', wake: 1 });
|
|
163
178
|
process.env['CRTR_NODE_ID'] = 'mgr';
|
|
164
179
|
const pi = makeFakePi();
|
|
165
180
|
registerCanvasStophook(pi);
|
|
166
181
|
let shutdown = false;
|
|
167
182
|
const ctx = { shutdown: () => { shutdown = true; } };
|
|
168
183
|
await settle(pi, stopEvent('still waiting on the worker'), ctx);
|
|
169
|
-
assert.equal(getNode('mgr')?.status, 'active', 'mgr stays active — NOT idle-released while
|
|
184
|
+
assert.equal(getNode('mgr')?.status, 'active', 'mgr stays active — NOT idle-released while a delivery is pending');
|
|
170
185
|
assert.equal(getNode('mgr')?.intent ?? null, null, 'no idle-release intent while a non-deferred entry is unseen');
|
|
171
186
|
assert.equal(shutdown, false, 'pi stays alive so the in-process watcher can still deliver/commit');
|
|
172
187
|
});
|
|
173
|
-
test('gh-451: finished does NOT shut down while a non-deferred
|
|
174
|
-
// A canonical final can settle while the in-process watcher has
|
|
175
|
-
//
|
|
176
|
-
//
|
|
188
|
+
test('gh-451: finished does NOT shut down while a non-deferred SQL delivery is pending', { timeout: 1_000 }, async () => {
|
|
189
|
+
// A canonical final can settle while the in-process watcher has a child
|
|
190
|
+
// report delivery pending. The finished branch must keep this broker alive
|
|
191
|
+
// for that delivery.
|
|
177
192
|
createNode(node('mgr', { parent: null, lifecycle: 'terminal', final_report: 'mgr-final.md' }));
|
|
178
|
-
|
|
193
|
+
enqueueNodeMail('mgr', { senderNodeId: 'worker', kind: 'update', label: 'worker made progress', urgency: 'normal', wake: 1 });
|
|
179
194
|
process.env['CRTR_NODE_ID'] = 'mgr';
|
|
180
195
|
const pi = makeFakePi();
|
|
181
196
|
registerCanvasStophook(pi);
|
|
@@ -192,7 +207,7 @@ test('a deferred send to a TERMINAL node was raised on append, so it holds the s
|
|
|
192
207
|
createNode(node('worker', { parent: 'mgr', lifecycle: 'terminal', status: 'active' }));
|
|
193
208
|
subscribe('root', 'mgr', true);
|
|
194
209
|
subscribe('mgr', 'worker', true);
|
|
195
|
-
|
|
210
|
+
enqueueNodeMail('mgr', { kind: 'message', label: 'a scheduled deferred note', urgency: 'deferred', wake: 1 });
|
|
196
211
|
process.env['CRTR_NODE_ID'] = 'mgr';
|
|
197
212
|
const pi = makeFakePi();
|
|
198
213
|
registerCanvasStophook(pi);
|
|
@@ -206,6 +221,7 @@ test('a deferred send to a TERMINAL node was raised on append, so it holds the s
|
|
|
206
221
|
test('queued continuation finishes before natural-stop routing commits', { timeout: 1_000 }, async () => {
|
|
207
222
|
createNode(node('leaf', { parent: null, lifecycle: 'terminal' }));
|
|
208
223
|
process.env['CRTR_NODE_ID'] = 'leaf';
|
|
224
|
+
activateBroker('leaf');
|
|
209
225
|
const pi = makeFakePi();
|
|
210
226
|
registerCanvasStophook(pi);
|
|
211
227
|
let shutdown = false;
|
|
@@ -318,7 +334,7 @@ test('refresh-yield (intent=refresh) writes NO push — silent to subscribers',
|
|
|
318
334
|
await settle(pi, stopEvent('checkpoint before refreshing'), { shutdown: () => { shutdown = true; } });
|
|
319
335
|
assert.equal(shutdown, true, 'pi shut down (no tmux pane → clean shutdown)');
|
|
320
336
|
assert.equal(reportCount('orch'), 0, 'a yield is silent: NO report file');
|
|
321
|
-
assert.equal(
|
|
337
|
+
assert.equal(hasUnseenWakeMail('root'), false, 'a yield is silent: NO SQL inbox delivery');
|
|
322
338
|
assert.equal(pi.injected.length, 0, 'no reprompt on a refresh-yield');
|
|
323
339
|
});
|
|
324
340
|
// turn_end — stale-⚠ fix: reaching turn_end proves the current provider
|
|
@@ -327,7 +343,7 @@ test('refresh-yield (intent=refresh) writes NO push — silent to subscribers',
|
|
|
327
343
|
function turnEndEvent(text) {
|
|
328
344
|
return { message: { role: 'assistant', content: [{ type: 'text', text }] } };
|
|
329
345
|
}
|
|
330
|
-
test('turn_end clears a stale pi→provider fatal fault (a completed round-trip proves the episode is over)', () => {
|
|
346
|
+
test('turn_end clears a stale pi→provider fatal fault (a completed round-trip proves the episode is over)', async () => {
|
|
331
347
|
createNode(node('leaf', { parent: null, lifecycle: 'terminal' }));
|
|
332
348
|
recordFault('leaf', {
|
|
333
349
|
link: 'pi→provider',
|
|
@@ -336,14 +352,14 @@ test('turn_end clears a stale pi→provider fatal fault (a completed round-trip
|
|
|
336
352
|
retry: { disposition: 'fatal' },
|
|
337
353
|
message: 'terminated',
|
|
338
354
|
});
|
|
339
|
-
assert.notEqual(readFault('leaf'), null, 'precondition: fault
|
|
340
|
-
|
|
355
|
+
assert.notEqual(readFault('leaf'), null, 'precondition: SQL recovery fault recorded');
|
|
356
|
+
activateBroker('leaf');
|
|
341
357
|
const pi = makeFakePi();
|
|
342
358
|
registerCanvasStophook(pi);
|
|
343
|
-
pi.fire('turn_end', turnEndEvent('all good now'), {});
|
|
359
|
+
await pi.fire('turn_end', turnEndEvent('all good now'), {});
|
|
344
360
|
assert.equal(readFault('leaf'), null, 'the pi→provider fault is cleared at turn_end');
|
|
345
361
|
});
|
|
346
|
-
test('turn_end still clears a daemon→node wedge fault (existing behavior, unchanged)', () => {
|
|
362
|
+
test('turn_end still clears a daemon→node wedge fault (existing behavior, unchanged)', async () => {
|
|
347
363
|
createNode(node('leaf', { parent: null, lifecycle: 'terminal' }));
|
|
348
364
|
recordFault('leaf', {
|
|
349
365
|
link: 'daemon→node',
|
|
@@ -352,16 +368,18 @@ test('turn_end still clears a daemon→node wedge fault (existing behavior, unch
|
|
|
352
368
|
retry: { disposition: 'manual' },
|
|
353
369
|
message: 'no progress for 20m',
|
|
354
370
|
});
|
|
355
|
-
assert.notEqual(readFault('leaf'), null, 'precondition: wedge fault recorded');
|
|
356
|
-
|
|
371
|
+
assert.notEqual(readFault('leaf'), null, 'precondition: SQL recovery wedge fault recorded');
|
|
372
|
+
activateBroker('leaf');
|
|
357
373
|
const pi = makeFakePi();
|
|
358
374
|
registerCanvasStophook(pi);
|
|
359
|
-
pi.fire('turn_end', turnEndEvent('turn completed'), {});
|
|
375
|
+
await pi.fire('turn_end', turnEndEvent('turn completed'), {});
|
|
360
376
|
assert.equal(readFault('leaf'), null, 'the daemon→node wedge fault is still cleared at turn_end');
|
|
361
377
|
});
|
|
362
|
-
test('a successful final or requested human reply suppresses the stop reprompt
|
|
378
|
+
test('a successful final or requested human reply suppresses the stop reprompt', async () => {
|
|
379
|
+
createNode(node('signal-only', { parent: null, lifecycle: 'terminal' }));
|
|
363
380
|
for (const [signal, shutsDown] of [['pushedFinal', true], ['requestedHumanReply', false]]) {
|
|
364
381
|
process.env['CRTR_NODE_ID'] = 'signal-only';
|
|
382
|
+
activateBroker('signal-only');
|
|
365
383
|
markStopSignal('signal-only', signal);
|
|
366
384
|
const pi = makeFakePi();
|
|
367
385
|
registerCanvasStophook(pi);
|
|
@@ -410,5 +428,5 @@ test('stalled leaf (nothing live to await, no final) is still reprompted', async
|
|
|
410
428
|
assert.equal(shutdown, false, 'a stalled leaf is NOT shut down — it is re-prompted to finish');
|
|
411
429
|
assert.notEqual(getNode('leaf')?.intent, 'idle-release', 'a stalled leaf does not idle-release');
|
|
412
430
|
assert.equal(reportCount('leaf'), 0, 'NO report file written on a stall');
|
|
413
|
-
assert.equal(
|
|
431
|
+
assert.equal(hasUnseenWakeMail('mgr'), false, 'NO SQL inbox delivery fanned on a stall');
|
|
414
432
|
});
|
|
@@ -20,11 +20,13 @@ import { tmpdir } from 'node:os';
|
|
|
20
20
|
import { join } from 'node:path';
|
|
21
21
|
import registerCanvasStophook from '../canvas-stophook.js';
|
|
22
22
|
import { createNode } from '../../core/canvas/canvas.js';
|
|
23
|
-
import {
|
|
23
|
+
import { beginExecution } from '../../core/canvas/executions.js';
|
|
24
|
+
import { closeDb, migrate, openDb } from '../../core/canvas/db.js';
|
|
24
25
|
import { apiSocketPath } from '../../core/canvas/paths.js';
|
|
25
26
|
import { createApiServer } from '../../daemon/api/server.js';
|
|
26
27
|
let home;
|
|
27
28
|
let origNode;
|
|
29
|
+
let origExecution;
|
|
28
30
|
let server;
|
|
29
31
|
async function waitForSocket(path) {
|
|
30
32
|
for (let i = 0; i < 200; i++) {
|
|
@@ -66,7 +68,10 @@ function turnEnd(content, stopReason = 'stop') {
|
|
|
66
68
|
return { message: { role: 'assistant', stopReason, content, usage: { input: 1, output: 1 } }, toolResults: [] };
|
|
67
69
|
}
|
|
68
70
|
const ctxAt = (tokens) => ({ getContextUsage: () => ({ tokens }) });
|
|
69
|
-
before(() => {
|
|
71
|
+
before(() => {
|
|
72
|
+
origNode = process.env['CRTR_NODE_ID'];
|
|
73
|
+
origExecution = process.env['CRTR_EXECUTION_ID'];
|
|
74
|
+
});
|
|
70
75
|
beforeEach(async () => {
|
|
71
76
|
closeDb();
|
|
72
77
|
if (home)
|
|
@@ -74,6 +79,7 @@ beforeEach(async () => {
|
|
|
74
79
|
home = mkdtempSync(join(tmpdir(), 'crtr-stophook-nudge-'));
|
|
75
80
|
process.env['CRTR_HOME'] = home;
|
|
76
81
|
mkdirSync(home, { recursive: true });
|
|
82
|
+
migrate(openDb());
|
|
77
83
|
server = createApiServer();
|
|
78
84
|
await waitForSocket(apiSocketPath());
|
|
79
85
|
});
|
|
@@ -89,10 +95,15 @@ after(() => {
|
|
|
89
95
|
delete process.env['CRTR_NODE_ID'];
|
|
90
96
|
else
|
|
91
97
|
process.env['CRTR_NODE_ID'] = origNode;
|
|
98
|
+
if (origExecution === undefined)
|
|
99
|
+
delete process.env['CRTR_EXECUTION_ID'];
|
|
100
|
+
else
|
|
101
|
+
process.env['CRTR_EXECUTION_ID'] = origExecution;
|
|
92
102
|
});
|
|
93
103
|
test('band crossing mid-run (tool calls present) → context nudge is a STEER', async () => {
|
|
94
104
|
createNode(node('midrun'));
|
|
95
105
|
process.env['CRTR_NODE_ID'] = 'midrun';
|
|
106
|
+
process.env['CRTR_EXECUTION_ID'] = beginExecution('midrun', { daemonEpoch: null });
|
|
96
107
|
const pi = makeFakePi();
|
|
97
108
|
registerCanvasStophook(pi);
|
|
98
109
|
await pi.fire('turn_end', turnEnd([{ type: 'toolCall', id: 't1', name: 'bash', arguments: {} }], 'toolUse'), ctxAt(150_000));
|
|
@@ -104,6 +115,7 @@ test('band crossing mid-run (tool calls present) → context nudge is a STEER',
|
|
|
104
115
|
test('band crossing on the FINAL message (no tool calls) → nudge is HELD as nextTurn, never a steer', async () => {
|
|
105
116
|
createNode(node('final'));
|
|
106
117
|
process.env['CRTR_NODE_ID'] = 'final';
|
|
118
|
+
process.env['CRTR_EXECUTION_ID'] = beginExecution('final', { daemonEpoch: null });
|
|
107
119
|
const pi = makeFakePi();
|
|
108
120
|
registerCanvasStophook(pi);
|
|
109
121
|
await pi.fire('turn_end', turnEnd([{ type: 'text', text: 'here is my summary' }]), ctxAt(150_000));
|
|
@@ -117,6 +129,7 @@ test('band crossing on the FINAL message (no tool calls) → nudge is HELD as ne
|
|
|
117
129
|
test('a truncated tool-calling turn (stopReason length) still steers — the loop continues past failed calls', async () => {
|
|
118
130
|
createNode(node('lengthrun'));
|
|
119
131
|
process.env['CRTR_NODE_ID'] = 'lengthrun';
|
|
132
|
+
process.env['CRTR_EXECUTION_ID'] = beginExecution('lengthrun', { daemonEpoch: null });
|
|
120
133
|
const pi = makeFakePi();
|
|
121
134
|
registerCanvasStophook(pi);
|
|
122
135
|
await pi.fire('turn_end', turnEnd([{ type: 'toolCall', id: 't1', name: 'bash', arguments: {} }], 'length'), ctxAt(150_000));
|
|
@@ -127,6 +140,7 @@ test('a truncated tool-calling turn (stopReason length) still steers — the loo
|
|
|
127
140
|
test('an aborted final turn also holds (the loop ends unconditionally on abort)', async () => {
|
|
128
141
|
createNode(node('aborted'));
|
|
129
142
|
process.env['CRTR_NODE_ID'] = 'aborted';
|
|
143
|
+
process.env['CRTR_EXECUTION_ID'] = beginExecution('aborted', { daemonEpoch: null });
|
|
130
144
|
const pi = makeFakePi();
|
|
131
145
|
registerCanvasStophook(pi);
|
|
132
146
|
// Aborted mid-tool-call: toolCall content present, but the run ends anyway —
|
|
@@ -27,9 +27,11 @@ import { tmpdir } from 'node:os';
|
|
|
27
27
|
import { join } from 'node:path';
|
|
28
28
|
import { registerCanvasDocSubstrate } from '../canvas-doc-substrate.js';
|
|
29
29
|
import { createNode } from '../../core/canvas/canvas.js';
|
|
30
|
-
import { closeDb } from '../../core/canvas/db.js';
|
|
30
|
+
import { closeDb, migrate, openDb } from '../../core/canvas/db.js';
|
|
31
|
+
import { beginExecution } from '../../core/canvas/executions.js';
|
|
31
32
|
import { apiSocketPath } from '../../core/canvas/paths.js';
|
|
32
33
|
import { resetScopeCache } from '../../core/scope.js';
|
|
34
|
+
import { initializeFreshScopedStore } from '../../core/scoped-state/migrate.js';
|
|
33
35
|
import { loadContextExposureState } from '../../core/substrate/injected-store.js';
|
|
34
36
|
import { clearSessionCache } from '../../core/substrate/session-cache.js';
|
|
35
37
|
import { createApiServer } from '../../daemon/api/server.js';
|
|
@@ -40,6 +42,7 @@ let server = null;
|
|
|
40
42
|
let origCwd;
|
|
41
43
|
let origHome;
|
|
42
44
|
let origNode;
|
|
45
|
+
let origExecution;
|
|
43
46
|
let origProfile;
|
|
44
47
|
async function waitForSocket(path) {
|
|
45
48
|
for (let i = 0; i < 200; i++) {
|
|
@@ -83,6 +86,7 @@ function seedNode(id) {
|
|
|
83
86
|
});
|
|
84
87
|
mkdirSync(join(home, 'nodes', id), { recursive: true });
|
|
85
88
|
process.env['CRTR_NODE_ID'] = id;
|
|
89
|
+
process.env['CRTR_EXECUTION_ID'] = beginExecution(id, { daemonEpoch: null });
|
|
86
90
|
}
|
|
87
91
|
/** The registered extension, driven through the pi events it actually binds. */
|
|
88
92
|
function registerSubstrate() {
|
|
@@ -117,6 +121,7 @@ before(() => {
|
|
|
117
121
|
origCwd = process.cwd();
|
|
118
122
|
origHome = process.env['HOME'];
|
|
119
123
|
origNode = process.env['CRTR_NODE_ID'];
|
|
124
|
+
origExecution = process.env['CRTR_EXECUTION_ID'];
|
|
120
125
|
origProfile = process.env['CRTR_PROFILE_ID'];
|
|
121
126
|
});
|
|
122
127
|
beforeEach(async () => {
|
|
@@ -130,9 +135,12 @@ beforeEach(async () => {
|
|
|
130
135
|
process.env['HOME'] = join(home, 'user');
|
|
131
136
|
process.env['CRTR_HOME'] = home;
|
|
132
137
|
delete process.env['CRTR_NODE_ID'];
|
|
138
|
+
delete process.env['CRTR_EXECUTION_ID'];
|
|
133
139
|
delete process.env['CRTR_PROFILE_ID'];
|
|
134
140
|
resetScopeCache();
|
|
135
141
|
clearSessionCache();
|
|
142
|
+
initializeFreshScopedStore({ kind: 'user', root: join(home, 'user', '.crouter') });
|
|
143
|
+
migrate(openDb());
|
|
136
144
|
server = createApiServer();
|
|
137
145
|
await waitForSocket(apiSocketPath());
|
|
138
146
|
});
|
|
@@ -160,6 +168,10 @@ after(() => {
|
|
|
160
168
|
delete process.env['CRTR_NODE_ID'];
|
|
161
169
|
else
|
|
162
170
|
process.env['CRTR_NODE_ID'] = origNode;
|
|
171
|
+
if (origExecution === undefined)
|
|
172
|
+
delete process.env['CRTR_EXECUTION_ID'];
|
|
173
|
+
else
|
|
174
|
+
process.env['CRTR_EXECUTION_ID'] = origExecution;
|
|
163
175
|
if (origProfile === undefined)
|
|
164
176
|
delete process.env['CRTR_PROFILE_ID'];
|
|
165
177
|
else
|