@north-light/crouter 0.3.312 → 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 +13 -1
- package/dist/core/__tests__/cron-armed-context-failure.test.js +17 -12
- package/dist/core/__tests__/cron-held-settlement.test.js +21 -3
- package/dist/core/__tests__/cron-node-sink-parked-root.test.js +29 -10
- package/dist/core/__tests__/cron-self-cancel-delivery.test.js +14 -2
- package/dist/core/__tests__/cron-timeout-descendants.test.js +13 -1
- package/dist/core/__tests__/daemon-boot.test.js +51 -14
- package/dist/core/__tests__/fixtures/fake-engine.d.ts +1 -1
- package/dist/core/__tests__/fixtures/fake-engine.js +8 -3
- package/dist/core/__tests__/focuses.test.js +10 -5
- package/dist/core/__tests__/helpers/harness.js +50 -18
- package/dist/core/__tests__/history-inbox.test.js +12 -16
- package/dist/core/__tests__/human-action-delivery.test.js +48 -28
- package/dist/core/__tests__/human-actions.test.js +7 -3
- package/dist/core/__tests__/inline-memory-refs.test.js +7 -2
- package/dist/core/__tests__/integration/broker-fork-seam.test.js +37 -10
- package/dist/core/__tests__/integration/broker-sdk-wiring.test.js +42 -0
- package/dist/core/__tests__/integration/broker-snapshot-history.test.js +42 -29
- package/dist/core/__tests__/integration/broker-wedge-supervision.test.js +36 -35
- package/dist/core/__tests__/integration/command-plugins.test.js +15 -6
- package/dist/core/__tests__/integration/deferred-no-wake.test.js +113 -92
- package/dist/core/__tests__/integration/host-teardown-process-group.test.js +9 -5
- package/dist/core/__tests__/integration/lifecycle-hooks.test.js +16 -3
- package/dist/core/__tests__/integration/plugin-revalidate.test.js +4 -0
- package/dist/core/__tests__/integration/profile-pause.test.js +4 -4
- package/dist/core/__tests__/integration/refresh-stall-recycle.test.js +9 -12
- package/dist/core/__tests__/integration/revive.test.js +67 -21
- package/dist/core/__tests__/integration/spawn-root.test.js +51 -8
- package/dist/core/__tests__/integration/subscription-delivery.test.js +33 -21
- package/dist/core/__tests__/integration/worktree-land.test.js +5 -2
- package/dist/core/__tests__/integration/worktree-reap.test.js +15 -1
- package/dist/core/__tests__/kickoff.test.js +36 -39
- package/dist/core/__tests__/lifecycle-terminal-reasons.test.js +2 -1
- package/dist/core/__tests__/lifecycle.test.js +2 -1
- package/dist/core/__tests__/live-lifecycle-prompt.test.js +13 -1
- package/dist/core/__tests__/memory-resolver-precedence.test.js +2 -0
- package/dist/core/__tests__/migration.test.js +145 -31
- package/dist/core/__tests__/model-pin-durability.test.js +4 -1
- package/dist/core/__tests__/model-routes-config.test.js +13 -5
- package/dist/core/__tests__/node-outcome.test.js +93 -26
- package/dist/core/__tests__/on-read-crouter-home-fence.test.js +2 -1
- package/dist/core/__tests__/on-read-dedup-resume.test.js +2 -1
- package/dist/core/__tests__/on-read-nested-store.test.js +2 -1
- package/dist/core/__tests__/passive-subscription.test.js +50 -157
- package/dist/core/__tests__/plugin-kinds.test.js +6 -4
- package/dist/core/__tests__/plugin-link-symlinked-scope-root.test.js +6 -1
- package/dist/core/__tests__/plugin-page-components.test.js +6 -4
- package/dist/core/__tests__/preview-registry-sync.test.js +2 -0
- package/dist/core/__tests__/profile-project-memory-delivery.test.js +4 -1
- package/dist/core/__tests__/prune.test.js +11 -5
- package/dist/core/__tests__/push-final-guard.test.js +14 -7
- package/dist/core/__tests__/relaunch-root.test.js +30 -2
- package/dist/core/__tests__/remote-canvas-target.test.js +7 -1
- package/dist/core/__tests__/repository-root-identity.test.js +4 -0
- package/dist/core/__tests__/review-model-floor.test.js +6 -3
- package/dist/core/__tests__/revive-all.test.js +13 -3
- package/dist/core/__tests__/revive-capacity.test.js +26 -4
- package/dist/core/__tests__/revive-parked-fresh.test.js +31 -8
- package/dist/core/__tests__/seam/broker-attach-stream.test.js +1 -1
- package/dist/core/__tests__/seam/broker-cap-freeze.test.js +4 -3
- package/dist/core/__tests__/seam/broker-crash-teardown.test.js +11 -14
- package/dist/core/__tests__/seam/broker-provider-retry.test.js +85 -71
- package/dist/core/__tests__/seam/dormancy-release.test.js +33 -19
- package/dist/core/__tests__/seam/held-deferred-human-prompt.test.js +7 -5
- package/dist/core/__tests__/seam/inbox-reference-guidance.test.js +20 -6
- package/dist/core/__tests__/seam/node-outcome-delivery.test.js +27 -3
- package/dist/core/__tests__/spawn-worktree-id-conflict.test.js +2 -1
- package/dist/core/__tests__/stop-guard.test.js +2 -1
- package/dist/core/__tests__/subscription-pool-credential-guard.test.js +4 -3
- package/dist/core/__tests__/warm-claim-preference-snapshot.test.js +18 -4
- package/dist/core/__tests__/yield-ensures-daemon.test.js +2 -1
- package/dist/core/bootstrap.js +2 -0
- package/dist/core/broker-client/__tests__/transport-socket.test.js +51 -6
- package/dist/core/broker-client/transport-socket.d.ts +1 -0
- package/dist/core/broker-client/transport-socket.js +13 -5
- package/dist/core/canvas/__tests__/attention.test.js +29 -35
- package/dist/core/canvas/__tests__/history-transcript.test.js +6 -6
- package/dist/core/canvas/__tests__/render-remote.test.js +25 -9
- package/dist/core/canvas/attention.d.ts +2 -5
- package/dist/core/canvas/attention.js +15 -64
- package/dist/core/canvas/boot.d.ts +6 -7
- package/dist/core/canvas/boot.js +5 -9
- package/dist/core/canvas/canvas.d.ts +13 -109
- package/dist/core/canvas/canvas.js +140 -401
- package/dist/core/canvas/crons.d.ts +2 -0
- package/dist/core/canvas/crons.js +16 -15
- package/dist/core/canvas/daemon-owner.js +10 -0
- package/dist/core/canvas/db.d.ts +2 -2
- package/dist/core/canvas/db.js +2 -18
- package/dist/core/canvas/deliveries.d.ts +104 -0
- package/dist/core/canvas/deliveries.js +354 -0
- package/dist/core/canvas/executions.d.ts +29 -0
- package/dist/core/canvas/executions.js +68 -0
- package/dist/core/canvas/history.js +35 -35
- package/dist/core/canvas/index.d.ts +3 -1
- package/dist/core/canvas/index.js +3 -1
- package/dist/core/canvas/migrations.js +20 -12
- package/dist/core/canvas/nav-model.js +1 -3
- package/dist/core/canvas/nav-render.d.ts +4 -4
- package/dist/core/canvas/nav-render.js +11 -21
- package/dist/core/canvas/node-sql-migration.d.ts +3 -0
- package/dist/core/canvas/node-sql-migration.js +261 -0
- package/dist/core/canvas/paths.d.ts +2 -16
- package/dist/core/canvas/paths.js +2 -31
- package/dist/core/canvas/recovery.d.ts +76 -0
- package/dist/core/canvas/recovery.js +588 -0
- package/dist/core/canvas/remote-canvas-source.js +4 -0
- package/dist/core/canvas/render-source.d.ts +16 -27
- package/dist/core/canvas/render-source.js +16 -45
- package/dist/core/canvas/sessions.d.ts +33 -0
- package/dist/core/canvas/sessions.js +78 -0
- package/dist/core/canvas/types.d.ts +33 -33
- package/dist/core/canvas/types.js +2 -5
- package/dist/core/canvas/waits.d.ts +18 -0
- package/dist/core/canvas/waits.js +70 -0
- package/dist/core/canvas/worktrees.d.ts +40 -0
- package/dist/core/canvas/worktrees.js +93 -0
- package/dist/core/config.d.ts +17 -12
- package/dist/core/config.js +106 -155
- package/dist/core/feed/__tests__/inbox-migrate.test.js +27 -31
- package/dist/core/feed/feed.d.ts +0 -6
- package/dist/core/feed/feed.js +68 -56
- package/dist/core/feed/inbox.d.ts +7 -81
- package/dist/core/feed/inbox.js +46 -378
- package/dist/core/feed/messages.d.ts +58 -0
- package/dist/core/feed/messages.js +217 -0
- package/dist/core/fs-utils.d.ts +4 -0
- package/dist/core/fs-utils.js +21 -1
- package/dist/core/human/answer.d.ts +1 -1
- package/dist/core/human/answer.js +1 -1
- package/dist/core/human/claim.d.ts +1 -1
- package/dist/core/human/claim.js +2 -4
- package/dist/core/human/component-docs.js +1 -1
- package/dist/core/human/feedback-companion.js +3 -2
- package/dist/core/human/feedback.d.ts +5 -8
- package/dist/core/human/feedback.js +57 -85
- package/dist/core/human/page-authoring.d.ts +30 -0
- package/dist/core/human/page-authoring.js +19 -0
- package/dist/core/human/requests.d.ts +136 -0
- package/dist/core/human/requests.js +515 -0
- package/dist/core/human/root.d.ts +0 -7
- package/dist/core/human/root.js +0 -17
- package/dist/core/human/scan.d.ts +2 -7
- package/dist/core/human/scan.js +48 -132
- package/dist/core/human/summary.d.ts +1 -1
- package/dist/core/human/summary.js +1 -1
- package/dist/core/human/tickets.d.ts +23 -83
- package/dist/core/human/tickets.js +92 -243
- package/dist/core/human/types.d.ts +5 -1
- package/dist/core/installed-plugins.js +8 -3
- package/dist/core/keybindings/__tests__/resolve.test.js +19 -17
- package/dist/core/locked-file.d.ts +6 -3
- package/dist/core/locked-file.js +36 -9
- package/dist/core/memory/extensions.js +2 -0
- package/dist/core/preview-registry.js +0 -1
- package/dist/core/profiles/__tests__/env-store.test.js +2 -0
- package/dist/core/profiles/default-binding.d.ts +0 -4
- package/dist/core/profiles/default-binding.js +12 -58
- package/dist/core/profiles/env-store.js +8 -3
- package/dist/core/profiles/manifest.d.ts +2 -37
- package/dist/core/profiles/manifest.js +35 -161
- package/dist/core/profiles/select.js +3 -0
- package/dist/core/review/__tests__/capture-origin.test.js +13 -2
- package/dist/core/review/__tests__/comments.test.js +28 -10
- package/dist/core/review/__tests__/remap.test.js +28 -10
- package/dist/core/review/__tests__/stage-identity.test.js +17 -7
- package/dist/core/review/birth.d.ts +1 -1
- package/dist/core/review/birth.js +34 -5
- package/dist/core/review/comments.js +1 -1
- package/dist/core/review/document.js +1 -1
- package/dist/core/review/project.d.ts +5 -1
- package/dist/core/review/project.js +14 -36
- package/dist/core/review/realize.d.ts +3 -6
- package/dist/core/review/realize.js +51 -168
- package/dist/core/review/remap.js +1 -1
- package/dist/core/review/stage.d.ts +3 -2
- package/dist/core/review/stage.js +2 -3
- package/dist/core/review/store.d.ts +3 -21
- package/dist/core/review/store.js +140 -186
- package/dist/core/review/types.d.ts +0 -1
- package/dist/core/runtime/__tests__/install-id-cache-scoping.test.js +9 -5
- package/dist/core/runtime/__tests__/spawn-env.test.js +8 -9
- package/dist/core/runtime/broker/auth-reload.js +9 -10
- package/dist/core/runtime/broker/daemon-ops.d.ts +25 -8
- package/dist/core/runtime/broker/daemon-ops.js +42 -9
- package/dist/core/runtime/broker/extension-abort.d.ts +3 -0
- package/dist/core/runtime/broker/extension-abort.js +11 -0
- package/dist/core/runtime/broker/fault-retry.d.ts +15 -6
- package/dist/core/runtime/broker/fault-retry.js +142 -95
- package/dist/core/runtime/broker/inbox.d.ts +4 -32
- package/dist/core/runtime/broker/inbox.js +4 -92
- package/dist/core/runtime/broker/rebind.d.ts +1 -0
- package/dist/core/runtime/broker/rebind.js +21 -12
- package/dist/core/runtime/broker-persona-guidance.d.ts +1 -1
- package/dist/core/runtime/broker-persona-guidance.js +2 -13
- package/dist/core/runtime/broker.js +28 -22
- package/dist/core/runtime/close.d.ts +3 -9
- package/dist/core/runtime/close.js +16 -27
- package/dist/core/runtime/fault.d.ts +3 -93
- package/dist/core/runtime/fault.js +9 -419
- package/dist/core/runtime/kickoff.d.ts +3 -6
- package/dist/core/runtime/kickoff.js +12 -18
- package/dist/core/runtime/launch.js +1 -1
- package/dist/core/runtime/lifecycle.js +40 -7
- package/dist/core/runtime/placement.js +2 -2
- package/dist/core/runtime/recycle.js +8 -2
- package/dist/core/runtime/reset.js +22 -6
- package/dist/core/runtime/revive.js +226 -218
- package/dist/core/runtime/spawn.js +14 -3
- package/dist/core/scoped-state/db.d.ts +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 +39 -15
- package/dist/daemon/__tests__/node-outcome-delivery.test.js +39 -10
- package/dist/daemon/__tests__/reconciler-signature.test.js +2 -2
- package/dist/daemon/__tests__/subtree-filter-freshness.test.js +2 -2
- package/dist/daemon/api/__tests__/broker-settle-park.test.js +17 -12
- package/dist/daemon/api/__tests__/canvas-snapshot-fields.test.js +27 -5
- package/dist/daemon/api/__tests__/model-config.test.js +8 -8
- package/dist/daemon/api/__tests__/node-create-description.test.js +22 -5
- package/dist/daemon/api/__tests__/node-model-validation.test.js +21 -1
- package/dist/daemon/api/__tests__/nodes-activity-query.test.js +10 -12
- package/dist/daemon/api/__tests__/profile-launch-gates.test.js +4 -1
- package/dist/daemon/api/__tests__/profile-metadata-route.test.js +4 -1
- package/dist/daemon/api/__tests__/reopen-delivery.test.js +26 -8
- package/dist/daemon/api/__tests__/seam/api-server.test.js +24 -32
- package/dist/daemon/api/__tests__/seam/b10-attach-modelauth.test.js +4 -1
- package/dist/daemon/api/__tests__/seam/leaf-api-parity.test.js +5 -4
- package/dist/daemon/api/__tests__/seam/profile-delete.test.js +27 -41
- package/dist/daemon/api/__tests__/submit-result.test.js +3 -2
- package/dist/daemon/api/bridge.js +1 -1
- package/dist/daemon/api/handlers/bash-jobs.js +6 -7
- package/dist/daemon/api/handlers/broker-ops.js +47 -84
- package/dist/daemon/api/handlers/broker-recovery.d.ts +4 -0
- package/dist/daemon/api/handlers/broker-recovery.js +251 -0
- package/dist/daemon/api/handlers/canvas.js +2 -44
- package/dist/daemon/api/handlers/daemon.js +41 -0
- package/dist/daemon/api/handlers/feedback-comments.js +2 -2
- package/dist/daemon/api/handlers/health.js +10 -5
- package/dist/daemon/api/handlers/human-requests.js +168 -188
- package/dist/daemon/api/handlers/human.js +3 -151
- package/dist/daemon/api/handlers/inbox-page.d.ts +4 -0
- package/dist/daemon/api/handlers/inbox-page.js +89 -0
- package/dist/daemon/api/handlers/inbox.js +21 -120
- package/dist/daemon/api/handlers/messages.d.ts +1 -0
- package/dist/daemon/api/handlers/messages.js +73 -15
- package/dist/daemon/api/handlers/node-outcomes.js +58 -13
- package/dist/daemon/api/handlers/nodes.js +7 -13
- package/dist/daemon/api/handlers/reviews.js +4 -29
- package/dist/daemon/api/map.d.ts +25 -3
- package/dist/daemon/api/map.js +84 -14
- package/dist/daemon/api/server.js +68 -9
- package/dist/daemon/control.d.ts +18 -0
- package/dist/daemon/cron/disposition.d.ts +2 -0
- package/dist/daemon/cron/disposition.js +8 -5
- package/dist/daemon/cron/settle.js +37 -13
- package/dist/daemon/cron/sinks.d.ts +18 -1
- package/dist/daemon/cron/sinks.js +47 -93
- package/dist/daemon/crtrd-cli.js +4 -19
- package/dist/daemon/crtrd.d.ts +2 -0
- package/dist/daemon/crtrd.js +206 -81
- package/dist/daemon/fleet.js +5 -6
- package/dist/daemon/human/finish.d.ts +12 -24
- package/dist/daemon/human/finish.js +88 -285
- package/dist/daemon/human/settle.d.ts +40 -0
- package/dist/daemon/human/settle.js +89 -0
- package/dist/daemon/human/sweep.d.ts +20 -5
- package/dist/daemon/human/sweep.js +56 -60
- package/dist/daemon/manage.d.ts +21 -16
- package/dist/daemon/manage.js +85 -51
- package/dist/daemon/messaging/node-message.d.ts +1 -1
- package/dist/daemon/messaging/node-message.js +9 -12
- package/dist/daemon/park-activity.js +3 -3
- package/dist/daemon/reconcilers/bash-deadline.js +6 -7
- package/dist/daemon/reconcilers/broker-supervision.d.ts +1 -1
- package/dist/daemon/reconcilers/broker-supervision.js +41 -19
- package/dist/daemon/reconcilers/controller-death.js +6 -18
- package/dist/daemon/reconcilers/delivery-lane.d.ts +9 -0
- package/dist/daemon/reconcilers/delivery-lane.js +130 -0
- package/dist/daemon/reconcilers/live-obligation.js +3 -3
- package/dist/daemon/reconcilers/node-deadline.js +1 -1
- package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.d.ts +1 -1
- package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.js +10 -12
- package/dist/daemon/reconcilers/node-lifecycle/tick.js +5 -5
- package/dist/daemon/reconcilers/node-lifecycle/wants-execution.js +1 -1
- package/dist/daemon/reconcilers/pending-review-submit.js +3 -3
- package/dist/daemon/reconcilers/storage-maintenance.d.ts +2 -8
- package/dist/daemon/reconcilers/storage-maintenance.js +13 -43
- package/dist/daemon/review/companion.js +5 -11
- package/dist/daemon/review/deliver.d.ts +1 -5
- package/dist/daemon/review/deliver.js +3 -52
- package/dist/daemon/review/finish.d.ts +2 -27
- package/dist/daemon/review/finish.js +79 -263
- package/dist/daemon/review/sweep.d.ts +3 -10
- package/dist/daemon/review/sweep.js +13 -131
- package/dist/daemon/startup-policy.d.ts +0 -5
- package/dist/daemon/startup-policy.js +0 -5
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1 -1
- package/dist/migrations/__tests__/activation-concurrency.test.js +3 -2
- package/dist/migrations/__tests__/activation.test.js +9 -6
- package/dist/migrations/activation.d.ts +3 -2
- package/dist/migrations/activation.js +2 -4
- package/dist/migrations/corpus.d.ts +2 -5
- package/dist/migrations/corpus.js +9 -20
- package/dist/migrations/runner.d.ts +3 -1
- package/dist/migrations/runner.js +6 -2
- package/dist/pi-extensions/__tests__/canvas-context-intro.test.js +21 -89
- package/dist/pi-extensions/__tests__/canvas-goal-capture-envelope.test.js +4 -2
- package/dist/pi-extensions/__tests__/canvas-stophook-agentend.test.js +51 -33
- package/dist/pi-extensions/__tests__/canvas-stophook-context-nudge.test.js +16 -2
- package/dist/pi-extensions/__tests__/pre-command-gate.test.js +13 -1
- package/dist/pi-extensions/canvas-inbox-watcher.js +98 -244
- package/dist/pi-extensions/canvas-passive-context.d.ts +4 -8
- package/dist/pi-extensions/canvas-passive-context.js +85 -37
- package/dist/pi-extensions/canvas-stophook.js +47 -31
- package/dist/shared/env.d.ts +1 -0
- package/dist/shared/env.js +3 -0
- package/package.json +1 -1
- package/runtime.lock.json +5 -5
- package/dist/clients/attach/__tests__/page-block.test.js +0 -54
- package/dist/clients/inbox/review-visibility.d.ts +0 -5
- package/dist/clients/inbox/review-visibility.js +0 -19
- package/dist/commands/canvas-rebuild-index.d.ts +0 -2
- package/dist/commands/canvas-rebuild-index.js +0 -46
- package/dist/core/__tests__/human-cancel-guard.test.js +0 -110
- package/dist/core/__tests__/human-deliver.test.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
|
@@ -27,9 +27,12 @@ import { tmpdir } from 'node:os';
|
|
|
27
27
|
import { join } from 'node:path';
|
|
28
28
|
import registerCanvasInboxWatcher from '../../pi-extensions/canvas-inbox-watcher.js';
|
|
29
29
|
import { createNode } from '../canvas/canvas.js';
|
|
30
|
-
import { closeDb } from '../canvas/db.js';
|
|
30
|
+
import { closeDb, migrate, openDb } from '../canvas/db.js';
|
|
31
|
+
import { acknowledgeNodeMail, claimNodeMail } from '../canvas/deliveries.js';
|
|
32
|
+
import { beginExecution } from '../canvas/executions.js';
|
|
31
33
|
import { apiSocketPath } from '../canvas/paths.js';
|
|
32
|
-
import {
|
|
34
|
+
import { enqueueNodeMail } from '../feed/messages.js';
|
|
35
|
+
import { nodeMailEntry } from '../feed/inbox.js';
|
|
33
36
|
import { BROKER_IDLE_TURN_START } from '../runtime/broker/held-deferred-inbox.js';
|
|
34
37
|
const TICK_MS = 20;
|
|
35
38
|
const DEBOUNCE_MS = 25;
|
|
@@ -107,19 +110,35 @@ function registerWatcher(pi) {
|
|
|
107
110
|
function freshNode(id) {
|
|
108
111
|
process.env['CRTR_NODE_ID'] = id;
|
|
109
112
|
createNode(node(id));
|
|
113
|
+
process.env['CRTR_EXECUTION_ID'] = beginExecution(id, { daemonEpoch: 'test' });
|
|
114
|
+
}
|
|
115
|
+
function publishMail(nodeId, input) {
|
|
116
|
+
return enqueueNodeMail(nodeId, {
|
|
117
|
+
kind: input.kind,
|
|
118
|
+
label: input.label,
|
|
119
|
+
senderNodeId: input.from,
|
|
120
|
+
bodyRef: input.ref,
|
|
121
|
+
bodyJson: input.data,
|
|
122
|
+
disposition: input.disposition,
|
|
123
|
+
urgency: input.tier,
|
|
124
|
+
wake: 1,
|
|
125
|
+
});
|
|
110
126
|
}
|
|
111
127
|
let origHome;
|
|
112
128
|
let origNode;
|
|
129
|
+
let origExecution;
|
|
113
130
|
let origTick;
|
|
114
131
|
let origDebounce;
|
|
115
132
|
before(async () => {
|
|
116
133
|
origHome = process.env['CRTR_HOME'];
|
|
117
134
|
origNode = process.env['CRTR_NODE_ID'];
|
|
135
|
+
origExecution = process.env['CRTR_EXECUTION_ID'];
|
|
118
136
|
origTick = process.env['CRTR_WATCHER_TICK_MS'];
|
|
119
137
|
origDebounce = process.env['CRTR_WATCHER_DEBOUNCE_MS'];
|
|
120
138
|
home = mkdtempSync(join(tmpdir(), 'crtr-inbox-naming-'));
|
|
121
139
|
mkdirSync(join(home, 'nodes'), { recursive: true });
|
|
122
140
|
process.env['CRTR_HOME'] = home;
|
|
141
|
+
migrate(openDb());
|
|
123
142
|
process.env['CRTR_WATCHER_TICK_MS'] = String(TICK_MS);
|
|
124
143
|
process.env['CRTR_WATCHER_DEBOUNCE_MS'] = String(DEBOUNCE_MS);
|
|
125
144
|
socket = createServer((connection) => {
|
|
@@ -151,9 +170,35 @@ before(async () => {
|
|
|
151
170
|
respond(connection, '200 OK', { applied: false });
|
|
152
171
|
return;
|
|
153
172
|
}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
173
|
+
const nodeId = nodeIdFromPath(path ?? '');
|
|
174
|
+
const bodyText = raw.split('\r\n\r\n')[1] ?? '';
|
|
175
|
+
const body = JSON.parse(bodyText);
|
|
176
|
+
if (method === 'POST' && path?.endsWith('/mail/claim')) {
|
|
177
|
+
const result = claimNodeMail(nodeId, body['execution_id'], body['channel']);
|
|
178
|
+
respond(connection, '200 OK', {
|
|
179
|
+
action: result.action,
|
|
180
|
+
deliveries: result.deliveries.map((delivery) => ({
|
|
181
|
+
delivery_id: delivery.deliveryId,
|
|
182
|
+
attempts: delivery.attempts,
|
|
183
|
+
handoff: delivery.handoff,
|
|
184
|
+
entry: nodeMailEntry(delivery),
|
|
185
|
+
})),
|
|
186
|
+
});
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
if (method === 'POST' && path?.endsWith('/mail/acknowledge')) {
|
|
190
|
+
const receipts = body['deliveries'];
|
|
191
|
+
const result = acknowledgeNodeMail(nodeId, body['execution_id'], receipts.map((receipt) => ({
|
|
192
|
+
deliveryId: receipt.delivery_id,
|
|
193
|
+
attempts: receipt.attempts,
|
|
194
|
+
disposition: receipt.disposition,
|
|
195
|
+
})));
|
|
196
|
+
respond(connection, '200 OK', {
|
|
197
|
+
action: result.action,
|
|
198
|
+
results: result.results.map((receipt) => ({ delivery_id: receipt.deliveryId, outcome: receipt.outcome })),
|
|
199
|
+
});
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
157
202
|
respond(connection, '500 Internal Server Error', { error: { code: 'internal', message: 'stub daemon' } });
|
|
158
203
|
});
|
|
159
204
|
});
|
|
@@ -175,6 +220,10 @@ after(async () => {
|
|
|
175
220
|
delete process.env['CRTR_NODE_ID'];
|
|
176
221
|
else
|
|
177
222
|
process.env['CRTR_NODE_ID'] = origNode;
|
|
223
|
+
if (origExecution === undefined)
|
|
224
|
+
delete process.env['CRTR_EXECUTION_ID'];
|
|
225
|
+
else
|
|
226
|
+
process.env['CRTR_EXECUTION_ID'] = origExecution;
|
|
178
227
|
if (origTick === undefined)
|
|
179
228
|
delete process.env['CRTR_WATCHER_TICK_MS'];
|
|
180
229
|
else
|
|
@@ -189,7 +238,7 @@ test('an inbox-delivered human first message reaches the naming pipeline and cap
|
|
|
189
238
|
const pi = makeFakePi();
|
|
190
239
|
disposers.push(registerWatcher(pi));
|
|
191
240
|
await wait(TICK_MS + 100);
|
|
192
|
-
|
|
241
|
+
publishMail('inbox-human-unnamed', {
|
|
193
242
|
from: 'human',
|
|
194
243
|
tier: 'normal',
|
|
195
244
|
kind: 'message',
|
|
@@ -209,7 +258,7 @@ test('a card/envelope delivery never reaches naming or goal capture', async () =
|
|
|
209
258
|
const pi = makeFakePi();
|
|
210
259
|
const dispose = registerWatcher(pi);
|
|
211
260
|
await wait(TICK_MS + 100);
|
|
212
|
-
|
|
261
|
+
publishMail('inbox-card-only', { from: 'child-9', tier: 'normal', kind: 'update', label: 'phase one done' });
|
|
213
262
|
await waitFor(() => pi.injected.length >= 1, 3000);
|
|
214
263
|
assert.equal(pi.injected.length, 1, 'the card still reaches the digest as a visible send');
|
|
215
264
|
dispose(); // release ownership of this node id before a second watcher binds a new one
|
|
@@ -221,7 +270,7 @@ test('a card/envelope delivery never reaches naming or goal capture', async () =
|
|
|
221
270
|
const clockPi = makeFakePi();
|
|
222
271
|
disposers.push(registerWatcher(clockPi));
|
|
223
272
|
await wait(TICK_MS + 100);
|
|
224
|
-
|
|
273
|
+
publishMail('inbox-card-clock', { from: 'human', tier: 'normal', kind: 'message', label: 'clock', data: { body: 'clock' } });
|
|
225
274
|
await waitFor(() => getRequests.some((line) => line.includes('inbox-card-clock')));
|
|
226
275
|
// Exactly the one startup GET (report-node seed) — no second, naming-triggered fetch.
|
|
227
276
|
assert.equal(getRequestCount('inbox-card-only'), 1, 'a card/envelope delivery never asks the naming pipeline to name the node');
|
|
@@ -233,7 +282,7 @@ test('an already-described node fetches state but never commits a new name', asy
|
|
|
233
282
|
const pi = makeFakePi();
|
|
234
283
|
const dispose = registerWatcher(pi);
|
|
235
284
|
await wait(TICK_MS + 100);
|
|
236
|
-
|
|
285
|
+
publishMail('inbox-already-named', {
|
|
237
286
|
from: 'human',
|
|
238
287
|
tier: 'normal',
|
|
239
288
|
kind: 'message',
|
|
@@ -254,7 +303,7 @@ test('an already-described node fetches state but never commits a new name', asy
|
|
|
254
303
|
const clockPi = makeFakePi();
|
|
255
304
|
disposers.push(registerWatcher(clockPi));
|
|
256
305
|
await wait(TICK_MS + 100);
|
|
257
|
-
|
|
306
|
+
publishMail('inbox-commit-clock', { from: 'human', tier: 'normal', kind: 'message', label: 'clock', data: { body: 'clock' } });
|
|
258
307
|
await waitFor(() => getRequests.some((line) => line.includes('inbox-commit-clock')));
|
|
259
308
|
await wait(DEBOUNCE_MS + 100);
|
|
260
309
|
assert.equal(postRequests.some((line) => line.includes('inbox-already-named')), false, 'an already-described node is untouched: the guard short-circuits before any generated-name commit');
|
|
@@ -12,13 +12,17 @@ import { mkdirSync, rmSync, writeFileSync } from 'node:fs';
|
|
|
12
12
|
import { tmpdir } from 'node:os';
|
|
13
13
|
import { join } from 'node:path';
|
|
14
14
|
import registerCanvasInboxWatcher from '../../pi-extensions/canvas-inbox-watcher.js';
|
|
15
|
-
import { createNode } from '../canvas/canvas.js';
|
|
15
|
+
import { createNode, getNode } from '../canvas/canvas.js';
|
|
16
|
+
import { claimNodeMail } from '../canvas/deliveries.js';
|
|
16
17
|
import { reportsDir } from '../canvas/paths.js';
|
|
17
|
-
import { closeDb } from '../canvas/db.js';
|
|
18
|
-
import {
|
|
18
|
+
import { closeDb, migrate, openDb } from '../canvas/db.js';
|
|
19
|
+
import { beginExecution } from '../canvas/executions.js';
|
|
20
|
+
import { enqueueNodeMail } from '../feed/messages.js';
|
|
21
|
+
import { coalesce, nodeMailEntry } from '../feed/inbox.js';
|
|
19
22
|
import { appendSituationalContext, SITUATIONAL_CONTEXT_CUSTOM_TYPE } from '../runtime/situational-context.js';
|
|
20
23
|
import { parseCard } from '../../shared/generated-context.js';
|
|
21
24
|
import { BROKER_IDLE_TURN_START } from '../runtime/broker/held-deferred-inbox.js';
|
|
25
|
+
import { createApiServer } from '../../daemon/api/server.js';
|
|
22
26
|
// Drive the watcher's injectable cadence seam (CRTR_WATCHER_TICK_MS /
|
|
23
27
|
// CRTR_WATCHER_DEBOUNCE_MS) at a fast tempo so the watcher delivers in tens of
|
|
24
28
|
// milliseconds, not seconds — exactly the resolve+seed tick, read tick, and
|
|
@@ -29,15 +33,53 @@ const TICK_MS = 20;
|
|
|
29
33
|
const DEBOUNCE_MS = 25;
|
|
30
34
|
let origHome;
|
|
31
35
|
let origNode;
|
|
36
|
+
let origExecution;
|
|
32
37
|
const homes = [];
|
|
38
|
+
let server;
|
|
33
39
|
const disposers = [];
|
|
34
40
|
/** Point CRTR_HOME at a fresh temp canvas root and bind CRTR_NODE_ID. */
|
|
35
41
|
function freshNode(nodeId) {
|
|
36
|
-
|
|
42
|
+
closeDb();
|
|
43
|
+
const home = join(tmpdir(), `cw-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
|
37
44
|
mkdirSync(home, { recursive: true });
|
|
38
45
|
homes.push(home);
|
|
39
46
|
process.env['CRTR_HOME'] = home;
|
|
40
47
|
process.env['CRTR_NODE_ID'] = nodeId;
|
|
48
|
+
migrate(openDb());
|
|
49
|
+
}
|
|
50
|
+
function ensureWatcherNode(nodeId) {
|
|
51
|
+
if (getNode(nodeId) !== null)
|
|
52
|
+
return;
|
|
53
|
+
createNode({
|
|
54
|
+
node_id: nodeId,
|
|
55
|
+
name: nodeId,
|
|
56
|
+
created: new Date().toISOString(),
|
|
57
|
+
cwd: '/tmp/work',
|
|
58
|
+
kind: 'general',
|
|
59
|
+
mode: 'base',
|
|
60
|
+
lifecycle: 'resident',
|
|
61
|
+
status: 'active',
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
function publishMail(nodeId, input) {
|
|
65
|
+
ensureWatcherNode(nodeId);
|
|
66
|
+
return enqueueNodeMail(nodeId, {
|
|
67
|
+
kind: input.kind,
|
|
68
|
+
label: input.label,
|
|
69
|
+
senderNodeId: input.from,
|
|
70
|
+
bodyRef: input.ref,
|
|
71
|
+
bodyJson: input.data,
|
|
72
|
+
disposition: input.disposition,
|
|
73
|
+
urgency: input.tier,
|
|
74
|
+
wake: 1,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
function claimedMail(nodeId, input) {
|
|
78
|
+
publishMail(nodeId, input);
|
|
79
|
+
const claim = claimNodeMail(nodeId, beginExecution(nodeId, { daemonEpoch: 'test' }), 'wake');
|
|
80
|
+
assert.equal(claim.action, 'claimed');
|
|
81
|
+
assert.equal(claim.deliveries.length, 1);
|
|
82
|
+
return nodeMailEntry(claim.deliveries[0]);
|
|
41
83
|
}
|
|
42
84
|
function makeFakePi() {
|
|
43
85
|
const handlers = {};
|
|
@@ -63,8 +105,12 @@ function onlyDelivery(deliveries) {
|
|
|
63
105
|
// registerCanvasInboxWatcher() alone only wires up handlers; without this the
|
|
64
106
|
// watcher never polls or sends anything.
|
|
65
107
|
function registerWatcher(pi) {
|
|
108
|
+
const nodeId = process.env['CRTR_NODE_ID'];
|
|
109
|
+
ensureWatcherNode(nodeId);
|
|
110
|
+
process.env['CRTR_EXECUTION_ID'] = beginExecution(nodeId, { daemonEpoch: 'test' });
|
|
66
111
|
const dispose = registerCanvasInboxWatcher(pi);
|
|
67
|
-
|
|
112
|
+
server ??= createApiServer();
|
|
113
|
+
void server.ready.then(() => pi.fire('session_start', { type: 'session_start' }, undefined));
|
|
68
114
|
return dispose;
|
|
69
115
|
}
|
|
70
116
|
// Poll `predicate` until it holds or `timeoutMs` elapses, then return either
|
|
@@ -100,7 +146,7 @@ test('coalesce renders one inbox card whose entries inline short report bodies a
|
|
|
100
146
|
mkdirSync(reportsDir(child.node_id), { recursive: true });
|
|
101
147
|
writeFileSync(reportPath, '---\nnode: child\nkind: update\n---\nshort report body', 'utf8');
|
|
102
148
|
const digest = onlyDelivery(coalesce([
|
|
103
|
-
|
|
149
|
+
claimedMail('child', { from: 'child', tier: 'normal', kind: 'update', label: 'short report', ref: 'child:reports/short-update.md' }),
|
|
104
150
|
]));
|
|
105
151
|
// The envelope is the whole message: a reader that finds it anywhere else
|
|
106
152
|
// attributes the digest to the person.
|
|
@@ -121,7 +167,7 @@ test('coalesce renders one inbox card whose entries inline short report bodies a
|
|
|
121
167
|
const canonical = parseCard({
|
|
122
168
|
role: 'user',
|
|
123
169
|
content: onlyDelivery(coalesce([
|
|
124
|
-
|
|
170
|
+
claimedMail('child', { from: 'child', tier: 'normal', kind: 'final', label: 'done', ref: 'child:reports/final.md' }),
|
|
125
171
|
])),
|
|
126
172
|
});
|
|
127
173
|
assert.deepEqual(canonical.senders[0].entries, [
|
|
@@ -131,7 +177,7 @@ test('coalesce renders one inbox card whose entries inline short report bodies a
|
|
|
131
177
|
const spilled = parseCard({
|
|
132
178
|
role: 'user',
|
|
133
179
|
content: onlyDelivery(coalesce([
|
|
134
|
-
|
|
180
|
+
claimedMail('child', { from: 'child', tier: 'normal', kind: 'message', label: 'long', ref: '/tmp/message.md', data: { body: 'long body' } }),
|
|
135
181
|
])),
|
|
136
182
|
});
|
|
137
183
|
assert.deepEqual(spilled.senders[0].entries, [
|
|
@@ -143,13 +189,14 @@ test('a human message coalesces verbatim — a conversation turn, not a digest',
|
|
|
143
189
|
// A human typing directly into a node's box is a CONVERSATION TURN, so the
|
|
144
190
|
// dormant wake path must read identically to the live path: no card, no
|
|
145
191
|
// `<from>` section. Every other sender is digest content.
|
|
192
|
+
freshNode('human');
|
|
146
193
|
const body = 'first line\n\nsecond paragraph';
|
|
147
194
|
const human = onlyDelivery(coalesce([
|
|
148
|
-
|
|
195
|
+
claimedMail('human', { from: 'human', tier: 'normal', kind: 'message', label: 'first line', data: { body } }),
|
|
149
196
|
]));
|
|
150
197
|
assert.equal(human, body);
|
|
151
198
|
const agent = onlyDelivery(coalesce([
|
|
152
|
-
|
|
199
|
+
claimedMail('agent', { from: 'mqifzplr-0753bde3', tier: 'normal', kind: 'message', label: 'go', data: { body: 'go' } }),
|
|
153
200
|
]));
|
|
154
201
|
assert.equal(agent.startsWith('<runtime kind="inbox"'), true);
|
|
155
202
|
assert.match(agent, /<from id="mqifzplr-0753bde3">/);
|
|
@@ -157,8 +204,9 @@ test('a human message coalesces verbatim — a conversation turn, not a digest',
|
|
|
157
204
|
test('a mixed batch splits: human words verbatim, node reports in one card, order preserved', () => {
|
|
158
205
|
// Concatenating the two into one message left `parseCard` unable to see the
|
|
159
206
|
// envelope, so the whole delivery read as the person's words.
|
|
160
|
-
|
|
161
|
-
const
|
|
207
|
+
freshNode('mixed');
|
|
208
|
+
const humanEntry = (body) => claimedMail('mixed-human', { from: 'human', tier: 'normal', kind: 'message', label: body, data: { body } });
|
|
209
|
+
const nodeEntry = (from, body) => claimedMail('mixed-node', { from, tier: 'normal', kind: 'update', label: body, data: { body } });
|
|
162
210
|
for (const [name, entries] of [
|
|
163
211
|
['human first', [humanEntry('do the thing'), nodeEntry('mqifzplr-0753bde3', 'phase one done')]],
|
|
164
212
|
['node first', [nodeEntry('mqifzplr-0753bde3', 'phase one done'), humanEntry('do the thing')]],
|
|
@@ -182,14 +230,18 @@ let origDebounce;
|
|
|
182
230
|
before(() => {
|
|
183
231
|
origHome = process.env['CRTR_HOME'];
|
|
184
232
|
origNode = process.env['CRTR_NODE_ID'];
|
|
233
|
+
origExecution = process.env['CRTR_EXECUTION_ID'];
|
|
185
234
|
origTick = process.env['CRTR_WATCHER_TICK_MS'];
|
|
186
235
|
origDebounce = process.env['CRTR_WATCHER_DEBOUNCE_MS'];
|
|
187
236
|
process.env['CRTR_WATCHER_TICK_MS'] = String(TICK_MS);
|
|
188
237
|
process.env['CRTR_WATCHER_DEBOUNCE_MS'] = String(DEBOUNCE_MS);
|
|
189
238
|
});
|
|
190
|
-
afterEach(() => {
|
|
239
|
+
afterEach(async () => {
|
|
191
240
|
while (disposers.length > 0)
|
|
192
241
|
disposers.pop()();
|
|
242
|
+
await server?.close();
|
|
243
|
+
server = undefined;
|
|
244
|
+
closeDb();
|
|
193
245
|
});
|
|
194
246
|
after(() => {
|
|
195
247
|
if (origHome === undefined)
|
|
@@ -200,6 +252,10 @@ after(() => {
|
|
|
200
252
|
delete process.env['CRTR_NODE_ID'];
|
|
201
253
|
else
|
|
202
254
|
process.env['CRTR_NODE_ID'] = origNode;
|
|
255
|
+
if (origExecution === undefined)
|
|
256
|
+
delete process.env['CRTR_EXECUTION_ID'];
|
|
257
|
+
else
|
|
258
|
+
process.env['CRTR_EXECUTION_ID'] = origExecution;
|
|
203
259
|
if (origTick === undefined)
|
|
204
260
|
delete process.env['CRTR_WATCHER_TICK_MS'];
|
|
205
261
|
else
|
|
@@ -223,7 +279,7 @@ describe('canvas inbox watcher — finished-node delivery', () => {
|
|
|
223
279
|
// Subscriber is actively streaming when the worker finishes.
|
|
224
280
|
pi.fire('agent_start', { type: 'agent_start' }, { isIdle: () => false });
|
|
225
281
|
await wait(TICK_MS + 100);
|
|
226
|
-
|
|
282
|
+
publishMail('node-final', { from: 'child-1', tier: 'normal', kind: 'final', label: 'all done' });
|
|
227
283
|
await waitFor(() => pi.injected.length >= 1);
|
|
228
284
|
assert.equal(pi.injected.length, 1, 'one coalesced injection');
|
|
229
285
|
assert.equal(pi.injected[0].deliverAs, 'steer', 'a finished node steers, not follows up');
|
|
@@ -233,8 +289,8 @@ describe('canvas inbox watcher — finished-node delivery', () => {
|
|
|
233
289
|
const pi = makeFakePi();
|
|
234
290
|
disposers.push(registerWatcher(pi));
|
|
235
291
|
await wait(TICK_MS + 100);
|
|
236
|
-
|
|
237
|
-
|
|
292
|
+
publishMail('node-mixed', { from: 'human', tier: 'normal', kind: 'message', label: 'do the thing', data: { body: 'do the thing' } });
|
|
293
|
+
publishMail('node-mixed', { from: 'child-9', tier: 'normal', kind: 'update', label: 'phase one done' });
|
|
238
294
|
// One visible send per cycle, so the second part lands a tick later.
|
|
239
295
|
await waitFor(() => pi.injected.length >= 2);
|
|
240
296
|
assert.equal(pi.injected.length, 2, 'the batch split into two visible messages');
|
|
@@ -250,7 +306,7 @@ describe('canvas inbox watcher — finished-node delivery', () => {
|
|
|
250
306
|
disposers.push(registerWatcher(pi));
|
|
251
307
|
pi.fire('agent_start', { type: 'agent_start' }, { isIdle: () => false });
|
|
252
308
|
await wait(TICK_MS + 100);
|
|
253
|
-
|
|
309
|
+
publishMail('node-update', { from: 'child-2', tier: 'normal', kind: 'update', label: 'still working' });
|
|
254
310
|
await waitFor(() => pi.injected.length >= 1);
|
|
255
311
|
assert.equal(pi.injected.length, 1);
|
|
256
312
|
assert.equal(pi.injected[0].deliverAs, 'followUp', 'a normal update is not urgent → followUp');
|
|
@@ -262,7 +318,7 @@ describe('canvas inbox watcher — hidden situational-context delivery', () => {
|
|
|
262
318
|
appendSituationalContext('node-situational-only', 'the user is mid-checkout on the store applet');
|
|
263
319
|
const pi = makeFakePi();
|
|
264
320
|
disposers.push(registerWatcher(pi));
|
|
265
|
-
|
|
321
|
+
publishMail('node-situational-only', {
|
|
266
322
|
from: null,
|
|
267
323
|
tier: 'normal',
|
|
268
324
|
kind: 'message',
|
|
@@ -288,7 +344,7 @@ describe('canvas inbox watcher — hidden situational-context delivery', () => {
|
|
|
288
344
|
appendSituationalContext('node-situational-combined', 'the hidden ambient checkout state');
|
|
289
345
|
const pi = makeFakePi();
|
|
290
346
|
disposers.push(registerWatcher(pi));
|
|
291
|
-
|
|
347
|
+
publishMail('node-situational-combined', {
|
|
292
348
|
from: 'child-3',
|
|
293
349
|
tier: 'normal',
|
|
294
350
|
kind: 'message',
|
|
@@ -323,7 +379,7 @@ describe('canvas inbox watcher — hidden situational-context delivery', () => {
|
|
|
323
379
|
realSendMessage(message, options);
|
|
324
380
|
};
|
|
325
381
|
disposers.push(registerWatcher(pi));
|
|
326
|
-
|
|
382
|
+
publishMail('node-situational-retry', {
|
|
327
383
|
from: null,
|
|
328
384
|
tier: 'normal',
|
|
329
385
|
kind: 'message',
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { test, before, after, beforeEach } from 'node:test';
|
|
2
2
|
import assert from 'node:assert/strict';
|
|
3
|
-
import { mkdtempSync, rmSync, existsSync,
|
|
3
|
+
import { mkdtempSync, rmSync, existsSync, writeFileSync } from 'node:fs';
|
|
4
4
|
import { tmpdir } from 'node:os';
|
|
5
5
|
import { join } from 'node:path';
|
|
6
|
-
import { createNode, getNode, getRow, updateNode, setStatus, subscribe, unsubscribe, setSubscriptionActive, recordSpawn, subscribersOf, subscriptionsOf, view, hasActiveLiveSubscription,
|
|
7
|
-
import { closeDb } from '../canvas/db.js';
|
|
6
|
+
import { createNode, getNode, getRow, updateNode, setStatus, subscribe, unsubscribe, setSubscriptionActive, recordSpawn, subscribersOf, subscriptionsOf, view, hasActiveLiveSubscription, } from '../canvas/canvas.js';
|
|
7
|
+
import { closeDb, migrate, openDb } from '../canvas/db.js';
|
|
8
8
|
import { nodeMetaPath } from '../canvas/paths.js';
|
|
9
9
|
let home;
|
|
10
10
|
function node(id, over = {}) {
|
|
@@ -28,25 +28,22 @@ beforeEach(() => {
|
|
|
28
28
|
// Fresh db + dirs per test for isolation.
|
|
29
29
|
closeDb();
|
|
30
30
|
rmSync(home, { recursive: true, force: true });
|
|
31
|
+
migrate(openDb());
|
|
31
32
|
});
|
|
32
33
|
after(() => {
|
|
33
34
|
closeDb();
|
|
34
35
|
rmSync(home, { recursive: true, force: true });
|
|
35
36
|
delete process.env['CRTR_HOME'];
|
|
36
37
|
});
|
|
37
|
-
test('
|
|
38
|
+
test('SQL is the source of truth; a node directory contains artifacts only', () => {
|
|
38
39
|
createNode(node('a', { kind: 'developer' }));
|
|
39
|
-
|
|
40
|
-
assert.equal(
|
|
40
|
+
assert.equal(getNode('a')?.kind, 'developer');
|
|
41
|
+
assert.equal(existsSync(nodeMetaPath('a')), false, 'creating a node does not write a metadata authority file');
|
|
41
42
|
});
|
|
42
|
-
//
|
|
43
|
-
// column — like pi_session_file) written by reviveNode/canvas-stophook and
|
|
44
|
-
// read back by reviveNode's locked launch arbitration. writeMeta only persists
|
|
45
|
-
// keys listed in IDENTITY_KEYS; if cycle_pending is missing from that whitelist,
|
|
46
|
-
// updateNode silently drops it and a competing caller can request strict resume.
|
|
43
|
+
// cycle_pending is stored on the node row and read by revive launch arbitration.
|
|
47
44
|
test('cycle_pending survives the updateNode/getNode meta.json round-trip', () => {
|
|
48
45
|
createNode(node('a'));
|
|
49
|
-
assert.equal(getNode('a')?.cycle_pending,
|
|
46
|
+
assert.equal(getNode('a')?.cycle_pending, false); // SQL default
|
|
50
47
|
updateNode('a', { cycle_pending: true });
|
|
51
48
|
assert.equal(getNode('a')?.cycle_pending, true);
|
|
52
49
|
updateNode('a', { cycle_pending: false });
|
|
@@ -118,50 +115,24 @@ test('recordSpawn writes the audit-only spawned_by edge', () => {
|
|
|
118
115
|
assert.equal(subscriptionsOf('child').length, 0);
|
|
119
116
|
assert.equal(subscribersOf('parent').length, 0);
|
|
120
117
|
});
|
|
121
|
-
|
|
122
|
-
// writeMeta uses atomic rename with fsync on both the temp file and parent
|
|
123
|
-
// directory to ensure atomicity and durability. readMeta/rebuildIndex tolerate
|
|
124
|
-
// an empty/corrupt meta.json as MISSING (returning null) rather than throwing,
|
|
125
|
-
// gracefully handling rare disk/NFS anomalies without breaking recovery.
|
|
126
|
-
test('writeMeta produces a durable, non-empty, atomically-named meta.json', () => {
|
|
118
|
+
test('artifact metadata does not alter a SQL node', () => {
|
|
127
119
|
createNode(node('a'));
|
|
128
|
-
|
|
129
|
-
assert.
|
|
130
|
-
assert.ok(!existsSync(`${p}.tmp`), 'temp file must be renamed away, not left behind');
|
|
131
|
-
assert.equal(getNode('a')?.node_id, 'a');
|
|
132
|
-
});
|
|
133
|
-
test('getNode returns null (not throw) on a 0-byte meta.json', () => {
|
|
134
|
-
createNode(node('a'));
|
|
135
|
-
writeFileSync(nodeMetaPath('a'), ''); // the observed NFS 0-byte corruption
|
|
136
|
-
assert.equal(getNode('a'), null);
|
|
120
|
+
writeFileSync(nodeMetaPath('a'), JSON.stringify({ node_id: 'a', kind: 'other' }));
|
|
121
|
+
assert.equal(getNode('a')?.kind, 'general');
|
|
137
122
|
});
|
|
138
|
-
test('
|
|
123
|
+
test('corrupt artifact metadata does not make a SQL node unreadable', () => {
|
|
139
124
|
createNode(node('a'));
|
|
140
125
|
writeFileSync(nodeMetaPath('a'), '{ broken json');
|
|
141
|
-
assert.equal(getNode('a'),
|
|
142
|
-
});
|
|
143
|
-
test('rebuildIndex skips a corrupt-meta node instead of throwing', () => {
|
|
144
|
-
createNode(node('good'));
|
|
145
|
-
createNode(node('bad'));
|
|
146
|
-
writeFileSync(nodeMetaPath('bad'), ''); // 0-byte corruption on one node
|
|
147
|
-
closeDb();
|
|
148
|
-
rmSync(join(home, 'canvas.db'), { force: true });
|
|
149
|
-
rmSync(join(home, 'canvas.db-wal'), { force: true });
|
|
150
|
-
rmSync(join(home, 'canvas.db-shm'), { force: true });
|
|
151
|
-
assert.doesNotThrow(() => rebuildIndex());
|
|
152
|
-
assert.equal(getRow('good')?.node_id, 'good'); // healthy node reindexed
|
|
153
|
-
assert.equal(getRow('bad'), null); // corrupt node skipped, no crash
|
|
126
|
+
assert.equal(getNode('a')?.node_id, 'a');
|
|
154
127
|
});
|
|
155
|
-
test('
|
|
128
|
+
test('deleting the database does not rebuild nodes from artifact directories', () => {
|
|
156
129
|
createNode(node('a', { parent: null }));
|
|
157
130
|
createNode(node('b', { parent: 'a' }));
|
|
158
|
-
// wipe just the db, keep the node dirs
|
|
159
131
|
closeDb();
|
|
160
132
|
rmSync(join(home, 'canvas.db'), { force: true });
|
|
161
133
|
rmSync(join(home, 'canvas.db-wal'), { force: true });
|
|
162
134
|
rmSync(join(home, 'canvas.db-shm'), { force: true });
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
assert.equal(getRow('
|
|
166
|
-
assert.equal(getRow('b')?.parent, 'a');
|
|
135
|
+
migrate(openDb());
|
|
136
|
+
assert.equal(getRow('a'), null);
|
|
137
|
+
assert.equal(getRow('b'), null);
|
|
167
138
|
});
|
|
@@ -6,14 +6,18 @@ import { tmpdir } from 'node:os';
|
|
|
6
6
|
import { join } from 'node:path';
|
|
7
7
|
import { spawnSync } from 'node:child_process';
|
|
8
8
|
import { createNode, getNode, subscribe } from '../canvas/canvas.js';
|
|
9
|
-
import { closeDb } from '../canvas/db.js';
|
|
10
|
-
import {
|
|
9
|
+
import { closeDb, openDb, migrate } from '../canvas/db.js';
|
|
10
|
+
import { beginExecution, recordExecutionPid } from '../canvas/executions.js';
|
|
11
|
+
import { bindSession } from '../canvas/sessions.js';
|
|
12
|
+
import { ensureScopeInitialized } from '../config.js';
|
|
13
|
+
import { closeScopedStores } from '../scoped-state/db.js';
|
|
11
14
|
import { closeNode } from '../runtime/close.js';
|
|
12
15
|
import { superviseTick } from '../../daemon/crtrd.js';
|
|
13
16
|
import { bindTestFleet } from './helpers/fleet.js';
|
|
14
17
|
import { resetFleetForTests } from '../runtime/fleet.js';
|
|
15
18
|
import { headlessBrokerHost } from '../runtime/host.js';
|
|
16
19
|
let home;
|
|
20
|
+
let priorUserHome;
|
|
17
21
|
let tf;
|
|
18
22
|
function node(id, over = {}) {
|
|
19
23
|
return {
|
|
@@ -55,21 +59,30 @@ function deadEngineChild(id, over = {}) {
|
|
|
55
59
|
pane: GONE_PANE,
|
|
56
60
|
tmux_session: 'crtr-cdw',
|
|
57
61
|
window: '@1',
|
|
58
|
-
pi_pid: deadPid(),
|
|
59
|
-
pi_session_id: 'booted',
|
|
60
62
|
intent: null,
|
|
61
63
|
status: 'active',
|
|
62
64
|
...over,
|
|
63
65
|
}));
|
|
66
|
+
const executionId = beginExecution(id, { daemonEpoch: 'test' });
|
|
67
|
+
assert.equal(bindSession(id, { executionId, sessionId: 'booted', transcriptPath: withSession(id) }), 'bound');
|
|
68
|
+
assert.equal(recordExecutionPid(executionId, id, deadPid()), 'recorded');
|
|
64
69
|
}
|
|
65
70
|
/** A dormant inbox-waiting PARENT — only ever the wake TARGET, asserted via its
|
|
66
71
|
* inbox. */
|
|
67
72
|
function inboxWaitingParent(id) {
|
|
68
73
|
createNode(node(id, { status: 'active' }));
|
|
69
74
|
}
|
|
70
|
-
|
|
75
|
+
function nodeMail(nodeId) {
|
|
76
|
+
return openDb().prepare(`SELECT m.sender_node_id AS "from", m.label
|
|
77
|
+
FROM deliveries d JOIN messages m ON m.message_id = d.message_id
|
|
78
|
+
WHERE d.destination_kind = 'node_inbox' AND d.destination_id = ?
|
|
79
|
+
ORDER BY m.seq`).all(nodeId);
|
|
80
|
+
}
|
|
81
|
+
const wakeFromChild = (parent, child) => nodeMail(parent).find((entry) => entry.from === child);
|
|
71
82
|
before(() => {
|
|
72
83
|
home = mkdtempSync(join(tmpdir(), 'crtr-child-death-wake-'));
|
|
84
|
+
priorUserHome = process.env['HOME'];
|
|
85
|
+
process.env['HOME'] = home;
|
|
73
86
|
process.env['CRTR_HOME'] = home;
|
|
74
87
|
// superviseTick requires a bound fleet (D-2). It starts empty: none of these
|
|
75
88
|
// fabricated rows has a live broker.
|
|
@@ -78,11 +91,18 @@ before(() => {
|
|
|
78
91
|
beforeEach(() => {
|
|
79
92
|
closeDb();
|
|
80
93
|
rmSync(home, { recursive: true, force: true });
|
|
94
|
+
ensureScopeInitialized('user', join(home, '.crouter'));
|
|
95
|
+
migrate(openDb());
|
|
81
96
|
});
|
|
82
97
|
after(() => {
|
|
83
98
|
closeDb();
|
|
99
|
+
closeScopedStores();
|
|
84
100
|
rmSync(home, { recursive: true, force: true });
|
|
85
101
|
delete process.env['CRTR_HOME'];
|
|
102
|
+
if (priorUserHome === undefined)
|
|
103
|
+
delete process.env['HOME'];
|
|
104
|
+
else
|
|
105
|
+
process.env['HOME'] = priorUserHome;
|
|
86
106
|
resetFleetForTests();
|
|
87
107
|
});
|
|
88
108
|
test('a dead-engine booted child enters durable backoff before recovery, is NOT reaped, and fans NO wake to its dormant parent', async () => {
|
|
@@ -108,7 +128,7 @@ test('a dead-engine booted child enters durable backoff before recovery, is NOT
|
|
|
108
128
|
// the row is relaunched on its saved session, never reaped to dead/done/idle.
|
|
109
129
|
assert.deepEqual(launches, ['CHILD'], 'the matured tick recovers the dead engine through the policy table');
|
|
110
130
|
assert.equal(getNode('CHILD').status, 'active', 'CHILD is recovered, NOT reaped');
|
|
111
|
-
assert.equal(
|
|
131
|
+
assert.equal(nodeMail('PARENT').length, 0, 'PARENT has no delivery from daemon liveness');
|
|
112
132
|
}
|
|
113
133
|
finally {
|
|
114
134
|
headlessBrokerHost.launch = originalLaunch;
|
|
@@ -118,7 +138,9 @@ test('a dead-engine booted child enters durable backoff before recovery, is NOT
|
|
|
118
138
|
test('node close of a child wakes its SURVIVING manager (the parent outside the closing set)', async () => {
|
|
119
139
|
inboxWaitingParent('PARENT');
|
|
120
140
|
// A booted child; closeNode tears its (paneless-for-the-test) engine down.
|
|
121
|
-
createNode(node('CHILD', { pane: GONE_PANE, tmux_session: 'crtr-cdw', window: '@1',
|
|
141
|
+
createNode(node('CHILD', { pane: GONE_PANE, tmux_session: 'crtr-cdw', window: '@1', status: 'active' }));
|
|
142
|
+
const executionId = beginExecution('CHILD', { daemonEpoch: 'test' });
|
|
143
|
+
assert.equal(bindSession('CHILD', { executionId, sessionId: 'booted', transcriptPath: withSession('CHILD') }), 'bound');
|
|
122
144
|
subscribe('PARENT', 'CHILD', true); // PARENT is a manager OUTSIDE the close set
|
|
123
145
|
// Closing CHILD: closingSet({CHILD}) cannot pull in PARENT (PARENT is a
|
|
124
146
|
// SUBSCRIBER of CHILD, never a descendant), so PARENT survives + must wake.
|
|
@@ -14,6 +14,7 @@ import { mkdtempSync, rmSync } from 'node:fs';
|
|
|
14
14
|
import { tmpdir } from 'node:os';
|
|
15
15
|
import { join } from 'node:path';
|
|
16
16
|
import { buildRoot } from '../../build-root.js';
|
|
17
|
+
import { ensureScopeInitialized } from '../config.js';
|
|
17
18
|
import { resetScopeCache } from '../scope.js';
|
|
18
19
|
// buildRoot() composes external command-plugin branches from the effective
|
|
19
20
|
// enabled plugins. Pin HOME to an isolated no-plugin home: a third party's
|
|
@@ -28,6 +29,7 @@ before(() => {
|
|
|
28
29
|
delete process.env['CRTR_PROFILE_ID'];
|
|
29
30
|
process.env['HOME'] = home;
|
|
30
31
|
resetScopeCache();
|
|
32
|
+
ensureScopeInitialized('user', join(home, '.crouter'));
|
|
31
33
|
});
|
|
32
34
|
after(() => {
|
|
33
35
|
if (realHome !== undefined)
|