@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
|
@@ -7,18 +7,23 @@ import { fileURLToPath } from 'node:url';
|
|
|
7
7
|
import { spawnSync, spawn } from 'node:child_process';
|
|
8
8
|
import { createServer } from 'node:net';
|
|
9
9
|
import { createNode, getNode, subscribe } from '../canvas/canvas.js';
|
|
10
|
-
import { closeDb } from '../canvas/db.js';
|
|
11
|
-
import {
|
|
10
|
+
import { closeDb, migrate, openDb } from '../canvas/db.js';
|
|
11
|
+
import { closeScopedStores } from '../scoped-state/db.js';
|
|
12
|
+
import { initializeFreshScopedStore } from '../scoped-state/migrate.js';
|
|
13
|
+
import { beginExecution, recordExecutionPid } from '../canvas/executions.js';
|
|
14
|
+
import { openTurn } from '../canvas/recovery.js';
|
|
12
15
|
import { superviseTick } from '../../daemon/crtrd.js';
|
|
13
16
|
import { readPidfile } from '../../daemon/pidfile.js';
|
|
14
17
|
import { verifyDaemonStartup, waitForDaemonExit } from '../../daemon/manage.js';
|
|
15
18
|
import { waitForBrokerViewSocket } from '../runtime/placement-tmux.js';
|
|
16
19
|
import { viewSocketPath } from '../canvas/paths.js';
|
|
17
|
-
import { markBusy, clearBusy } from '../runtime/busy.js';
|
|
18
20
|
import { headlessBrokerHost } from '../runtime/host.js';
|
|
19
21
|
import { bindTestFleet } from './helpers/fleet.js';
|
|
20
22
|
import { resetFleetForTests } from '../runtime/fleet.js';
|
|
21
23
|
let home;
|
|
24
|
+
let scopeHome;
|
|
25
|
+
let originalCwd;
|
|
26
|
+
let originalHome;
|
|
22
27
|
let tf;
|
|
23
28
|
function node(id, over = {}) {
|
|
24
29
|
return {
|
|
@@ -43,20 +48,41 @@ function deadPid() {
|
|
|
43
48
|
const r = spawnSync('true', [], { stdio: 'ignore' });
|
|
44
49
|
return r.pid ?? 0x7ffffffe;
|
|
45
50
|
}
|
|
51
|
+
function wakeMail(nodeId) {
|
|
52
|
+
return openDb().prepare(`SELECT m.sender_node_id AS "from", d.urgency AS tier, m.label
|
|
53
|
+
FROM deliveries d JOIN messages m ON m.message_id = d.message_id
|
|
54
|
+
WHERE d.destination_kind = 'node_inbox' AND d.destination_id = ? AND d.wake = 1
|
|
55
|
+
ORDER BY m.seq`).all(nodeId);
|
|
56
|
+
}
|
|
46
57
|
before(() => {
|
|
47
58
|
home = mkdtempSync(join(tmpdir(), 'crtr-daemon-boot-'));
|
|
59
|
+
scopeHome = mkdtempSync(join(tmpdir(), 'crtr-daemon-boot-home-'));
|
|
60
|
+
originalCwd = process.cwd();
|
|
61
|
+
originalHome = process.env['HOME'];
|
|
62
|
+
process.chdir(scopeHome);
|
|
63
|
+
process.env['HOME'] = scopeHome;
|
|
48
64
|
process.env['CRTR_HOME'] = home;
|
|
49
65
|
// superviseTick + exit-policy delivery require a bound fleet (D-2).
|
|
50
66
|
tf = bindTestFleet();
|
|
51
67
|
});
|
|
52
68
|
beforeEach(() => {
|
|
53
69
|
closeDb();
|
|
70
|
+
closeScopedStores();
|
|
54
71
|
rmSync(home, { recursive: true, force: true });
|
|
72
|
+
initializeFreshScopedStore({ kind: 'user', root: join(scopeHome, '.crouter') });
|
|
73
|
+
migrate(openDb());
|
|
55
74
|
});
|
|
56
75
|
after(() => {
|
|
57
76
|
closeDb();
|
|
77
|
+
closeScopedStores();
|
|
58
78
|
rmSync(home, { recursive: true, force: true });
|
|
79
|
+
process.chdir(originalCwd);
|
|
80
|
+
rmSync(scopeHome, { recursive: true, force: true });
|
|
59
81
|
delete process.env['CRTR_HOME'];
|
|
82
|
+
if (originalHome === undefined)
|
|
83
|
+
delete process.env['HOME'];
|
|
84
|
+
else
|
|
85
|
+
process.env['HOME'] = originalHome;
|
|
60
86
|
tf.fleet.dispose();
|
|
61
87
|
resetFleetForTests();
|
|
62
88
|
});
|
|
@@ -66,13 +92,15 @@ after(() => {
|
|
|
66
92
|
// exit is observation-only.
|
|
67
93
|
test('never-booted broker is marked dead by the tick and surfaced to the parent as urgent', async () => {
|
|
68
94
|
createNode(node('P', { kind: 'developer', lifecycle: 'resident' }));
|
|
95
|
+
const crashedPid = deadPid();
|
|
69
96
|
createNode(node('C', {
|
|
70
97
|
parent: 'P',
|
|
71
98
|
kind: 'explore',
|
|
72
|
-
pi_pid:
|
|
99
|
+
pi_pid: crashedPid, // launch recorded its process before it died
|
|
73
100
|
pi_session_id: null, // never booted
|
|
74
101
|
intent: null,
|
|
75
102
|
}));
|
|
103
|
+
recordExecutionPid(beginExecution('C', { daemonEpoch: 'test' }), 'C', crashedPid);
|
|
76
104
|
spawnEdge('P', 'C');
|
|
77
105
|
// The launch's real child exit is delivered synthetically here, then the
|
|
78
106
|
// authoritative tick classifies the dead recorded pid as table row 8:
|
|
@@ -84,7 +112,7 @@ test('never-booted broker is marked dead by the tick and surfaced to the parent
|
|
|
84
112
|
// Row 8 fans TWO entries: the urgent surfaceBootFailure push and the normal
|
|
85
113
|
// doctrine wake (design flow B row 8 — crash + surfaceBootFailure + doctrine
|
|
86
114
|
// wake), both from C.
|
|
87
|
-
const inbox =
|
|
115
|
+
const inbox = wakeMail('P');
|
|
88
116
|
assert.equal(inbox.length, 2, 'parent received the boot-failure push and the doctrine wake');
|
|
89
117
|
const urgent = inbox.find((e) => e.tier === 'urgent');
|
|
90
118
|
assert.ok(urgent, 'boot failure is delivered as urgent');
|
|
@@ -105,16 +133,19 @@ test('a crashed booted child is relaunched on its saved session, not reaped, and
|
|
|
105
133
|
};
|
|
106
134
|
try {
|
|
107
135
|
createNode(node('P2', { kind: 'developer', lifecycle: 'resident' }));
|
|
136
|
+
const crashedPid = deadPid();
|
|
108
137
|
createNode(node('C2', {
|
|
109
138
|
cwd: home, // a cwd that exists — reviveNode's preflight refuses a missing one
|
|
110
139
|
parent: 'P2',
|
|
111
140
|
kind: 'explore',
|
|
112
|
-
pi_pid:
|
|
141
|
+
pi_pid: crashedPid, // engine crashed — its recorded pid is dead
|
|
113
142
|
pi_session_id: '019e8f00-booted-once', // it booted before dying
|
|
114
143
|
intent: null,
|
|
115
144
|
}));
|
|
116
145
|
spawnEdge('P2', 'C2');
|
|
117
|
-
|
|
146
|
+
const executionId = beginExecution('C2', { daemonEpoch: 'test' });
|
|
147
|
+
recordExecutionPid(executionId, 'C2', crashedPid);
|
|
148
|
+
openTurn(executionId, { reason: 'agent-start' }); // died mid-generation
|
|
118
149
|
await superviseTick();
|
|
119
150
|
const afterFirstTick = getNode('C2');
|
|
120
151
|
assert.deepEqual(launches, [], 'the first tick records the failed launch without relaunching');
|
|
@@ -123,8 +154,7 @@ test('a crashed booted child is relaunched on its saved session, not reaped, and
|
|
|
123
154
|
await superviseTick(Date.parse(afterFirstTick.respawn_not_before));
|
|
124
155
|
assert.deepEqual(launches, ['C2'], 'the matured tick recovers the crash through the policy table');
|
|
125
156
|
assert.equal(getNode('C2').status, 'active', 'crashed booted child is relaunched, NOT marked dead');
|
|
126
|
-
assert.equal(
|
|
127
|
-
clearBusy('C2');
|
|
157
|
+
assert.equal(wakeMail('P2').length, 0, 'no false boot-failure / child-death push on a crash (wake relocated to push/close)');
|
|
128
158
|
}
|
|
129
159
|
finally {
|
|
130
160
|
headlessBrokerHost.launch = originalLaunch;
|
|
@@ -193,17 +223,24 @@ test('verifyDaemonStartup waits for pidfile, live pid, and serving socket before
|
|
|
193
223
|
assert.equal(socketServing, true, 'the Unix API socket must serve before success');
|
|
194
224
|
assert.equal(slept >= 40, true, 'the guard must actually poll through socket readiness');
|
|
195
225
|
});
|
|
196
|
-
test('runDaemon
|
|
226
|
+
test('runDaemon initializes SQL before binding restricted repair', () => {
|
|
197
227
|
const source = readFileSync(fileURLToPath(new URL('../../daemon/crtrd.ts', import.meta.url)), 'utf8');
|
|
198
228
|
const runDaemonAt = source.indexOf('export async function runDaemon');
|
|
199
|
-
const activationAt = source.indexOf('await ensureOnDiskMigrations();', runDaemonAt);
|
|
200
229
|
const ownershipAt = source.indexOf('claimDaemonOwnership(', runDaemonAt);
|
|
201
|
-
const
|
|
230
|
+
const profileAt = source.indexOf('runProfileManifestMigrations(', ownershipAt);
|
|
231
|
+
const migrateAt = source.indexOf('migrate(openDb());', profileAt);
|
|
232
|
+
const restrictionAt = source.indexOf("phase: 'initializing'", migrateAt);
|
|
233
|
+
const pidfileAt = source.indexOf('writePidfile();', restrictionAt);
|
|
234
|
+
const serverAt = source.indexOf('createApiServer(', pidfileAt);
|
|
235
|
+
const activationAt = source.indexOf('await activateOnDiskMigrations(', serverAt);
|
|
202
236
|
assert.ok(runDaemonAt >= 0, 'runDaemon exists');
|
|
203
237
|
assert.ok(ownershipAt > runDaemonAt, 'runDaemon claims ownership');
|
|
204
238
|
assert.equal(source.slice(runDaemonAt, ownershipAt).includes('await '), false, 'ownership is claimed before startup can await');
|
|
205
|
-
assert.ok(ownershipAt <
|
|
206
|
-
assert.ok(
|
|
239
|
+
assert.ok(ownershipAt < profileAt, 'ownership precedes raw profile migration');
|
|
240
|
+
assert.ok(profileAt < migrateAt, 'profile migration precedes SQL migration');
|
|
241
|
+
assert.ok(migrateAt < restrictionAt, 'SQL migration precedes restriction state');
|
|
242
|
+
assert.ok(restrictionAt < pidfileAt && pidfileAt < serverAt, 'restriction precedes repair listener binding');
|
|
243
|
+
assert.ok(serverAt < activationAt, 'repair listener precedes on-disk activation');
|
|
207
244
|
});
|
|
208
245
|
// Regression for the cold-guest recreate blocker: the production startup window
|
|
209
246
|
// must tolerate a slower cold start than the old 500ms bound.
|
|
@@ -20,7 +20,7 @@ export declare class SessionManager {
|
|
|
20
20
|
* broker tests do not replay source history, but they must reach the same
|
|
21
21
|
* post-fork model/session construction path as the real engine. */
|
|
22
22
|
static forkFrom(_source: string, cwd: string): SessionManager;
|
|
23
|
-
/** Resume: round-trip the
|
|
23
|
+
/** Resume: round-trip the saved session identity with its .jsonl path. */
|
|
24
24
|
static open(path: string): SessionManager;
|
|
25
25
|
getSessionId(): string;
|
|
26
26
|
getSessionFile(): string;
|
|
@@ -91,7 +91,9 @@ export class SessionManager {
|
|
|
91
91
|
const sessionFile = join(dir, 'fake-session.jsonl');
|
|
92
92
|
if (!existsSync(sessionFile))
|
|
93
93
|
writeFileSync(sessionFile, '');
|
|
94
|
-
|
|
94
|
+
const sessionId = `fake-sess-${randomUUID()}`;
|
|
95
|
+
writeFileSync(`${sessionFile}.id`, sessionId);
|
|
96
|
+
return new SessionManager(sessionId, sessionFile, false);
|
|
95
97
|
}
|
|
96
98
|
/** Spawn-time fork: create the fork's distinct fake session. The focused
|
|
97
99
|
* broker tests do not replay source history, but they must reach the same
|
|
@@ -99,9 +101,12 @@ export class SessionManager {
|
|
|
99
101
|
static forkFrom(_source, cwd) {
|
|
100
102
|
return SessionManager.create(cwd);
|
|
101
103
|
}
|
|
102
|
-
/** Resume: round-trip the
|
|
104
|
+
/** Resume: round-trip the saved session identity with its .jsonl path. */
|
|
103
105
|
static open(path) {
|
|
104
|
-
|
|
106
|
+
const sessionId = readFileSync(`${path}.id`, 'utf8').trim();
|
|
107
|
+
if (sessionId === '')
|
|
108
|
+
throw new Error(`fake session identity is empty: ${path}.id`);
|
|
109
|
+
return new SessionManager(sessionId, path, true);
|
|
105
110
|
}
|
|
106
111
|
getSessionId() {
|
|
107
112
|
return this.sessionId;
|
|
@@ -16,7 +16,7 @@ import { mkdtempSync, rmSync } from 'node:fs';
|
|
|
16
16
|
import { tmpdir } from 'node:os';
|
|
17
17
|
import { join } from 'node:path';
|
|
18
18
|
import { openFocusRow, setFocusOccupant, setFocusPane, closeFocusRow, getFocusByNode, getFocusByPane, getFocusById, listFocuses, } from '../canvas/focuses.js';
|
|
19
|
-
import { openDb, closeDb, MIGRATIONS } from '../canvas/db.js';
|
|
19
|
+
import { openDb, closeDb, migrate, MIGRATIONS } from '../canvas/db.js';
|
|
20
20
|
import { focusOf, isFocused, focusByPane, focusedNodes, listFocuses as placementListFocuses, } from '../runtime/placement.js';
|
|
21
21
|
let home;
|
|
22
22
|
function userVersion(db) {
|
|
@@ -25,6 +25,11 @@ function userVersion(db) {
|
|
|
25
25
|
function tableNames(db) {
|
|
26
26
|
return db.prepare("SELECT name FROM sqlite_master WHERE type = 'table'").all().map((r) => r.name);
|
|
27
27
|
}
|
|
28
|
+
function freshDb() {
|
|
29
|
+
const db = openDb();
|
|
30
|
+
migrate(db);
|
|
31
|
+
return db;
|
|
32
|
+
}
|
|
28
33
|
before(() => {
|
|
29
34
|
home = mkdtempSync(join(tmpdir(), 'crtr-focuses-'));
|
|
30
35
|
process.env['CRTR_HOME'] = home;
|
|
@@ -40,13 +45,13 @@ after(() => {
|
|
|
40
45
|
});
|
|
41
46
|
// Migration v6 — the additive `focuses` table.
|
|
42
47
|
test('a fresh db migrates to the latest version and has the focuses table', () => {
|
|
43
|
-
const db =
|
|
48
|
+
const db = freshDb();
|
|
44
49
|
assert.equal(userVersion(db), MIGRATIONS.length);
|
|
45
50
|
assert.ok(tableNames(db).includes('focuses'), 'focuses table exists on a fresh db');
|
|
46
51
|
});
|
|
47
52
|
// Canvas setters / reads — open / setOccupant / setPane / close round-trip.
|
|
48
53
|
test('open / setOccupant / close round-trip with the reads', () => {
|
|
49
|
-
|
|
54
|
+
freshDb();
|
|
50
55
|
openFocusRow('f1', '%a', 'Sa', 'A');
|
|
51
56
|
// getFocusByNode / getFocusByPane / getFocusById all resolve the same row.
|
|
52
57
|
const byNode = getFocusByNode('A');
|
|
@@ -70,7 +75,7 @@ test('open / setOccupant / close round-trip with the reads', () => {
|
|
|
70
75
|
assert.deepEqual(listFocuses(), []);
|
|
71
76
|
});
|
|
72
77
|
test('independent focus rows do not contend', () => {
|
|
73
|
-
|
|
78
|
+
freshDb();
|
|
74
79
|
openFocusRow('f1', '%a', 'Sa', 'A');
|
|
75
80
|
openFocusRow('f2', '%b', 'Sb', 'B');
|
|
76
81
|
// Mutating one viewport leaves the other entirely intact.
|
|
@@ -89,7 +94,7 @@ test('independent focus rows do not contend', () => {
|
|
|
89
94
|
// can't be fabricated in the ordinary suite, so we cover the prune + null-pane paths
|
|
90
95
|
// here; the live-pane read is covered in the compiled-seam broker lifecycle suite.
|
|
91
96
|
test('placement reads GC dead-pane viewer rows and keep null-pane rows', () => {
|
|
92
|
-
|
|
97
|
+
freshDb();
|
|
93
98
|
openFocusRow('f1', '%a', 'Sa', 'A'); // %a is not a live tmux pane → pruned on read
|
|
94
99
|
openFocusRow('f2', null, 'Sb', 'B'); // null pane (not realized yet) → kept
|
|
95
100
|
// The dead-pane row is GC'd on read: placement returns null AND the row is
|
|
@@ -26,15 +26,19 @@ import { homedir, tmpdir } from 'node:os';
|
|
|
26
26
|
import { join, dirname } from 'node:path';
|
|
27
27
|
import { fileURLToPath } from 'node:url';
|
|
28
28
|
import { createRequire } from 'node:module';
|
|
29
|
-
import { createNode, getNode,
|
|
30
|
-
import { closeDb } from '../../canvas/db.js';
|
|
29
|
+
import { createNode, getNode, subscribersOf, subscriptionsOf, } from '../../canvas/canvas.js';
|
|
30
|
+
import { closeDb, migrate, openDb } from '../../canvas/db.js';
|
|
31
|
+
import { beginExecution, liveExecutionForNode, recordExecutionPid } from '../../canvas/executions.js';
|
|
32
|
+
import { resetSession } from '../../canvas/sessions.js';
|
|
33
|
+
import { closeScopedStores } from '../../scoped-state/db.js';
|
|
34
|
+
import { initializeFreshScopedStore } from '../../scoped-state/migrate.js';
|
|
35
|
+
import { piAgentDir } from '../../runtime/package-health.js';
|
|
31
36
|
import { spawnChild } from '../../runtime/spawn.js';
|
|
32
37
|
import { superviseTick } from '../../../daemon/crtrd.js';
|
|
33
38
|
import { DaemonFleet } from '../../../daemon/fleet.js';
|
|
34
39
|
import { apiSocketPath } from '../../canvas/paths.js';
|
|
35
40
|
import { bindDaemonEventSource, resetEventSourceForTests } from '../../events/source.js';
|
|
36
41
|
import { bindFleet, resetFleetForTests } from '../../runtime/fleet.js';
|
|
37
|
-
import { readInboxSince } from '../../feed/inbox.js';
|
|
38
42
|
import { capturePidCommand, recordedPidLiveness } from '../../canvas/pid.js';
|
|
39
43
|
// locations
|
|
40
44
|
const HERE = dirname(fileURLToPath(import.meta.url));
|
|
@@ -157,7 +161,7 @@ export async function createHarness(opts = {}) {
|
|
|
157
161
|
// short); a test-only artifact of the long temp base. Use a SHORT base + short
|
|
158
162
|
// prefix for the canvas home so broker sockets fit. tmpHome (HOME) hosts no
|
|
159
163
|
// socket, so it can stay on the standard temp base.
|
|
160
|
-
const shortTmpBase =
|
|
164
|
+
const shortTmpBase = tmpdir();
|
|
161
165
|
const home = mkdtempSync(join(shortTmpBase, 'crh-'));
|
|
162
166
|
const tmpHome = mkdtempSync(join(tmpdir(), 'crtr-harness-HOME-'));
|
|
163
167
|
const session = `${opts.sessionPrefix ?? 'crtr-harness'}-${process.pid}-${Date.now().toString(36)}`;
|
|
@@ -202,7 +206,10 @@ export async function createHarness(opts = {}) {
|
|
|
202
206
|
.join(' ');
|
|
203
207
|
}
|
|
204
208
|
process.env['CRTR_BROKER_ENGINE'] = FAKE_ENGINE;
|
|
209
|
+
initializeFreshScopedStore({ kind: 'user', root: join(tmpHome, '.crouter') });
|
|
210
|
+
initializeFreshScopedStore({ kind: 'provider', root: piAgentDir() });
|
|
205
211
|
closeDb();
|
|
212
|
+
migrate(openDb());
|
|
206
213
|
// The harness drives superviseTick() in-process, so it stands in for the
|
|
207
214
|
// daemon process (crtrd.ts:2490 binds the same way at real-daemon startup).
|
|
208
215
|
// Reset first: `bound` is a single-assignment process global with no other
|
|
@@ -432,6 +439,29 @@ export async function createHarness(opts = {}) {
|
|
|
432
439
|
function bootCount(nodeId) {
|
|
433
440
|
return readLines(join(nodeDir(nodeId), 'fake-pi.boots.jsonl')).length;
|
|
434
441
|
}
|
|
442
|
+
function inbox(nodeId) {
|
|
443
|
+
return openDb().prepare(`SELECT m.message_id AS entry_id, m.operation_id, m.created_at AS ts,
|
|
444
|
+
m.sender_node_id AS "from", m.sender_name AS from_name, d.urgency AS tier,
|
|
445
|
+
m.kind, m.body_ref AS ref, m.label, m.body_json AS data, m.disposition
|
|
446
|
+
FROM deliveries d JOIN messages m ON m.message_id = d.message_id
|
|
447
|
+
WHERE d.destination_kind = 'node_inbox' AND d.destination_id = ? AND d.wake = 1
|
|
448
|
+
ORDER BY m.seq`).all(nodeId).map((row) => {
|
|
449
|
+
const value = row;
|
|
450
|
+
return {
|
|
451
|
+
entry_id: value['entry_id'],
|
|
452
|
+
operation_id: value['operation_id'],
|
|
453
|
+
ts: value['ts'],
|
|
454
|
+
from: value['from'],
|
|
455
|
+
...(value['from_name'] === null ? {} : { from_name: value['from_name'] }),
|
|
456
|
+
tier: value['tier'],
|
|
457
|
+
kind: value['kind'],
|
|
458
|
+
...(value['ref'] === null ? {} : { ref: value['ref'] }),
|
|
459
|
+
label: value['label'],
|
|
460
|
+
...(value['data'] === null ? {} : { data: JSON.parse(value['data']) }),
|
|
461
|
+
...(value['disposition'] === null ? {} : { disposition: value['disposition'] }),
|
|
462
|
+
};
|
|
463
|
+
});
|
|
464
|
+
}
|
|
435
465
|
function injected(nodeId) {
|
|
436
466
|
return readLines(join(nodeDir(nodeId), 'fake-pi.injected.jsonl'))
|
|
437
467
|
.map((l) => {
|
|
@@ -470,16 +500,8 @@ export async function createHarness(opts = {}) {
|
|
|
470
500
|
parent: null,
|
|
471
501
|
};
|
|
472
502
|
createNode(meta);
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
// well before any daemon tick) — a production root's pi_pid is never
|
|
476
|
-
// null for longer than an instant. This in-process fixture has no real
|
|
477
|
-
// broker to launch, so mint it a pid that is genuinely alive for the
|
|
478
|
-
// rest of the test: this harness process's own pid (already threaded
|
|
479
|
-
// into the id scheme above). The pid is metadata post-cutover (fleet
|
|
480
|
-
// entries are the liveness authority), but status surfaces and identity
|
|
481
|
-
// rechecks still read it, so keep the fixture row shaped like a real one.
|
|
482
|
-
recordPid(id, process.pid);
|
|
503
|
+
const executionId = beginExecution(id, { daemonEpoch: fleet.epoch() });
|
|
504
|
+
recordExecutionPid(executionId, id, process.pid);
|
|
483
505
|
closeDb();
|
|
484
506
|
return id;
|
|
485
507
|
},
|
|
@@ -502,6 +524,13 @@ export async function createHarness(opts = {}) {
|
|
|
502
524
|
pi_pid: o.pi_pid ?? null,
|
|
503
525
|
};
|
|
504
526
|
createNode(meta);
|
|
527
|
+
if (o.pi_pid !== null && o.pi_pid !== undefined) {
|
|
528
|
+
const executionId = beginExecution(id, { daemonEpoch: fleet.epoch() });
|
|
529
|
+
recordExecutionPid(executionId, id, o.pi_pid);
|
|
530
|
+
}
|
|
531
|
+
if (o.pi_session_id !== null && o.pi_session_id !== undefined || o.pi_session_file !== null && o.pi_session_file !== undefined) {
|
|
532
|
+
resetSession(id, { sessionId: o.pi_session_id ?? '', transcriptPath: o.pi_session_file ?? null });
|
|
533
|
+
}
|
|
505
534
|
closeDb();
|
|
506
535
|
return id;
|
|
507
536
|
},
|
|
@@ -631,7 +660,7 @@ export async function createHarness(opts = {}) {
|
|
|
631
660
|
},
|
|
632
661
|
inbox(nodeId) {
|
|
633
662
|
closeDb();
|
|
634
|
-
return
|
|
663
|
+
return inbox(nodeId);
|
|
635
664
|
},
|
|
636
665
|
injected,
|
|
637
666
|
fakeCmd(nodeId, cmd) {
|
|
@@ -644,7 +673,7 @@ export async function createHarness(opts = {}) {
|
|
|
644
673
|
catch {
|
|
645
674
|
/* already gone */
|
|
646
675
|
}
|
|
647
|
-
await waitFor(() => apiServerProc.exitCode === null ? null : true, { label: 'harness API server exit' });
|
|
676
|
+
await waitFor(() => apiServerProc.exitCode === null && apiServerProc.signalCode === null ? null : true, { label: 'harness API server exit' });
|
|
648
677
|
},
|
|
649
678
|
dialogResults(nodeId) {
|
|
650
679
|
return readLines(join(nodeDir(nodeId), 'fake-pi.dialog.jsonl'))
|
|
@@ -685,8 +714,9 @@ export async function createHarness(opts = {}) {
|
|
|
685
714
|
for (const d of nodeDirs()) {
|
|
686
715
|
try {
|
|
687
716
|
const n = getNode(d);
|
|
688
|
-
|
|
689
|
-
|
|
717
|
+
const execution = liveExecutionForNode(d);
|
|
718
|
+
if (execution?.pid != null)
|
|
719
|
+
pidsToKill.add(execution.pid);
|
|
690
720
|
}
|
|
691
721
|
catch {
|
|
692
722
|
/* row gone — fine */
|
|
@@ -726,6 +756,7 @@ export async function createHarness(opts = {}) {
|
|
|
726
756
|
}
|
|
727
757
|
}
|
|
728
758
|
closeDb();
|
|
759
|
+
closeScopedStores();
|
|
729
760
|
// Stop the standalone API-server process (its socket lives under home/,
|
|
730
761
|
// removed below). SIGTERM lets it close() its listener and unlink the
|
|
731
762
|
// socket; the pid is also in pidsToKill as a backstop.
|
|
@@ -735,6 +766,7 @@ export async function createHarness(opts = {}) {
|
|
|
735
766
|
catch {
|
|
736
767
|
/* already gone */
|
|
737
768
|
}
|
|
769
|
+
await waitFor(() => apiServerProc.exitCode === null && apiServerProc.signalCode === null ? null : true, { label: 'harness API server exit' });
|
|
738
770
|
// Leave the process-global event source + fleet unbound so the next
|
|
739
771
|
// harness instance in this same test process can bind cleanly (see setup
|
|
740
772
|
// above). dispose() the fleet first: a pending backoff-respawn timer
|
|
@@ -6,13 +6,13 @@
|
|
|
6
6
|
// sender (`from`) is visible in both the read body and the artifact title.
|
|
7
7
|
import { test, before, after, beforeEach } from 'node:test';
|
|
8
8
|
import assert from 'node:assert/strict';
|
|
9
|
-
import { mkdtempSync, rmSync, writeFileSync } from 'node:fs';
|
|
9
|
+
import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from 'node:fs';
|
|
10
10
|
import { tmpdir } from 'node:os';
|
|
11
11
|
import { join } from 'node:path';
|
|
12
12
|
import { createNode } from '../canvas/canvas.js';
|
|
13
|
-
import { closeDb } from '../canvas/db.js';
|
|
13
|
+
import { closeDb, migrate, openDb } from '../canvas/db.js';
|
|
14
14
|
import { contextDir } from '../canvas/paths.js';
|
|
15
|
-
import {
|
|
15
|
+
import { enqueueNodeMail } from '../feed/messages.js';
|
|
16
16
|
import { buildCorpus, nodeArtifacts, resolveRef } from '../canvas/history.js';
|
|
17
17
|
let home;
|
|
18
18
|
function node(id, cwd) {
|
|
@@ -34,6 +34,8 @@ before(() => {
|
|
|
34
34
|
beforeEach(() => {
|
|
35
35
|
closeDb();
|
|
36
36
|
rmSync(home, { recursive: true, force: true });
|
|
37
|
+
mkdirSync(home, { recursive: true });
|
|
38
|
+
migrate(openDb());
|
|
37
39
|
});
|
|
38
40
|
after(() => {
|
|
39
41
|
closeDb();
|
|
@@ -64,12 +66,9 @@ test('default history excludes inbox; --type inbox includes it, with full sender
|
|
|
64
66
|
createNode(node('sender-1', cwd));
|
|
65
67
|
const receiver = createNode(node('receiver-1', cwd));
|
|
66
68
|
const longBody = 'a'.repeat(4000); // well past any old label-clip length
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
kind: 'message',
|
|
71
|
-
label: 'first line of a long message',
|
|
72
|
-
data: { body: longBody },
|
|
69
|
+
enqueueNodeMail(receiver.node_id, {
|
|
70
|
+
senderNodeId: 'sender-1', kind: 'message', label: 'first line of a long message',
|
|
71
|
+
bodyJson: { body: longBody }, urgency: 'urgent', wake: 1,
|
|
73
72
|
});
|
|
74
73
|
// (a) default corpus (no explicit types) excludes inbox entirely.
|
|
75
74
|
const defaultCorpus = buildCorpus({ nodes: [receiver.node_id] }, {});
|
|
@@ -104,12 +103,9 @@ test('a spilled message body is read RAW — a leading frontmatter-shaped block
|
|
|
104
103
|
// survive intact, unlike a report ref (which always has real frontmatter
|
|
105
104
|
// stripped by fileBodyLoader).
|
|
106
105
|
const body = '---\nfoo: bar\n---\n' + 'a'.repeat(4000);
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
kind: 'message',
|
|
111
|
-
label: 'first line',
|
|
112
|
-
data: { body },
|
|
106
|
+
enqueueNodeMail(receiver.node_id, {
|
|
107
|
+
senderNodeId: 'sender-3', kind: 'message', label: 'first line',
|
|
108
|
+
bodyJson: { body }, urgency: 'normal', wake: 1,
|
|
113
109
|
});
|
|
114
110
|
const resolved = resolveRef(`${receiver.node_id}:inbox/000000`);
|
|
115
111
|
assert.ok(resolved !== null);
|
|
@@ -118,7 +114,7 @@ test('a spilled message body is read RAW — a leading frontmatter-shaped block
|
|
|
118
114
|
test('a null-from (system) inbox entry reads as "system", not blank or thrown', () => {
|
|
119
115
|
const cwd = '/tmp/hist-work-2';
|
|
120
116
|
const receiver = createNode(node('receiver-2', cwd));
|
|
121
|
-
|
|
117
|
+
enqueueNodeMail(receiver.node_id, { kind: 'update', label: 'system note', urgency: 'normal', wake: 1 });
|
|
122
118
|
const resolved = resolveRef(`${receiver.node_id}:inbox/000000`);
|
|
123
119
|
assert.ok(resolved !== null);
|
|
124
120
|
assert.ok(resolved.body.includes('from: system'), 'null sender renders as "system"');
|
|
@@ -3,29 +3,55 @@ import assert from 'node:assert/strict';
|
|
|
3
3
|
import { chmodSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
|
|
4
4
|
import { tmpdir } from 'node:os';
|
|
5
5
|
import { join } from 'node:path';
|
|
6
|
-
import { closeDb } from '../canvas/db.js';
|
|
7
|
-
import {
|
|
6
|
+
import { closeDb, migrate, openDb } from '../canvas/db.js';
|
|
7
|
+
import { ensureScopeInitialized } from '../config.js';
|
|
8
|
+
import { closeScopedStores } from '../scoped-state/db.js';
|
|
9
|
+
import { enqueueExternalAction } from '../feed/messages.js';
|
|
10
|
+
import { claimExternalActionDelivery, readExternalActionDelivery, settleDelivery } from '../canvas/deliveries.js';
|
|
8
11
|
import { deliveryBackoffMs } from '../canvas/delivery-contract.js';
|
|
9
|
-
import { deliverySettlementForOutcome } from '../../daemon/delivery/run-delivery.js';
|
|
10
|
-
import { deliverAction } from '../../daemon/human/deliver-action.js';
|
|
12
|
+
import { deliverySettlementForOutcome, runDelivery } from '../../daemon/delivery/run-delivery.js';
|
|
11
13
|
let home;
|
|
12
14
|
const priorHome = process.env['CRTR_HOME'];
|
|
15
|
+
const priorUserHome = process.env['HOME'];
|
|
16
|
+
function actionDelivery(requestId) {
|
|
17
|
+
return readExternalActionDelivery(`human-action:${requestId}`);
|
|
18
|
+
}
|
|
19
|
+
function enqueueAction(requestId, argv, cwd, completion) {
|
|
20
|
+
return enqueueExternalAction({
|
|
21
|
+
destinationId: 'human_action',
|
|
22
|
+
adapter: { adapter: 'subprocess', argv, cwd },
|
|
23
|
+
bodyJson: completion,
|
|
24
|
+
idempotencyKey: `human-action:${requestId}`,
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
async function deliverAction(deliveryId, argv, cwd, document, attempt, claimOwner) {
|
|
28
|
+
await runDelivery({ argv, cwd, document, attempt }, (settlement) => settleDelivery(deliveryId, attempt, claimOwner, settlement, Date.now()));
|
|
29
|
+
}
|
|
13
30
|
beforeEach(() => {
|
|
14
31
|
closeDb();
|
|
15
32
|
home = mkdtempSync(join(tmpdir(), 'crtr-human-action-delivery-'));
|
|
16
33
|
process.env['CRTR_HOME'] = home;
|
|
34
|
+
process.env['HOME'] = home;
|
|
35
|
+
ensureScopeInitialized('user', join(home, '.crouter'));
|
|
36
|
+
migrate(openDb());
|
|
17
37
|
});
|
|
18
38
|
afterEach(() => {
|
|
19
39
|
closeDb();
|
|
40
|
+
closeScopedStores();
|
|
20
41
|
rmSync(home, { recursive: true, force: true });
|
|
21
42
|
});
|
|
22
43
|
after(() => {
|
|
23
44
|
closeDb();
|
|
45
|
+
closeScopedStores();
|
|
24
46
|
rmSync(home, { recursive: true, force: true });
|
|
25
47
|
if (priorHome === undefined)
|
|
26
48
|
delete process.env['CRTR_HOME'];
|
|
27
49
|
else
|
|
28
50
|
process.env['CRTR_HOME'] = priorHome;
|
|
51
|
+
if (priorUserHome === undefined)
|
|
52
|
+
delete process.env['HOME'];
|
|
53
|
+
else
|
|
54
|
+
process.env['HOME'] = priorUserHome;
|
|
29
55
|
});
|
|
30
56
|
test('delivery retries follow the durable backoff and exit boundary', () => {
|
|
31
57
|
assert.equal(deliveryBackoffMs(1), 5_000);
|
|
@@ -92,15 +118,12 @@ test('the delivery child gets the consent boundary env, never crtrd\'s own', asy
|
|
|
92
118
|
process.env['CRTRD_ONLY_SECRET'] = 'must-not-cross';
|
|
93
119
|
const requestId = 'b'.repeat(64);
|
|
94
120
|
try {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
completion: { schema: 'crtr.human-completion/v1', requestId, delivery: { attempt: 0 } },
|
|
100
|
-
});
|
|
101
|
-
const claimed = claimActionDelivery(requestId, Date.now(), 'claimant');
|
|
121
|
+
enqueueAction(requestId, [script], project, { schema: 'crtr.human-completion/v1', requestId, delivery: { attempt: 0 } });
|
|
122
|
+
const delivery = actionDelivery(requestId);
|
|
123
|
+
assert.ok(delivery !== null);
|
|
124
|
+
const claimed = claimExternalActionDelivery(delivery.deliveryId, Date.now(), 'claimant');
|
|
102
125
|
assert.ok(claimed !== null);
|
|
103
|
-
await deliverAction(claimed, 'claimant');
|
|
126
|
+
await deliverAction(claimed.deliveryId, [script], project, { schema: 'crtr.human-completion/v1', requestId, delivery: { attempt: 0 } }, claimed.attempts, 'claimant');
|
|
104
127
|
}
|
|
105
128
|
finally {
|
|
106
129
|
delete process.env['NL_CORE_URL'];
|
|
@@ -110,7 +133,7 @@ test('the delivery child gets the consent boundary env, never crtrd\'s own', asy
|
|
|
110
133
|
else
|
|
111
134
|
process.env['HOME'] = priorUserHome;
|
|
112
135
|
}
|
|
113
|
-
assert.equal(
|
|
136
|
+
assert.equal(actionDelivery(requestId)?.state, 'acknowledged');
|
|
114
137
|
const childEnv = new Map(readFileSync(envDump, 'utf8').split('\n').flatMap((line) => {
|
|
115
138
|
const split = line.indexOf('=');
|
|
116
139
|
return split === -1 ? [] : [[line.slice(0, split), line.slice(split + 1)]];
|
|
@@ -122,21 +145,18 @@ test('the delivery child gets the consent boundary env, never crtrd\'s own', asy
|
|
|
122
145
|
});
|
|
123
146
|
test('the guarded claim admits only one contender', () => {
|
|
124
147
|
const requestId = 'a'.repeat(64);
|
|
125
|
-
|
|
126
|
-
requestId,
|
|
127
|
-
argv: ['/bin/true'],
|
|
128
|
-
cwd: home,
|
|
129
|
-
completion: { schema: 'crtr.human-completion/v1', delivery: { attempt: 0 } },
|
|
130
|
-
});
|
|
148
|
+
enqueueAction(requestId, ['/bin/true'], home, { schema: 'crtr.human-completion/v1', delivery: { attempt: 0 } });
|
|
131
149
|
const now = Date.now();
|
|
132
|
-
const
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
150
|
+
const delivery = actionDelivery(requestId);
|
|
151
|
+
assert.ok(delivery !== null);
|
|
152
|
+
const first = claimExternalActionDelivery(delivery.deliveryId, now, 'claimant-a');
|
|
153
|
+
const second = claimExternalActionDelivery(delivery.deliveryId, now, 'claimant-b');
|
|
154
|
+
assert.equal(first?.state, 'handed_off');
|
|
155
|
+
assert.equal(first?.attempts, 1);
|
|
136
156
|
assert.equal(second, null);
|
|
137
|
-
assert.deepEqual(
|
|
138
|
-
state:
|
|
139
|
-
attempt:
|
|
140
|
-
claimOwner:
|
|
141
|
-
}, { state: '
|
|
157
|
+
assert.deepEqual(actionDelivery(requestId) && {
|
|
158
|
+
state: actionDelivery(requestId).state,
|
|
159
|
+
attempt: actionDelivery(requestId).attempts,
|
|
160
|
+
claimOwner: actionDelivery(requestId).claimOwner,
|
|
161
|
+
}, { state: 'handed_off', attempt: 1, claimOwner: 'claimant-a' });
|
|
142
162
|
});
|
|
@@ -8,6 +8,8 @@ import assert from 'node:assert/strict';
|
|
|
8
8
|
import { chmodSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs';
|
|
9
9
|
import { tmpdir } from 'node:os';
|
|
10
10
|
import { join } from 'node:path';
|
|
11
|
+
import { ensureScopeInitialized, writeRawConfig } from '../config.js';
|
|
12
|
+
import { closeScopedStores } from '../scoped-state/db.js';
|
|
11
13
|
import { resolveHumanAction } from '../human-actions.js';
|
|
12
14
|
import { createProfile } from '../profiles/manifest.js';
|
|
13
15
|
import { resetScopeCache } from '../scope.js';
|
|
@@ -29,13 +31,16 @@ beforeEach(() => {
|
|
|
29
31
|
delete process.env['CRTR_PROFILE_ID'];
|
|
30
32
|
process.chdir(cwd);
|
|
31
33
|
resetScopeCache();
|
|
34
|
+
ensureScopeInitialized('user', join(home, '.crouter'));
|
|
32
35
|
});
|
|
33
36
|
afterEach(() => {
|
|
34
37
|
process.chdir(previousCwd);
|
|
38
|
+
closeScopedStores();
|
|
35
39
|
rmSync(home, { recursive: true, force: true });
|
|
36
40
|
resetScopeCache();
|
|
37
41
|
});
|
|
38
42
|
after(() => {
|
|
43
|
+
closeScopedStores();
|
|
39
44
|
process.chdir(previousCwd);
|
|
40
45
|
if (previousHome === undefined)
|
|
41
46
|
delete process.env['HOME'];
|
|
@@ -57,10 +62,9 @@ function writeAction(root, relativeExecutable, relativeCwd) {
|
|
|
57
62
|
test('nearest project declaration wins and resolves paths from its authoring root', () => {
|
|
58
63
|
const userRoot = join(home, '.crouter');
|
|
59
64
|
writeAction(userRoot, 'user-bin', 'user-cwd');
|
|
60
|
-
|
|
61
|
-
writeFileSync(join(userRoot, 'config.json'), JSON.stringify({
|
|
65
|
+
writeRawConfig('user', {
|
|
62
66
|
humanActions: { release: { argv: ['user-bin'], cwd: 'user-cwd' }, 'user-only': { argv: ['user-bin'], cwd: 'user-cwd' } },
|
|
63
|
-
})
|
|
67
|
+
});
|
|
64
68
|
const outer = join(home, 'work', 'outer');
|
|
65
69
|
writeAction(outer, 'outer-bin', 'outer-cwd');
|
|
66
70
|
mkdirSync(join(outer, '.crouter'), { recursive: true });
|