@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
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { after, afterEach, before, beforeEach, test } from 'node:test';
|
|
2
2
|
import assert from 'node:assert/strict';
|
|
3
|
-
import { mkdtempSync, mkdirSync,
|
|
3
|
+
import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from 'node:fs';
|
|
4
4
|
import { tmpdir } from 'node:os';
|
|
5
5
|
import { join } from 'node:path';
|
|
6
|
-
import { persistModelRoute, readConfig, readMergedLaunchConfig } from '../config.js';
|
|
6
|
+
import { persistModelRoute, readConfig, readMergedLaunchConfig, readRawConfigAtRoot, writeRawConfig } from '../config.js';
|
|
7
|
+
import { initializeFreshScopedStore } from '../scoped-state/migrate.js';
|
|
7
8
|
import { expandModelCandidates } from '../model-routes.js';
|
|
9
|
+
import { piAgentDir } from '../runtime/package-health.js';
|
|
8
10
|
import { resetScopeCache } from '../scope.js';
|
|
9
11
|
let home;
|
|
10
12
|
let work;
|
|
@@ -23,6 +25,10 @@ function route(providerId = 'provider-x', family = 'family-x', credentialSource
|
|
|
23
25
|
};
|
|
24
26
|
}
|
|
25
27
|
function writeConfig(root, config) {
|
|
28
|
+
if (root === join(home, '.crouter')) {
|
|
29
|
+
writeRawConfig('user', config);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
26
32
|
mkdirSync(root, { recursive: true });
|
|
27
33
|
writeFileSync(join(root, 'config.json'), JSON.stringify(config));
|
|
28
34
|
}
|
|
@@ -34,6 +40,8 @@ beforeEach(() => {
|
|
|
34
40
|
work = mkdtempSync(join(tmpdir(), 'crtr-model-routes-work-'));
|
|
35
41
|
process.env.HOME = home;
|
|
36
42
|
resetScopeCache();
|
|
43
|
+
initializeFreshScopedStore({ kind: 'user', root: join(home, '.crouter') });
|
|
44
|
+
initializeFreshScopedStore({ kind: 'provider', root: piAgentDir() });
|
|
37
45
|
});
|
|
38
46
|
afterEach(() => {
|
|
39
47
|
resetScopeCache();
|
|
@@ -87,7 +95,7 @@ test('route records retain __proto__ ids when read and persisted', () => {
|
|
|
87
95
|
writeConfig(root, JSON.parse(JSON.stringify({ modelRoutes: { ['__proto__']: route() } })));
|
|
88
96
|
assert.deepEqual(readMergedLaunchConfig(work, null).modelRoutes?.['__proto__'], route());
|
|
89
97
|
persistModelRoute(root, '__proto__', route('persisted-provider'));
|
|
90
|
-
const raw =
|
|
98
|
+
const raw = readRawConfigAtRoot(root);
|
|
91
99
|
assert.deepEqual(raw.modelRoutes['__proto__'], route('persisted-provider'));
|
|
92
100
|
});
|
|
93
101
|
test('route candidate identity distinguishes delimiter-containing route and provider ids', () => {
|
|
@@ -131,12 +139,12 @@ test('persistModelRoute touches only its raw route and deletes by restoring inhe
|
|
|
131
139
|
const other = route('other-provider');
|
|
132
140
|
writeConfig(root, { modelRoutes: { other }, max_panes_per_window: 7 });
|
|
133
141
|
persistModelRoute(root, 'edited', route('edited-provider'));
|
|
134
|
-
let raw =
|
|
142
|
+
let raw = readRawConfigAtRoot(root);
|
|
135
143
|
assert.deepEqual(raw.modelRoutes.other, other);
|
|
136
144
|
assert.deepEqual(raw.modelRoutes.edited, route('edited-provider'));
|
|
137
145
|
assert.equal(raw.modelLadders, undefined);
|
|
138
146
|
assert.equal(raw.max_panes_per_window, 7);
|
|
139
147
|
persistModelRoute(root, 'edited', undefined);
|
|
140
|
-
raw =
|
|
148
|
+
raw = readRawConfigAtRoot(root);
|
|
141
149
|
assert.deepEqual(raw.modelRoutes, { other });
|
|
142
150
|
});
|
|
@@ -4,15 +4,80 @@ import { DatabaseSync } from 'node:sqlite';
|
|
|
4
4
|
import { mkdirSync, mkdtempSync, rmSync } from 'node:fs';
|
|
5
5
|
import { tmpdir } from 'node:os';
|
|
6
6
|
import { join } from 'node:path';
|
|
7
|
-
import { closeDb, MIGRATIONS } from '../canvas/db.js';
|
|
8
|
-
import { createNode, getRow } from '../canvas/canvas.js';
|
|
9
|
-
import {
|
|
7
|
+
import { closeDb, MIGRATIONS, migrate, openDb, withCanvasWrite } from '../canvas/db.js';
|
|
8
|
+
import { createNode, getNode, getRow } from '../canvas/canvas.js';
|
|
9
|
+
import { activateArmedExternalActionDelivery, armExternalActionDelivery, claimExternalActionDelivery, messageBodyForDelivery, readExternalActionDelivery, resetHandedOffDeliveries, settleDelivery, } from '../canvas/deliveries.js';
|
|
10
10
|
import { transition } from '../runtime/lifecycle.js';
|
|
11
11
|
import { composeNodeOutcomeDocument } from '../runtime/outcome-document.js';
|
|
12
12
|
import { pushFinal } from '../feed/feed.js';
|
|
13
13
|
import { OUTCOME_PAYLOAD_MAX_BYTES } from '../canvas/types.js';
|
|
14
14
|
let home;
|
|
15
15
|
const priorHome = process.env['CRTR_HOME'];
|
|
16
|
+
function outcomeKey(nodeId) {
|
|
17
|
+
return `node-outcome:${nodeId}`;
|
|
18
|
+
}
|
|
19
|
+
function outcomeDelivery(nodeId) {
|
|
20
|
+
return readExternalActionDelivery(outcomeKey(nodeId));
|
|
21
|
+
}
|
|
22
|
+
function nodeAtOutcome(node) {
|
|
23
|
+
const reason = node.outcome_reason;
|
|
24
|
+
let status;
|
|
25
|
+
let intent;
|
|
26
|
+
if (node.outcome_kind === 'result' || reason === 'finished' || reason === 'declined') {
|
|
27
|
+
status = 'done';
|
|
28
|
+
intent = 'done';
|
|
29
|
+
}
|
|
30
|
+
else if (reason === 'parked') {
|
|
31
|
+
status = 'done';
|
|
32
|
+
intent = 'parked';
|
|
33
|
+
}
|
|
34
|
+
else if (reason === 'closed' || reason === 'retired' || reason === 'stranded' || reason === 'deadline_exceeded') {
|
|
35
|
+
status = 'canceled';
|
|
36
|
+
intent = null;
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
status = 'dead';
|
|
40
|
+
intent = null;
|
|
41
|
+
}
|
|
42
|
+
return { ...node, status, intent, terminal_reason: reason };
|
|
43
|
+
}
|
|
44
|
+
function armOutcomeAction(input) {
|
|
45
|
+
const payload = input.payload ?? null;
|
|
46
|
+
const json = JSON.stringify(payload);
|
|
47
|
+
if (json === undefined)
|
|
48
|
+
throw new TypeError('outcome delivery payload must be JSON-serializable');
|
|
49
|
+
if (Buffer.byteLength(json, 'utf8') > OUTCOME_PAYLOAD_MAX_BYTES)
|
|
50
|
+
throw new RangeError(`outcome delivery payload exceeds ${OUTCOME_PAYLOAD_MAX_BYTES} bytes`);
|
|
51
|
+
return withCanvasWrite((db) => {
|
|
52
|
+
const existing = outcomeDelivery(input.nodeId);
|
|
53
|
+
if (existing !== null && existing.state !== 'armed')
|
|
54
|
+
return null;
|
|
55
|
+
armExternalActionDelivery(db, {
|
|
56
|
+
destinationId: input.actionName,
|
|
57
|
+
adapter: { adapter: 'subprocess', argv: input.argv, cwd: input.cwd, config_origin: input.configOrigin, payload },
|
|
58
|
+
idempotencyKey: outcomeKey(input.nodeId),
|
|
59
|
+
}, input.now);
|
|
60
|
+
const node = getNode(input.nodeId);
|
|
61
|
+
if (node === null)
|
|
62
|
+
throw new Error(`unknown node ${input.nodeId}`);
|
|
63
|
+
if (node.outcome_at !== null) {
|
|
64
|
+
if (node.outcome_kind === null || node.outcome_reason === null)
|
|
65
|
+
throw new Error(`outcome latch is incomplete for node ${input.nodeId}`);
|
|
66
|
+
activateArmedExternalActionDelivery(db, {
|
|
67
|
+
idempotencyKey: outcomeKey(input.nodeId),
|
|
68
|
+
label: input.nodeId,
|
|
69
|
+
bodyJson: JSON.stringify(composeNodeOutcomeDocument({
|
|
70
|
+
node: nodeAtOutcome(node),
|
|
71
|
+
outcome: { kind: node.outcome_kind, reason: node.outcome_reason, at: node.outcome_at, revision: node.outcome_revision, detailJson: node.outcome_detail_json ?? null },
|
|
72
|
+
action: { name: input.actionName, payload },
|
|
73
|
+
finalReport: node.final_report,
|
|
74
|
+
})),
|
|
75
|
+
supersede: false,
|
|
76
|
+
}, input.now);
|
|
77
|
+
}
|
|
78
|
+
return outcomeDelivery(input.nodeId);
|
|
79
|
+
});
|
|
80
|
+
}
|
|
16
81
|
function node(nodeId) {
|
|
17
82
|
return {
|
|
18
83
|
node_id: nodeId,
|
|
@@ -29,6 +94,7 @@ beforeEach(() => {
|
|
|
29
94
|
closeDb();
|
|
30
95
|
home = mkdtempSync(join(tmpdir(), 'crtr-node-outcome-'));
|
|
31
96
|
process.env['CRTR_HOME'] = home;
|
|
97
|
+
migrate(openDb());
|
|
32
98
|
});
|
|
33
99
|
afterEach(() => {
|
|
34
100
|
closeDb();
|
|
@@ -105,23 +171,24 @@ test('a canonical final supersedes a prior failure outcome and increments revisi
|
|
|
105
171
|
});
|
|
106
172
|
test('outcome delivery rejects an oversized payload before a node is armed', () => {
|
|
107
173
|
createNode(node('oversized-payload'));
|
|
108
|
-
assert.throws(() =>
|
|
174
|
+
assert.throws(() => armOutcomeAction({
|
|
109
175
|
nodeId: 'oversized-payload', actionName: 'test-action', argv: ['/bin/true'], cwd: home, configOrigin: 'test', payload: { value: 'x'.repeat(OUTCOME_PAYLOAD_MAX_BYTES) },
|
|
110
176
|
}), /exceeds/);
|
|
111
|
-
assert.equal(
|
|
177
|
+
assert.equal(outcomeDelivery('oversized-payload'), null);
|
|
112
178
|
});
|
|
113
179
|
test('outcome delivery armed after settlement is born pending with its document', () => {
|
|
114
180
|
createNode(node('settled-delivery'));
|
|
115
181
|
transition('settled-delivery', 'crash');
|
|
116
|
-
const delivery =
|
|
182
|
+
const delivery = armOutcomeAction({
|
|
117
183
|
nodeId: 'settled-delivery', actionName: 'test-action', argv: ['/bin/true'], cwd: home, configOrigin: 'test', payload: { callback: 'one' }, now: 123,
|
|
118
184
|
});
|
|
119
185
|
assert.equal(delivery?.state, 'pending');
|
|
120
186
|
assert.equal(delivery?.nextAttemptAt, 123);
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
187
|
+
const document = delivery === null ? null : messageBodyForDelivery(delivery.deliveryId);
|
|
188
|
+
assert.deepEqual(document && {
|
|
189
|
+
schema: document.schema,
|
|
190
|
+
outcomeId: document.outcomeId,
|
|
191
|
+
action: document.action,
|
|
125
192
|
}, {
|
|
126
193
|
schema: 'crtr.node-outcome/v1',
|
|
127
194
|
outcomeId: 'settled-delivery:1',
|
|
@@ -130,28 +197,28 @@ test('outcome delivery armed after settlement is born pending with its document'
|
|
|
130
197
|
});
|
|
131
198
|
test('outcome delivery state is fenced, recoverable, and follows the durable backoff', () => {
|
|
132
199
|
createNode(node('delivery'));
|
|
133
|
-
assert.ok(
|
|
200
|
+
assert.ok(armOutcomeAction({
|
|
134
201
|
nodeId: 'delivery', actionName: 'test-action', argv: ['/bin/true'], cwd: home, configOrigin: 'test', payload: { callback: 'one' }, now: 100,
|
|
135
202
|
}));
|
|
136
203
|
transition('delivery', 'crash');
|
|
137
|
-
assert.equal(
|
|
138
|
-
assert.ok(
|
|
139
|
-
const first =
|
|
140
|
-
assert.equal(first.state, '
|
|
141
|
-
assert.equal(
|
|
142
|
-
assert.equal(
|
|
143
|
-
assert.equal(
|
|
204
|
+
assert.equal(outcomeDelivery('delivery')?.state, 'pending');
|
|
205
|
+
assert.ok(messageBodyForDelivery(outcomeDelivery('delivery').deliveryId), 'the armed row is stamped with its outcome document');
|
|
206
|
+
const first = claimExternalActionDelivery(outcomeDelivery('delivery').deliveryId, Date.now(), 'daemon-a');
|
|
207
|
+
assert.equal(first.state, 'handed_off');
|
|
208
|
+
assert.equal(settleDelivery(first.deliveryId, first.attempts, 'daemon-b', { state: 'accepted' }, Date.now()), false, 'a stale claimant cannot settle');
|
|
209
|
+
assert.equal(settleDelivery(first.deliveryId, first.attempts, 'daemon-a', { state: 'accepted' }, Date.now()), true);
|
|
210
|
+
assert.equal(outcomeDelivery('delivery')?.state, 'acknowledged');
|
|
144
211
|
createNode(node('recover'));
|
|
145
|
-
|
|
212
|
+
armOutcomeAction({ nodeId: 'recover', actionName: 'test-action', argv: ['/bin/true'], cwd: home, configOrigin: 'test', now: 100 });
|
|
146
213
|
transition('recover', 'crash');
|
|
147
|
-
const running =
|
|
148
|
-
assert.equal(running.state, '
|
|
214
|
+
const running = claimExternalActionDelivery(outcomeDelivery('recover').deliveryId, Date.now(), 'daemon-a');
|
|
215
|
+
assert.equal(running.state, 'handed_off');
|
|
149
216
|
const recoveredAt = Date.now();
|
|
150
|
-
assert.equal(
|
|
151
|
-
assert.deepEqual(
|
|
152
|
-
state:
|
|
153
|
-
nextAttemptAt:
|
|
154
|
-
claimOwner:
|
|
217
|
+
assert.equal(resetHandedOffDeliveries(recoveredAt), 1);
|
|
218
|
+
assert.deepEqual(outcomeDelivery('recover') && {
|
|
219
|
+
state: outcomeDelivery('recover').state,
|
|
220
|
+
nextAttemptAt: outcomeDelivery('recover').nextAttemptAt,
|
|
221
|
+
claimOwner: outcomeDelivery('recover').claimOwner,
|
|
155
222
|
}, { state: 'pending', nextAttemptAt: recoveredAt, claimOwner: null });
|
|
156
223
|
});
|
|
157
224
|
test('v39 migrates a v38 database and backfills finalized and terminal rows', () => {
|
|
@@ -10,7 +10,7 @@ import assert from 'node:assert/strict';
|
|
|
10
10
|
import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from 'node:fs';
|
|
11
11
|
import { tmpdir } from 'node:os';
|
|
12
12
|
import { join } from 'node:path';
|
|
13
|
-
import { closeDb } from '../canvas/db.js';
|
|
13
|
+
import { closeDb, migrate, openDb } from '../canvas/db.js';
|
|
14
14
|
import { resetScopeCache } from '../scope.js';
|
|
15
15
|
import { spawnNode } from '../runtime/nodes.js';
|
|
16
16
|
import { renderOnReadDocs } from '../substrate/on-read-node.js';
|
|
@@ -32,6 +32,7 @@ beforeEach(() => {
|
|
|
32
32
|
// touch the fake user home; the read path we test is constructed by hand.
|
|
33
33
|
canvasHome = mkdtempSync(join(tmpdir(), 'crtr-fence-canvas-'));
|
|
34
34
|
process.env['CRTR_HOME'] = canvasHome;
|
|
35
|
+
migrate(openDb());
|
|
35
36
|
});
|
|
36
37
|
after(() => {
|
|
37
38
|
closeDb();
|
|
@@ -10,7 +10,7 @@ import assert from 'node:assert/strict';
|
|
|
10
10
|
import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from 'node:fs';
|
|
11
11
|
import { tmpdir } from 'node:os';
|
|
12
12
|
import { join } from 'node:path';
|
|
13
|
-
import { closeDb } from '../canvas/db.js';
|
|
13
|
+
import { closeDb, migrate, openDb } from '../canvas/db.js';
|
|
14
14
|
import { resetScopeCache } from '../scope.js';
|
|
15
15
|
import { spawnNode } from '../runtime/nodes.js';
|
|
16
16
|
import { renderOnReadDocs } from '../substrate/on-read-node.js';
|
|
@@ -44,6 +44,7 @@ beforeEach(() => {
|
|
|
44
44
|
else
|
|
45
45
|
process.env['HOME'] = prevHomeEnv;
|
|
46
46
|
work = mkdtempSync(join(tmpdir(), 'crtr-onread-work-'));
|
|
47
|
+
migrate(openDb());
|
|
47
48
|
});
|
|
48
49
|
after(() => {
|
|
49
50
|
closeDb();
|
|
@@ -11,7 +11,7 @@ import assert from 'node:assert/strict';
|
|
|
11
11
|
import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from 'node:fs';
|
|
12
12
|
import { tmpdir } from 'node:os';
|
|
13
13
|
import { join } from 'node:path';
|
|
14
|
-
import { closeDb } from '../canvas/db.js';
|
|
14
|
+
import { closeDb, migrate, openDb } from '../canvas/db.js';
|
|
15
15
|
import { resetScopeCache } from '../scope.js';
|
|
16
16
|
import { spawnNode } from '../runtime/nodes.js';
|
|
17
17
|
import { renderOnReadDocs, renderWorkspaceOpenDocs } from '../substrate/on-read-node.js';
|
|
@@ -36,6 +36,7 @@ beforeEach(() => {
|
|
|
36
36
|
process.env['HOME'] = fakeHome;
|
|
37
37
|
canvasHome = mkdtempSync(join(tmpdir(), 'crtr-nested-canvas-'));
|
|
38
38
|
process.env['CRTR_HOME'] = canvasHome;
|
|
39
|
+
migrate(openDb());
|
|
39
40
|
});
|
|
40
41
|
after(() => {
|
|
41
42
|
closeDb();
|
|
@@ -1,49 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
// 1. A passive subscriber's pushes land in passive.jsonl, NOT inbox.jsonl
|
|
3
|
-
// (so the inbox-watcher never wakes it); an active subscriber's land in
|
|
4
|
-
// inbox.jsonl as before.
|
|
5
|
-
// 2. the broker drain reads + clears the accumulator (surfaces exactly once).
|
|
6
|
-
// 3. canvas-passive-context formats drained entries as timestamped XML and
|
|
7
|
-
// transforms an `input` event into pre-text + the original message.
|
|
8
|
-
//
|
|
9
|
-
// Run: node --import tsx/esm --test src/core/__tests__/passive-subscription.test.ts
|
|
10
|
-
import { test, before, beforeEach, afterEach, after } from 'node:test';
|
|
1
|
+
import { after, before, beforeEach, test } from 'node:test';
|
|
11
2
|
import assert from 'node:assert/strict';
|
|
12
|
-
import { mkdtempSync, mkdirSync, rmSync
|
|
3
|
+
import { mkdtempSync, mkdirSync, rmSync } from 'node:fs';
|
|
13
4
|
import { tmpdir } from 'node:os';
|
|
14
5
|
import { basename, join } from 'node:path';
|
|
15
6
|
import { createNode, subscribe } from '../canvas/canvas.js';
|
|
16
7
|
import { armCron, getCron } from '../canvas/crons.js';
|
|
17
|
-
import { closeDb } from '../canvas/db.js';
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
8
|
+
import { closeDb, migrate, openDb } from '../canvas/db.js';
|
|
9
|
+
import { acknowledgeNodeMail, claimNodeMail, hasUnseenWakeMail } from '../canvas/deliveries.js';
|
|
10
|
+
import { beginExecution } from '../canvas/executions.js';
|
|
20
11
|
import { push } from '../feed/feed.js';
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
23
|
-
import { drainBrokerPassive } from '../runtime/broker/passive.js';
|
|
24
|
-
import { readLeaf } from '../../commands/canvas-history/read.js';
|
|
25
|
-
import registerCanvasPassiveContext from '../../pi-extensions/canvas-passive-context.js';
|
|
12
|
+
import { nodeMailEntry } from '../feed/inbox.js';
|
|
13
|
+
import { formatPassive } from '../../pi-extensions/canvas-passive-context.js';
|
|
26
14
|
let home;
|
|
27
|
-
function readPassiveEntries(nodeId) {
|
|
28
|
-
const path = passivePath(nodeId);
|
|
29
|
-
if (!existsSync(path))
|
|
30
|
-
return [];
|
|
31
|
-
return readFileSync(path, 'utf8').split('\n').filter(Boolean).map((line) => JSON.parse(line));
|
|
32
|
-
}
|
|
33
|
-
// The one test that resolves an emitted feed ref drives `canvas history read`'s
|
|
34
|
-
// leaf (`readLeaf`), a thin CLI forwarder to crtrd since the API re-plumb. Stand
|
|
35
|
-
// up a real in-process `createApiServer()` on the isolated CRTR_HOME's socket so
|
|
36
|
-
// that read resolves through the genuine daemon seam — no autostarted
|
|
37
|
-
// subprocess, no mock client.
|
|
38
|
-
let server;
|
|
39
|
-
async function waitForSocket(path) {
|
|
40
|
-
for (let i = 0; i < 200; i++) {
|
|
41
|
-
if (existsSync(path))
|
|
42
|
-
return;
|
|
43
|
-
await new Promise((r) => setTimeout(r, 25));
|
|
44
|
-
}
|
|
45
|
-
throw new Error(`api socket never bound at ${path}`);
|
|
46
|
-
}
|
|
47
15
|
function node(id, over = {}) {
|
|
48
16
|
return {
|
|
49
17
|
node_id: id,
|
|
@@ -57,53 +25,44 @@ function node(id, over = {}) {
|
|
|
57
25
|
...over,
|
|
58
26
|
};
|
|
59
27
|
}
|
|
28
|
+
function execution(nodeId) {
|
|
29
|
+
return beginExecution(nodeId, { daemonEpoch: 'test' });
|
|
30
|
+
}
|
|
60
31
|
before(() => {
|
|
61
32
|
home = mkdtempSync(join(tmpdir(), 'crtr-passive-'));
|
|
62
33
|
process.env['CRTR_HOME'] = home;
|
|
63
34
|
});
|
|
64
|
-
beforeEach(
|
|
35
|
+
beforeEach(() => {
|
|
65
36
|
closeDb();
|
|
66
37
|
rmSync(home, { recursive: true, force: true });
|
|
67
38
|
mkdirSync(home, { recursive: true });
|
|
68
|
-
|
|
69
|
-
await waitForSocket(apiSocketPath());
|
|
70
|
-
});
|
|
71
|
-
afterEach(async () => {
|
|
72
|
-
await server?.close();
|
|
39
|
+
migrate(openDb());
|
|
73
40
|
});
|
|
74
41
|
after(() => {
|
|
75
42
|
closeDb();
|
|
76
43
|
rmSync(home, { recursive: true, force: true });
|
|
77
44
|
delete process.env['CRTR_HOME'];
|
|
78
|
-
delete process.env['CRTR_NODE_ID'];
|
|
79
45
|
});
|
|
80
|
-
test('passive
|
|
46
|
+
test('a passive subscriber receives a non-waking SQL delivery with the canonical report ref', async () => {
|
|
81
47
|
createNode(node('pub'));
|
|
82
48
|
createNode(node('observer'));
|
|
83
|
-
subscribe('observer', 'pub', false);
|
|
49
|
+
subscribe('observer', 'pub', false);
|
|
84
50
|
const result = await push('pub', { kind: 'update', body: 'first observation\nmore detail' });
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
assert.equal(
|
|
90
|
-
const
|
|
91
|
-
assert.equal(
|
|
92
|
-
assert.equal(
|
|
93
|
-
assert.equal(result.reportPath
|
|
94
|
-
|
|
95
|
-
assert.equal(existsSync(inboxPath('observer')), false);
|
|
96
|
-
assert.equal(readInboxSince('observer').length, 0);
|
|
97
|
-
// It landed in the passive accumulator instead.
|
|
98
|
-
assert.equal(acc.length, 1);
|
|
99
|
-
assert.equal(acc[0].from, 'pub');
|
|
100
|
-
assert.equal(acc[0].label, 'first observation');
|
|
101
|
-
assert.match(acc[0].ref ?? '', /^pub:reports\/\d{8}T\d{9}-[0-9a-f]{8}-update\.md$/, 'report refs use a compact random suffix');
|
|
51
|
+
const executionId = execution('observer');
|
|
52
|
+
const claim = claimNodeMail('observer', executionId, 'passive');
|
|
53
|
+
assert.equal(hasUnseenWakeMail('observer'), false, 'passive mail does not wake a node');
|
|
54
|
+
assert.equal(claim.action, 'claimed');
|
|
55
|
+
assert.equal(claim.deliveries.length, 1);
|
|
56
|
+
const entry = nodeMailEntry(claim.deliveries[0]);
|
|
57
|
+
assert.equal(entry.from, 'pub');
|
|
58
|
+
assert.equal(entry.label, 'first observation');
|
|
59
|
+
assert.equal(entry.ref, `pub:reports/${basename(result.reportPath)}`);
|
|
60
|
+
assert.match(entry.ref ?? '', /^pub:reports\/\d{8}T\d{9}-[0-9a-f]{8}-update\.md$/);
|
|
102
61
|
});
|
|
103
|
-
test('active
|
|
62
|
+
test('an active subscriber receives waking SQL mail and clears its deadline', async () => {
|
|
104
63
|
createNode(node('pub'));
|
|
105
64
|
createNode(node('worker-mgr'));
|
|
106
|
-
subscribe('worker-mgr', 'pub', true);
|
|
65
|
+
subscribe('worker-mgr', 'pub', true);
|
|
107
66
|
armCron({
|
|
108
67
|
cron_id: 'manager-deadline',
|
|
109
68
|
name: 'manager deadline',
|
|
@@ -126,102 +85,36 @@ test('active push still lands in inbox.jsonl (wakes) and clears the manager dead
|
|
|
126
85
|
tier: 'normal',
|
|
127
86
|
});
|
|
128
87
|
await push('pub', { kind: 'update', body: 'active report' });
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
assert.equal(
|
|
132
|
-
assert.equal(
|
|
133
|
-
assert.
|
|
134
|
-
assert.equal(getCron('manager-deadline'), null, 'the child report won the deadline race');
|
|
135
|
-
});
|
|
136
|
-
test('a deferred update still lands in an active subscriber inbox at deferred tier', async () => {
|
|
137
|
-
createNode(node('pub'));
|
|
138
|
-
// Resident: deferred mail to a TERMINAL target is bumped to urgent by the
|
|
139
|
-
// shipped tier bump, so only a resident subscriber shows the requested tier.
|
|
140
|
-
createNode(node('worker-mgr', { lifecycle: 'resident' }));
|
|
141
|
-
subscribe('worker-mgr', 'pub', true); // ACTIVE
|
|
142
|
-
await push('pub', { kind: 'update', deliveryTier: 'deferred', body: 'active report' });
|
|
143
|
-
assert.equal(existsSync(passivePath('worker-mgr')), false);
|
|
144
|
-
const inbox = readInboxSince('worker-mgr');
|
|
145
|
-
assert.equal(inbox.length, 1);
|
|
146
|
-
assert.equal(inbox[0].from, 'pub');
|
|
147
|
-
assert.equal(inbox[0].tier, 'deferred', 'requested delivery urgency reaches the subscriber unchanged');
|
|
148
|
-
assert.equal(inbox[0].kind, 'update', 'the stored report kind is untouched by delivery urgency');
|
|
149
|
-
assert.match(inbox[0].ref ?? '', /^pub:reports\/.+-update\.md$/);
|
|
88
|
+
const claim = claimNodeMail('worker-mgr', execution('worker-mgr'), 'wake');
|
|
89
|
+
assert.equal(hasUnseenWakeMail('worker-mgr'), true);
|
|
90
|
+
assert.equal(getCron('manager-deadline'), null, 'the report won the deadline race');
|
|
91
|
+
assert.equal(claim.deliveries.length, 1);
|
|
92
|
+
assert.equal(nodeMailEntry(claim.deliveries[0]).from, 'pub');
|
|
150
93
|
});
|
|
151
|
-
test('
|
|
94
|
+
test('a passive delivery is acknowledged only after it has been claimed', async () => {
|
|
152
95
|
createNode(node('pub'));
|
|
153
|
-
createNode(node('active-sub'));
|
|
154
|
-
createNode(node('passive-sub'));
|
|
155
|
-
subscribe('active-sub', 'pub', true);
|
|
156
|
-
subscribe('passive-sub', 'pub', false);
|
|
157
|
-
const res = await push('pub', { kind: 'urgent', body: 'something happened' });
|
|
158
|
-
assert.deepEqual(new Set(res.deliveredTo), new Set(['active-sub', 'passive-sub']));
|
|
159
|
-
assert.equal(readInboxSince('active-sub').length, 1);
|
|
160
|
-
assert.equal(existsSync(passivePath('active-sub')), false);
|
|
161
|
-
assert.equal(readPassiveEntries('passive-sub').length, 1);
|
|
162
|
-
assert.equal(existsSync(inboxPath('passive-sub')), false);
|
|
163
|
-
});
|
|
164
|
-
test('broker passive drain reads then clears (surfaces exactly once)', () => {
|
|
165
|
-
createNode(node('observer'));
|
|
166
|
-
appendPassive('observer', { from: 'a', tier: 'normal', kind: 'update', label: 'one' });
|
|
167
|
-
appendPassive('observer', { from: 'b', tier: 'normal', kind: 'update', label: 'two' });
|
|
168
|
-
const drained = drainBrokerPassive('observer');
|
|
169
|
-
assert.equal(drained.length, 2);
|
|
170
|
-
assert.deepEqual(drained.map((e) => e.label), ['one', 'two']); // oldest first
|
|
171
|
-
// Cleared — a second drain is empty.
|
|
172
|
-
assert.equal(drainBrokerPassive('observer').length, 0);
|
|
173
|
-
assert.equal(readPassiveEntries('observer').length, 0);
|
|
174
|
-
});
|
|
175
|
-
test('broker passive drain tolerates a corrupt line — keeps every good entry, loses only the bad one', () => {
|
|
176
96
|
createNode(node('observer'));
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
const
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
assert.
|
|
97
|
+
subscribe('observer', 'pub', false);
|
|
98
|
+
await push('pub', { kind: 'update', body: 'one' });
|
|
99
|
+
await push('pub', { kind: 'update', body: 'two' });
|
|
100
|
+
const executionId = execution('observer');
|
|
101
|
+
const claim = claimNodeMail('observer', executionId, 'passive');
|
|
102
|
+
assert.deepEqual(claim.deliveries.map((delivery) => nodeMailEntry(delivery).label), ['one', 'two']);
|
|
103
|
+
const receipt = acknowledgeNodeMail('observer', executionId, claim.deliveries.map((delivery) => ({
|
|
104
|
+
deliveryId: delivery.deliveryId,
|
|
105
|
+
attempts: delivery.attempts,
|
|
106
|
+
disposition: 'acknowledged',
|
|
107
|
+
})));
|
|
108
|
+
assert.deepEqual(receipt.results.map((result) => result.outcome), ['acknowledged', 'acknowledged']);
|
|
109
|
+
assert.deepEqual(claimNodeMail('observer', executionId, 'passive').deliveries, []);
|
|
189
110
|
});
|
|
190
|
-
|
|
191
|
-
return { on(e, h) { if (e === 'input')
|
|
192
|
-
this.handler = h; } };
|
|
193
|
-
}
|
|
194
|
-
test('input handler injects drained backlog as pre-text, then clears it', async () => {
|
|
111
|
+
test('passive SQL mail retains the existing timestamped backlog rendering', async () => {
|
|
195
112
|
createNode(node('pub'));
|
|
196
113
|
createNode(node('observer'));
|
|
197
114
|
subscribe('observer', 'pub', false);
|
|
198
115
|
await push('pub', { kind: 'update', body: 'the body of the report\nsecond line' });
|
|
199
|
-
|
|
200
|
-
const
|
|
201
|
-
|
|
202
|
-
assert.
|
|
203
|
-
// First message → backlog drains in as pre-text before the user's text.
|
|
204
|
-
const out = await pi.handler({ type: 'input', text: 'hey what happened', source: 'interactive' });
|
|
205
|
-
assert.equal(out.action, 'transform');
|
|
206
|
-
assert.match(out.text, /<passive-subscription-backlog/);
|
|
207
|
-
assert.match(out.text, /the body of the report/); // dereferenced report body
|
|
208
|
-
assert.match(out.text, /hey what happened$/); // original message preserved at the end
|
|
209
|
-
// Second message → nothing accumulated → left untouched.
|
|
210
|
-
const out2 = await pi.handler({ type: 'input', text: 'still there?', source: 'interactive' });
|
|
211
|
-
assert.ok(out2 === undefined || out2.action === 'continue');
|
|
212
|
-
// Oversized canonical reports must leave an actionable reader command in the
|
|
213
|
-
// truncation tail, using the exact ref emitted into the passive feed.
|
|
214
|
-
await push('pub', { kind: 'update', body: 'oversized report line '.repeat(250) });
|
|
215
|
-
const oversizedRef = readPassiveEntries('observer')[0].ref;
|
|
216
|
-
const out3 = await pi.handler({ type: 'input', text: 'show me the rest', source: 'interactive' });
|
|
217
|
-
assert.equal(out3.action, 'transform');
|
|
218
|
-
assert.ok(out3.text.includes(`crtr canvas history read ${oversizedRef}`), 'truncation tail names the canonical reader and emitted ref');
|
|
219
|
-
});
|
|
220
|
-
test('input handler is inert when nothing is accumulated', async () => {
|
|
221
|
-
createNode(node('observer'));
|
|
222
|
-
process.env['CRTR_NODE_ID'] = 'observer';
|
|
223
|
-
const pi = makeFakePi();
|
|
224
|
-
registerCanvasPassiveContext(pi);
|
|
225
|
-
const out = await pi.handler({ type: 'input', text: 'plain message', source: 'interactive' });
|
|
226
|
-
assert.ok(out === undefined || out.action === 'continue');
|
|
116
|
+
const claim = claimNodeMail('observer', execution('observer'), 'passive');
|
|
117
|
+
const text = formatPassive(claim.deliveries.map(nodeMailEntry));
|
|
118
|
+
assert.match(text, /<passive-subscription-backlog/);
|
|
119
|
+
assert.match(text, /the body of the report/);
|
|
227
120
|
});
|
|
@@ -17,7 +17,8 @@ import { tmpdir } from 'node:os';
|
|
|
17
17
|
import { join } from 'node:path';
|
|
18
18
|
import * as tar from 'tar';
|
|
19
19
|
import { resetScopeCache } from '../scope.js';
|
|
20
|
-
import { readMergedLaunchConfig } from '../config.js';
|
|
20
|
+
import { readMergedLaunchConfig, updateRawConfigAtomically, writeRawConfig } from '../config.js';
|
|
21
|
+
import { initializeFreshScopedStore } from '../scoped-state/migrate.js';
|
|
21
22
|
import { validatePluginBundle } from '../command-plugins/bundle.js';
|
|
22
23
|
let isolatedHome;
|
|
23
24
|
let isolatedCwd;
|
|
@@ -32,6 +33,7 @@ beforeEach(() => {
|
|
|
32
33
|
isolatedCwd = realpathSync(mkdtempSync(join(tmpdir(), 'crtr-plugin-kinds-cwd-')));
|
|
33
34
|
process.env.HOME = isolatedHome;
|
|
34
35
|
process.chdir(isolatedCwd);
|
|
36
|
+
initializeFreshScopedStore({ kind: 'user', root: join(isolatedHome, '.crouter') });
|
|
35
37
|
resetScopeCache();
|
|
36
38
|
});
|
|
37
39
|
afterEach(() => {
|
|
@@ -76,7 +78,7 @@ test('the scope\u2019s own config.json overrides its plugins; a disabled plugin
|
|
|
76
78
|
const root = userRoot();
|
|
77
79
|
plantPlugin(root, 'northlight', { 'applet-builder': { whenToUse: 'plugin gloss', model: 'anthropic/strong' } });
|
|
78
80
|
plantPlugin(root, 'zzz-disabled', { ghost: { whenToUse: 'never registers' } });
|
|
79
|
-
|
|
81
|
+
updateRawConfigAtomically('user', () => ({
|
|
80
82
|
plugins: { 'zzz-disabled': { enabled: false } },
|
|
81
83
|
kinds: { 'applet-builder': { model: 'openai/medium' } },
|
|
82
84
|
}));
|
|
@@ -91,7 +93,7 @@ test('a whenToUse-only entry re-glosses an existing kind without stripping its m
|
|
|
91
93
|
// Now every entry field-merges over an existing kind; only a NEW kind
|
|
92
94
|
// requires whenToUse (a whenToUse-less new kind is dropped).
|
|
93
95
|
const root = userRoot();
|
|
94
|
-
|
|
96
|
+
updateRawConfigAtomically('user', () => ({ kinds: { explore: { whenToUse: 'custom explore gloss' }, 'new-glossless': { model: 'openai/light' } } }));
|
|
95
97
|
const kinds = readMergedLaunchConfig().kinds;
|
|
96
98
|
assert.equal(kinds['explore']?.whenToUse, 'custom explore gloss');
|
|
97
99
|
assert.equal(kinds['explore']?.model, 'openai/light'); // builtin tier survives
|
|
@@ -100,7 +102,7 @@ test('a whenToUse-only entry re-glosses an existing kind without stripping its m
|
|
|
100
102
|
});
|
|
101
103
|
test('a project-root plugin layers above user config, and the project config above the plugin', () => {
|
|
102
104
|
const uRoot = userRoot();
|
|
103
|
-
|
|
105
|
+
writeRawConfig('user', { kinds: { shared: { whenToUse: 'user gloss', model: 'openai/light' } } });
|
|
104
106
|
const pRoot = projectRoot();
|
|
105
107
|
plantPlugin(pRoot, 'proj-plugin', { shared: { model: 'anthropic/strong' }, 'proj-kind': { whenToUse: 'project plugin kind' } });
|
|
106
108
|
writeFileSync(join(pRoot, 'config.json'), JSON.stringify({ kinds: { 'proj-kind': { model: 'openai/medium' } } }));
|
|
@@ -11,8 +11,11 @@ import assert from 'node:assert/strict';
|
|
|
11
11
|
import { mkdtempSync, mkdirSync, rmSync, symlinkSync, writeFileSync } from 'node:fs';
|
|
12
12
|
import { tmpdir } from 'node:os';
|
|
13
13
|
import { join } from 'node:path';
|
|
14
|
+
import { realpathSync } from 'node:fs';
|
|
14
15
|
import { linkOrCopy } from '../fs-utils.js';
|
|
15
16
|
import { listInstalledPluginsInRoot } from '../resolver.js';
|
|
17
|
+
import { closeScopedStores } from '../scoped-state/db.js';
|
|
18
|
+
import { initializeFreshScopedStore } from '../scoped-state/migrate.js';
|
|
16
19
|
describe('plugin link through a symlinked scope-root ancestor', () => {
|
|
17
20
|
test('the installed plugin resolves on the next invocation', () => {
|
|
18
21
|
const base = mkdtempSync(join(tmpdir(), 'crtr-plugin-link-'));
|
|
@@ -28,10 +31,12 @@ describe('plugin link through a symlinked scope-root ancestor', () => {
|
|
|
28
31
|
symlinkSync(join('physical', 'home'), join(base, 'home'), 'dir');
|
|
29
32
|
const scopeRootPath = join(base, 'home', '.crouter');
|
|
30
33
|
mkdirSync(join(scopeRootPath, 'plugins'), { recursive: true });
|
|
34
|
+
initializeFreshScopedStore({ kind: 'user', root: scopeRootPath });
|
|
31
35
|
linkOrCopy(source, join(scopeRootPath, 'plugins', 'search'));
|
|
32
|
-
assert.deepEqual(listInstalledPluginsInRoot('user', scopeRootPath).map((p) => p.name), ['search']);
|
|
36
|
+
assert.deepEqual(listInstalledPluginsInRoot('user', realpathSync(scopeRootPath)).map((p) => p.name), ['search']);
|
|
33
37
|
}
|
|
34
38
|
finally {
|
|
39
|
+
closeScopedStores();
|
|
35
40
|
rmSync(base, { recursive: true, force: true });
|
|
36
41
|
}
|
|
37
42
|
});
|