@north-light/crouter 0.3.311 → 0.3.313
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/client.d.ts +27 -30
- package/dist/api/client.js +80 -67
- package/dist/api/dto/broker-ops.d.ts +10 -20
- package/dist/api/dto/canvas.d.ts +1 -10
- package/dist/api/dto/health.d.ts +113 -0
- package/dist/api/dto/human-requests.d.ts +14 -3
- package/dist/api/dto/human.d.ts +2 -48
- package/dist/api/dto/human.js +3 -2
- package/dist/api/dto/inbox.d.ts +14 -0
- package/dist/api/dto/mail.d.ts +43 -0
- package/dist/api/dto/nodes.d.ts +11 -8
- package/dist/api/dto/recovery.d.ts +96 -0
- package/dist/api/dto/reviews.d.ts +2 -2
- package/dist/api/routes.d.ts +9 -6
- package/dist/api/routes.js +11 -11
- package/dist/build-root.d.ts +4 -0
- package/dist/build-root.js +11 -1
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/__tests__/integration/provider-rotation.test.ts +35 -47
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.d.ts +1 -1
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.js +12 -5
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.ts +12 -5
- package/dist/cli.js +10 -1
- package/dist/clients/__tests__/helpers/human-daemon.d.ts +11 -0
- package/dist/clients/__tests__/helpers/human-daemon.js +60 -0
- package/dist/clients/attach/chrome/canvas-panels.js +1 -1
- package/dist/clients/attach/chrome/inbox-strip.d.ts +3 -3
- package/dist/clients/attach/chrome/inbox-strip.js +17 -9
- package/dist/clients/attach/chrome/ticket-panel.d.ts +2 -2
- package/dist/clients/attach/chrome/ticket-panel.js +77 -46
- package/dist/clients/attach/overlays/graph.js +6 -9
- package/dist/clients/attach/render/chat-view.d.ts +5 -4
- package/dist/clients/attach/render/chat-view.js +22 -13
- package/dist/clients/attach/render/page-block.d.ts +11 -7
- package/dist/clients/attach/render/page-block.js +64 -55
- package/dist/clients/attach/viewer.js +746 -735
- package/dist/clients/inbox/__tests__/integration/inbox-controller.test.js +56 -56
- package/dist/clients/inbox/__tests__/integration/stale-row-activation.test.js +45 -32
- package/dist/clients/inbox/controller.d.ts +42 -14
- package/dist/clients/inbox/controller.js +240 -124
- package/dist/clients/inbox/dto-adapt.d.ts +28 -0
- package/dist/clients/inbox/dto-adapt.js +93 -0
- package/dist/clients/inbox/page-adapter.d.ts +5 -4
- package/dist/clients/inbox/page-adapter.js +12 -12
- package/dist/clients/inbox/resolve.d.ts +10 -5
- package/dist/clients/inbox/resolve.js +13 -12
- package/dist/clients/inbox/review/review-client.d.ts +0 -1
- package/dist/clients/inbox/review/review-client.js +0 -4
- package/dist/clients/inbox/review-adapter.d.ts +2 -1
- package/dist/clients/inbox/review-adapter.js +3 -5
- package/dist/clients/inbox/surface.d.ts +2 -2
- package/dist/clients/inbox/surface.js +19 -8
- package/dist/clients/inbox/tui.d.ts +3 -3
- package/dist/commands/__tests__/human.test.js +31 -15
- package/dist/commands/__tests__/integration/dashboard-snapshot.test.js +36 -11
- package/dist/commands/{sys/__tests__ → __tests__/integration}/migrate.test.js +142 -36
- package/dist/commands/__tests__/revive-now-gate.test.js +2 -0
- package/dist/commands/api-client.d.ts +5 -4
- package/dist/commands/api-client.js +13 -7
- package/dist/commands/canvas-history/shared.js +1 -1
- package/dist/commands/canvas-history.js +1 -1
- package/dist/commands/canvas-roster.js +1 -1
- package/dist/commands/canvas.js +1 -2
- package/dist/commands/human/feedback.js +20 -17
- package/dist/commands/human/prompts.js +45 -36
- package/dist/commands/human/queue.js +73 -123
- package/dist/commands/human/review.js +6 -16
- package/dist/commands/memory/__tests__/command-selector-and-mutation-guards.test.js +2 -0
- package/dist/commands/memory/__tests__/memory-list-and-lint-ignore.test.js +2 -0
- package/dist/commands/memory/__tests__/repository-root-lint.test.js +2 -0
- package/dist/commands/node-inspect-artifacts.js +1 -1
- package/dist/commands/node-lifecycle-revive.d.ts +2 -2
- package/dist/commands/node-lifecycle-revive.js +9 -19
- package/dist/commands/pkg/plugin-manage.js +0 -1
- package/dist/commands/profile/show.js +4 -12
- package/dist/commands/surface-tmux-spread.js +1 -5
- package/dist/commands/sys/__tests__/config-model-ladders.test.js +23 -30
- package/dist/commands/sys/__tests__/sync-project-guidance.test.js +37 -11
- package/dist/commands/sys/branch.d.ts +2 -0
- package/dist/commands/sys/branch.js +19 -0
- package/dist/commands/sys/config.js +106 -33
- package/dist/commands/sys/daemon.d.ts +2 -0
- package/dist/commands/sys/daemon.js +130 -7
- package/dist/commands/sys/doctor.js +5 -15
- package/dist/commands/sys/migrate.js +21 -92
- package/dist/commands/sys/setup-settings-runner.js +4 -2
- package/dist/commands/sys.js +2 -15
- package/dist/core/__tests__/boot-fault-attempt.test.js +23 -1
- package/dist/core/__tests__/boot.test.js +32 -25
- package/dist/core/__tests__/broker-launch-candidates.test.js +49 -0
- package/dist/core/__tests__/canvas-inbox-watcher-hold.test.js +149 -176
- package/dist/core/__tests__/canvas-inbox-watcher-naming.test.js +59 -10
- package/dist/core/__tests__/canvas-inbox-watcher.test.js +76 -20
- package/dist/core/__tests__/canvas.test.js +18 -47
- package/dist/core/__tests__/child-death-wake.test.js +29 -7
- package/dist/core/__tests__/cli-help-contract.test.js +2 -0
- package/dist/core/__tests__/close.test.js +29 -10
- package/dist/core/__tests__/collectible.test.js +2 -1
- package/dist/core/__tests__/config-change-delta.test.js +2 -0
- package/dist/core/__tests__/context-intro.test.js +17 -5
- package/dist/core/__tests__/cron-armed-context-failure.test.js +17 -12
- package/dist/core/__tests__/cron-held-settlement.test.js +21 -3
- package/dist/core/__tests__/cron-node-sink-parked-root.test.js +29 -10
- package/dist/core/__tests__/cron-self-cancel-delivery.test.js +14 -2
- package/dist/core/__tests__/cron-timeout-descendants.test.js +13 -1
- package/dist/core/__tests__/daemon-boot.test.js +51 -14
- package/dist/core/__tests__/fixtures/fake-engine.d.ts +1 -1
- package/dist/core/__tests__/fixtures/fake-engine.js +8 -3
- package/dist/core/__tests__/focuses.test.js +10 -5
- package/dist/core/__tests__/helpers/harness.js +50 -18
- package/dist/core/__tests__/history-inbox.test.js +12 -16
- package/dist/core/__tests__/human-action-delivery.test.js +48 -28
- package/dist/core/__tests__/human-actions.test.js +7 -3
- package/dist/core/__tests__/inline-memory-refs.test.js +7 -2
- package/dist/core/__tests__/integration/broker-fork-seam.test.js +37 -10
- package/dist/core/__tests__/integration/broker-sdk-wiring.test.js +42 -0
- package/dist/core/__tests__/integration/broker-snapshot-history.test.js +42 -29
- package/dist/core/__tests__/integration/broker-wedge-supervision.test.js +36 -35
- package/dist/core/__tests__/integration/command-plugins.test.js +15 -6
- package/dist/core/__tests__/integration/deferred-no-wake.test.js +113 -92
- package/dist/core/__tests__/integration/host-teardown-process-group.test.js +9 -5
- package/dist/core/__tests__/integration/lifecycle-hooks.test.js +312 -1
- package/dist/core/__tests__/integration/plugin-revalidate.test.js +4 -0
- package/dist/core/__tests__/integration/profile-pause.test.js +4 -4
- package/dist/core/__tests__/integration/refresh-stall-recycle.test.js +9 -12
- package/dist/core/__tests__/integration/revive.test.js +67 -21
- package/dist/core/__tests__/integration/spawn-root.test.js +62 -19
- package/dist/core/__tests__/integration/subscription-delivery.test.js +33 -21
- package/dist/core/__tests__/integration/worktree-land.test.js +5 -2
- package/dist/core/__tests__/integration/worktree-reap.test.js +15 -1
- package/dist/core/__tests__/kickoff.test.js +36 -39
- package/dist/core/__tests__/lifecycle-terminal-reasons.test.js +2 -1
- package/dist/core/__tests__/lifecycle.test.js +2 -1
- package/dist/core/__tests__/live-lifecycle-prompt.test.js +13 -1
- package/dist/core/__tests__/memory-resolver-precedence.test.js +2 -0
- package/dist/core/__tests__/migration.test.js +145 -31
- package/dist/core/__tests__/model-pin-durability.test.js +4 -1
- package/dist/core/__tests__/model-routes-config.test.js +13 -5
- package/dist/core/__tests__/node-outcome.test.js +93 -26
- package/dist/core/__tests__/on-read-crouter-home-fence.test.js +4 -3
- package/dist/core/__tests__/on-read-dedup-resume.test.js +8 -7
- package/dist/core/__tests__/on-read-nested-store.test.js +8 -7
- package/dist/core/__tests__/passive-subscription.test.js +50 -157
- package/dist/core/__tests__/plugin-kinds.test.js +6 -4
- package/dist/core/__tests__/plugin-link-symlinked-scope-root.test.js +6 -1
- package/dist/core/__tests__/plugin-page-components.test.js +6 -4
- package/dist/core/__tests__/preview-registry-sync.test.js +2 -0
- package/dist/core/__tests__/profile-project-memory-delivery.test.js +35 -32
- package/dist/core/__tests__/prune.test.js +11 -5
- package/dist/core/__tests__/push-final-guard.test.js +14 -7
- package/dist/core/__tests__/relaunch-root.test.js +30 -2
- package/dist/core/__tests__/remote-canvas-target.test.js +7 -1
- package/dist/core/__tests__/repository-root-identity.test.js +4 -0
- package/dist/core/__tests__/review-model-floor.test.js +6 -3
- package/dist/core/__tests__/revive-all.test.js +13 -3
- package/dist/core/__tests__/revive-capacity.test.js +26 -4
- package/dist/core/__tests__/revive-parked-fresh.test.js +31 -8
- package/dist/core/__tests__/seam/broker-attach-stream.test.js +1 -1
- package/dist/core/__tests__/seam/broker-cap-freeze.test.js +4 -3
- package/dist/core/__tests__/seam/broker-crash-teardown.test.js +11 -14
- package/dist/core/__tests__/seam/broker-provider-retry.test.js +85 -71
- package/dist/core/__tests__/seam/dormancy-release.test.js +33 -19
- package/dist/core/__tests__/seam/held-deferred-human-prompt.test.js +7 -5
- package/dist/core/__tests__/seam/inbox-reference-guidance.test.js +20 -6
- package/dist/core/__tests__/seam/node-outcome-delivery.test.js +27 -3
- package/dist/core/__tests__/spawn-worktree-id-conflict.test.js +5 -4
- package/dist/core/__tests__/stop-guard.test.js +2 -1
- package/dist/core/__tests__/subscription-pool-credential-guard.test.js +4 -3
- package/dist/core/__tests__/warm-claim-preference-snapshot.test.js +19 -5
- package/dist/core/__tests__/yield-ensures-daemon.test.js +2 -1
- package/dist/core/bootstrap.js +2 -0
- package/dist/core/broker-client/__tests__/transport-socket.test.js +51 -6
- package/dist/core/broker-client/transport-socket.d.ts +1 -0
- package/dist/core/broker-client/transport-socket.js +13 -5
- package/dist/core/canvas/__tests__/attention.test.js +29 -35
- package/dist/core/canvas/__tests__/history-transcript.test.js +6 -6
- package/dist/core/canvas/__tests__/render-remote.test.js +25 -9
- package/dist/core/canvas/attention.d.ts +2 -5
- package/dist/core/canvas/attention.js +15 -64
- package/dist/core/canvas/boot.d.ts +6 -7
- package/dist/core/canvas/boot.js +5 -9
- package/dist/core/canvas/canvas.d.ts +13 -109
- package/dist/core/canvas/canvas.js +140 -401
- package/dist/core/canvas/crons.d.ts +2 -0
- package/dist/core/canvas/crons.js +16 -15
- package/dist/core/canvas/daemon-owner.js +10 -0
- package/dist/core/canvas/db.d.ts +2 -2
- package/dist/core/canvas/db.js +2 -18
- package/dist/core/canvas/deliveries.d.ts +104 -0
- package/dist/core/canvas/deliveries.js +354 -0
- package/dist/core/canvas/executions.d.ts +29 -0
- package/dist/core/canvas/executions.js +68 -0
- package/dist/core/canvas/history.js +35 -35
- package/dist/core/canvas/index.d.ts +3 -1
- package/dist/core/canvas/index.js +3 -1
- package/dist/core/canvas/migrations.js +20 -12
- package/dist/core/canvas/nav-model.js +1 -3
- package/dist/core/canvas/nav-render.d.ts +4 -4
- package/dist/core/canvas/nav-render.js +11 -21
- package/dist/core/canvas/node-sql-migration.d.ts +3 -0
- package/dist/core/canvas/node-sql-migration.js +261 -0
- package/dist/core/canvas/paths.d.ts +2 -16
- package/dist/core/canvas/paths.js +2 -31
- package/dist/core/canvas/recovery.d.ts +76 -0
- package/dist/core/canvas/recovery.js +588 -0
- package/dist/core/canvas/remote-canvas-source.js +4 -0
- package/dist/core/canvas/render-source.d.ts +16 -27
- package/dist/core/canvas/render-source.js +16 -45
- package/dist/core/canvas/sessions.d.ts +33 -0
- package/dist/core/canvas/sessions.js +78 -0
- package/dist/core/canvas/types.d.ts +33 -33
- package/dist/core/canvas/types.js +2 -5
- package/dist/core/canvas/waits.d.ts +18 -0
- package/dist/core/canvas/waits.js +70 -0
- package/dist/core/canvas/worktrees.d.ts +40 -0
- package/dist/core/canvas/worktrees.js +93 -0
- package/dist/core/command-hooks/artifact.d.ts +6 -0
- package/dist/core/command-hooks/artifact.js +22 -6
- package/dist/core/command-hooks/discovery.d.ts +2 -0
- package/dist/core/command-hooks/discovery.js +2 -0
- package/dist/core/command-hooks/lifecycle-catalog.d.ts +20 -2
- package/dist/core/command-hooks/lifecycle-catalog.js +7 -2
- package/dist/core/command-hooks/lifecycle-create.d.ts +4 -0
- package/dist/core/command-hooks/lifecycle-create.js +51 -0
- package/dist/core/command-hooks/schema.d.ts +2 -2
- package/dist/core/command-hooks/schema.js +5 -4
- package/dist/core/command-hooks/transport/exec-invoke.js +3 -1
- package/dist/core/command-hooks/transport/exec-lifecycle.d.ts +18 -8
- package/dist/core/command-hooks/transport/exec-lifecycle.js +89 -30
- package/dist/core/config.d.ts +17 -12
- package/dist/core/config.js +106 -155
- package/dist/core/errors.d.ts +1 -0
- package/dist/core/errors.js +4 -0
- package/dist/core/feed/__tests__/inbox-migrate.test.js +27 -31
- package/dist/core/feed/feed.d.ts +0 -6
- package/dist/core/feed/feed.js +68 -56
- package/dist/core/feed/inbox.d.ts +7 -81
- package/dist/core/feed/inbox.js +46 -378
- package/dist/core/feed/messages.d.ts +58 -0
- package/dist/core/feed/messages.js +217 -0
- package/dist/core/fs-utils.d.ts +4 -0
- package/dist/core/fs-utils.js +21 -1
- package/dist/core/human/answer.d.ts +1 -1
- package/dist/core/human/answer.js +1 -1
- package/dist/core/human/claim.d.ts +1 -1
- package/dist/core/human/claim.js +2 -4
- package/dist/core/human/component-docs.js +1 -1
- package/dist/core/human/feedback-companion.js +4 -3
- package/dist/core/human/feedback.d.ts +5 -8
- package/dist/core/human/feedback.js +57 -85
- package/dist/core/human/page-authoring.d.ts +30 -0
- package/dist/core/human/page-authoring.js +19 -0
- package/dist/core/human/requests.d.ts +136 -0
- package/dist/core/human/requests.js +515 -0
- package/dist/core/human/root.d.ts +0 -7
- package/dist/core/human/root.js +0 -17
- package/dist/core/human/scan.d.ts +2 -7
- package/dist/core/human/scan.js +48 -132
- package/dist/core/human/summary.d.ts +1 -1
- package/dist/core/human/summary.js +1 -1
- package/dist/core/human/tickets.d.ts +23 -83
- package/dist/core/human/tickets.js +92 -243
- package/dist/core/human/types.d.ts +5 -1
- package/dist/core/installed-plugins.js +8 -3
- package/dist/core/keybindings/__tests__/resolve.test.js +19 -17
- package/dist/core/locked-file.d.ts +6 -3
- package/dist/core/locked-file.js +36 -9
- package/dist/core/memory/extensions.js +2 -0
- package/dist/core/preview-registry.js +0 -1
- package/dist/core/profiles/__tests__/env-store.test.js +2 -0
- package/dist/core/profiles/default-binding.d.ts +0 -4
- package/dist/core/profiles/default-binding.js +12 -58
- package/dist/core/profiles/env-store.js +8 -3
- package/dist/core/profiles/manifest.d.ts +2 -37
- package/dist/core/profiles/manifest.js +35 -161
- package/dist/core/profiles/select.js +3 -0
- package/dist/core/review/__tests__/capture-origin.test.js +13 -2
- package/dist/core/review/__tests__/comments.test.js +28 -10
- package/dist/core/review/__tests__/remap.test.js +28 -10
- package/dist/core/review/__tests__/stage-identity.test.js +17 -7
- package/dist/core/review/birth.d.ts +1 -1
- package/dist/core/review/birth.js +34 -5
- package/dist/core/review/comments.js +1 -1
- package/dist/core/review/companion.d.ts +1 -1
- package/dist/core/review/companion.js +2 -2
- package/dist/core/review/document.js +1 -1
- package/dist/core/review/project.d.ts +5 -1
- package/dist/core/review/project.js +14 -36
- package/dist/core/review/realize.d.ts +3 -6
- package/dist/core/review/realize.js +51 -168
- package/dist/core/review/remap.js +1 -1
- package/dist/core/review/stage.d.ts +3 -2
- package/dist/core/review/stage.js +2 -3
- package/dist/core/review/store.d.ts +3 -21
- package/dist/core/review/store.js +140 -186
- package/dist/core/review/types.d.ts +0 -1
- package/dist/core/runtime/__tests__/install-id-cache-scoping.test.js +9 -5
- package/dist/core/runtime/__tests__/spawn-env.test.js +8 -9
- package/dist/core/runtime/broker/auth-reload.js +9 -10
- package/dist/core/runtime/broker/daemon-ops.d.ts +25 -8
- package/dist/core/runtime/broker/daemon-ops.js +42 -9
- package/dist/core/runtime/broker/extension-abort.d.ts +3 -0
- package/dist/core/runtime/broker/extension-abort.js +11 -0
- package/dist/core/runtime/broker/fault-retry.d.ts +15 -6
- package/dist/core/runtime/broker/fault-retry.js +142 -95
- package/dist/core/runtime/broker/inbox.d.ts +4 -32
- package/dist/core/runtime/broker/inbox.js +4 -92
- package/dist/core/runtime/broker/rebind.d.ts +1 -0
- package/dist/core/runtime/broker/rebind.js +21 -12
- package/dist/core/runtime/broker-persona-guidance.d.ts +1 -1
- package/dist/core/runtime/broker-persona-guidance.js +2 -13
- package/dist/core/runtime/broker.js +28 -22
- package/dist/core/runtime/close.d.ts +3 -9
- package/dist/core/runtime/close.js +16 -27
- package/dist/core/runtime/fault.d.ts +3 -93
- package/dist/core/runtime/fault.js +9 -419
- package/dist/core/runtime/kickoff.d.ts +3 -6
- package/dist/core/runtime/kickoff.js +12 -18
- package/dist/core/runtime/launch.js +1 -1
- package/dist/core/runtime/lifecycle.js +40 -7
- package/dist/core/runtime/nodes.d.ts +5 -1
- package/dist/core/runtime/nodes.js +26 -11
- package/dist/core/runtime/placement.js +2 -2
- package/dist/core/runtime/recycle.js +24 -14
- package/dist/core/runtime/reset.js +26 -7
- package/dist/core/runtime/revive.js +226 -217
- package/dist/core/runtime/spawn.d.ts +4 -1
- package/dist/core/runtime/spawn.js +43 -5
- package/dist/core/runtime/warm-pool.d.ts +2 -2
- package/dist/core/runtime/warm-pool.js +23 -3
- package/dist/core/scoped-state/db.d.ts +7 -0
- package/dist/core/scoped-state/db.js +92 -0
- package/dist/core/scoped-state/migrate.d.ts +11 -0
- package/dist/core/scoped-state/migrate.js +198 -0
- package/dist/core/scoped-state/paths.d.ts +9 -0
- package/dist/core/scoped-state/paths.js +27 -0
- package/dist/core/scoped-state/profiles.d.ts +12 -0
- package/dist/core/scoped-state/profiles.js +62 -0
- package/dist/core/scoped-state/providers.d.ts +16 -0
- package/dist/core/scoped-state/providers.js +8 -0
- package/dist/core/scoped-state/schema.d.ts +3 -0
- package/dist/core/scoped-state/schema.js +26 -0
- package/dist/core/scoped-state/settings.d.ts +28 -0
- package/dist/core/scoped-state/settings.js +82 -0
- package/dist/core/subscription-state.d.ts +29 -48
- package/dist/core/subscription-state.js +176 -712
- package/dist/core/worktree-close.js +4 -4
- package/dist/core/worktree-mutation-async.js +2 -2
- package/dist/core/worktree-sweep.js +11 -16
- package/dist/core/worktree.js +6 -12
- package/dist/daemon/__tests__/autostart-storm.test.js +1 -39
- package/dist/daemon/__tests__/helpers/source-daemon.d.ts +2 -2
- package/dist/daemon/__tests__/helpers/source-daemon.js +7 -6
- package/dist/daemon/__tests__/integration/migration-startup.test.js +59 -26
- package/dist/daemon/__tests__/node-deadline-lane.test.js +2 -1
- package/dist/daemon/__tests__/node-outcome-birth-invariants.test.js +41 -17
- package/dist/daemon/__tests__/node-outcome-delivery.test.js +39 -10
- package/dist/daemon/__tests__/reconciler-signature.test.js +2 -2
- package/dist/daemon/__tests__/subtree-filter-freshness.test.js +2 -2
- package/dist/daemon/api/__tests__/broker-settle-park.test.js +17 -12
- package/dist/daemon/api/__tests__/canvas-snapshot-fields.test.js +27 -5
- package/dist/daemon/api/__tests__/model-config.test.js +8 -8
- package/dist/daemon/api/__tests__/node-create-description.test.js +22 -5
- package/dist/daemon/api/__tests__/node-model-validation.test.js +21 -1
- package/dist/daemon/api/__tests__/nodes-activity-query.test.js +10 -12
- package/dist/daemon/api/__tests__/profile-launch-gates.test.js +6 -3
- package/dist/daemon/api/__tests__/profile-metadata-route.test.js +4 -1
- package/dist/daemon/api/__tests__/reopen-delivery.test.js +26 -8
- package/dist/daemon/api/__tests__/seam/api-server.test.js +24 -32
- package/dist/daemon/api/__tests__/seam/b10-attach-modelauth.test.js +4 -1
- package/dist/daemon/api/__tests__/seam/leaf-api-parity.test.js +5 -4
- package/dist/daemon/api/__tests__/seam/profile-delete.test.js +29 -43
- package/dist/daemon/api/__tests__/submit-result.test.js +3 -2
- package/dist/daemon/api/bridge.js +1 -1
- package/dist/daemon/api/handlers/bash-jobs.js +6 -7
- package/dist/daemon/api/handlers/broker-ops.js +47 -84
- package/dist/daemon/api/handlers/broker-recovery.d.ts +4 -0
- package/dist/daemon/api/handlers/broker-recovery.js +251 -0
- package/dist/daemon/api/handlers/canvas.js +2 -44
- package/dist/daemon/api/handlers/daemon.js +41 -0
- package/dist/daemon/api/handlers/feedback-comments.js +2 -2
- package/dist/daemon/api/handlers/health.js +10 -5
- package/dist/daemon/api/handlers/human-requests.js +168 -188
- package/dist/daemon/api/handlers/human.js +3 -148
- package/dist/daemon/api/handlers/inbox-page.d.ts +4 -0
- package/dist/daemon/api/handlers/inbox-page.js +89 -0
- package/dist/daemon/api/handlers/inbox.js +21 -120
- package/dist/daemon/api/handlers/messages.d.ts +1 -0
- package/dist/daemon/api/handlers/messages.js +73 -15
- package/dist/daemon/api/handlers/node-outcomes.js +58 -13
- package/dist/daemon/api/handlers/nodes.d.ts +1 -0
- package/dist/daemon/api/handlers/nodes.js +41 -42
- package/dist/daemon/api/handlers/reviews.js +4 -29
- package/dist/daemon/api/map.d.ts +25 -3
- package/dist/daemon/api/map.js +84 -14
- package/dist/daemon/api/server.js +68 -9
- package/dist/daemon/control.d.ts +18 -0
- package/dist/daemon/cron/disposition.d.ts +2 -0
- package/dist/daemon/cron/disposition.js +8 -5
- package/dist/daemon/cron/settle.js +37 -13
- package/dist/daemon/cron/sinks.d.ts +18 -1
- package/dist/daemon/cron/sinks.js +47 -93
- package/dist/daemon/crtrd-cli.js +4 -19
- package/dist/daemon/crtrd.d.ts +2 -0
- package/dist/daemon/crtrd.js +206 -81
- package/dist/daemon/fleet.js +5 -6
- package/dist/daemon/human/finish.d.ts +12 -24
- package/dist/daemon/human/finish.js +88 -285
- package/dist/daemon/human/settle.d.ts +40 -0
- package/dist/daemon/human/settle.js +89 -0
- package/dist/daemon/human/sweep.d.ts +20 -5
- package/dist/daemon/human/sweep.js +56 -60
- package/dist/daemon/manage.d.ts +21 -16
- package/dist/daemon/manage.js +85 -51
- package/dist/daemon/messaging/node-message.d.ts +1 -1
- package/dist/daemon/messaging/node-message.js +9 -12
- package/dist/daemon/park-activity.js +3 -3
- package/dist/daemon/reconcilers/bash-deadline.js +6 -7
- package/dist/daemon/reconcilers/broker-supervision.d.ts +1 -1
- package/dist/daemon/reconcilers/broker-supervision.js +41 -19
- package/dist/daemon/reconcilers/controller-death.js +6 -18
- package/dist/daemon/reconcilers/delivery-lane.d.ts +9 -0
- package/dist/daemon/reconcilers/delivery-lane.js +130 -0
- package/dist/daemon/reconcilers/live-obligation.js +3 -3
- package/dist/daemon/reconcilers/node-deadline.js +1 -1
- package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.d.ts +1 -1
- package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.js +10 -12
- package/dist/daemon/reconcilers/node-lifecycle/tick.js +5 -5
- package/dist/daemon/reconcilers/node-lifecycle/wants-execution.js +1 -1
- package/dist/daemon/reconcilers/pending-review-submit.js +3 -3
- package/dist/daemon/reconcilers/storage-maintenance.d.ts +2 -8
- package/dist/daemon/reconcilers/storage-maintenance.js +13 -43
- package/dist/daemon/review/companion.js +5 -11
- package/dist/daemon/review/deliver.d.ts +1 -5
- package/dist/daemon/review/deliver.js +3 -52
- package/dist/daemon/review/finish.d.ts +2 -27
- package/dist/daemon/review/finish.js +79 -263
- package/dist/daemon/review/sweep.d.ts +3 -10
- package/dist/daemon/review/sweep.js +13 -131
- package/dist/daemon/startup-policy.d.ts +0 -5
- package/dist/daemon/startup-policy.js +0 -5
- package/dist/hook-authoring.d.ts +28 -2
- package/dist/hook-authoring.js +53 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.js +1 -1
- package/dist/migrations/__tests__/activation-concurrency.test.js +3 -2
- package/dist/migrations/__tests__/activation.test.js +9 -6
- package/dist/migrations/activation.d.ts +3 -2
- package/dist/migrations/activation.js +2 -4
- package/dist/migrations/corpus.d.ts +2 -5
- package/dist/migrations/corpus.js +9 -20
- package/dist/migrations/runner.d.ts +3 -1
- package/dist/migrations/runner.js +6 -2
- package/dist/pi-extensions/__tests__/canvas-context-intro.test.js +21 -89
- package/dist/pi-extensions/__tests__/canvas-goal-capture-envelope.test.js +4 -2
- package/dist/pi-extensions/__tests__/canvas-stophook-agentend.test.js +51 -33
- package/dist/pi-extensions/__tests__/canvas-stophook-context-nudge.test.js +16 -2
- package/dist/pi-extensions/__tests__/pre-command-gate.test.js +13 -1
- package/dist/pi-extensions/canvas-inbox-watcher.js +98 -244
- package/dist/pi-extensions/canvas-passive-context.d.ts +4 -8
- package/dist/pi-extensions/canvas-passive-context.js +85 -37
- package/dist/pi-extensions/canvas-stophook.js +47 -31
- package/dist/shared/env.d.ts +1 -0
- package/dist/shared/env.js +3 -0
- package/package.json +1 -1
- package/runtime.lock.json +5 -5
- package/dist/clients/attach/__tests__/page-block.test.js +0 -54
- package/dist/clients/inbox/review-visibility.d.ts +0 -5
- package/dist/clients/inbox/review-visibility.js +0 -19
- package/dist/commands/canvas-rebuild-index.d.ts +0 -2
- package/dist/commands/canvas-rebuild-index.js +0 -46
- package/dist/core/__tests__/human-cancel-guard.test.js +0 -110
- package/dist/core/__tests__/human-deliver.test.d.ts +0 -1
- package/dist/core/__tests__/human-deliver.test.js +0 -256
- package/dist/core/__tests__/human-node-not-supervised.test.d.ts +0 -1
- package/dist/core/__tests__/human-node-not-supervised.test.js +0 -89
- package/dist/core/__tests__/integration/human-deliver-e2e.test.d.ts +0 -1
- package/dist/core/__tests__/integration/human-deliver-e2e.test.js +0 -131
- package/dist/core/__tests__/phase4-review-store.test.d.ts +0 -1
- package/dist/core/__tests__/phase4-review-store.test.js +0 -144
- package/dist/core/__tests__/watchdog-abort-arms-retry.test.d.ts +0 -1
- package/dist/core/__tests__/watchdog-abort-arms-retry.test.js +0 -110
- package/dist/core/canvas/human-deliveries.d.ts +0 -39
- package/dist/core/canvas/human-deliveries.js +0 -75
- package/dist/core/canvas/node-outcome-deliveries.d.ts +0 -64
- package/dist/core/canvas/node-outcome-deliveries.js +0 -159
- package/dist/core/feed/passive.d.ts +0 -3
- package/dist/core/feed/passive.js +0 -53
- package/dist/core/human/__tests__/inbox-cancel-worker.d.ts +0 -1
- package/dist/core/human/__tests__/inbox-cancel-worker.js +0 -7
- package/dist/core/human/__tests__/inbox-claim-worker.d.ts +0 -1
- package/dist/core/human/__tests__/inbox-claim-worker.js +0 -17
- package/dist/core/human/__tests__/inbox-stale-claim-worker.d.ts +0 -1
- package/dist/core/human/__tests__/inbox-stale-claim-worker.js +0 -8
- package/dist/core/human/__tests__/integration/inbox-core.test.d.ts +0 -1
- package/dist/core/human/__tests__/integration/inbox-core.test.js +0 -145
- package/dist/core/human/__tests__/page-tickets.test.d.ts +0 -1
- package/dist/core/human/__tests__/page-tickets.test.js +0 -161
- package/dist/core/review/ticket-filter.d.ts +0 -17
- package/dist/core/review/ticket-filter.js +0 -21
- package/dist/core/runtime/broker/passive.d.ts +0 -17
- package/dist/core/runtime/broker/passive.js +0 -44
- package/dist/core/runtime/busy.d.ts +0 -46
- package/dist/core/runtime/busy.js +0 -150
- package/dist/daemon/__tests__/startup-block-marker.test.d.ts +0 -1
- package/dist/daemon/__tests__/startup-block-marker.test.js +0 -86
- package/dist/daemon/api/__tests__/review-terminal-conflict.test.d.ts +0 -1
- package/dist/daemon/api/__tests__/review-terminal-conflict.test.js +0 -98
- package/dist/daemon/human/deliver-action.d.ts +0 -3
- package/dist/daemon/human/deliver-action.js +0 -9
- package/dist/daemon/node-outcome/deliver-outcome.d.ts +0 -3
- package/dist/daemon/node-outcome/deliver-outcome.js +0 -9
- package/dist/daemon/reconcilers/human-delivery-lane.d.ts +0 -10
- package/dist/daemon/reconcilers/human-delivery-lane.js +0 -41
- package/dist/daemon/reconcilers/node-outcome-delivery-lane.d.ts +0 -10
- package/dist/daemon/reconcilers/node-outcome-delivery-lane.js +0 -41
- package/dist/daemon/startup-block-marker.d.ts +0 -25
- package/dist/daemon/startup-block-marker.js +0 -99
- /package/dist/{clients/attach/__tests__/page-block.test.d.ts → api/dto/mail.js} +0 -0
- /package/dist/{commands/sys/__tests__/migrate.test.d.ts → api/dto/recovery.js} +0 -0
- /package/dist/{core/__tests__/human-cancel-guard.test.d.ts → commands/__tests__/integration/migrate.test.d.ts} +0 -0
package/dist/core/locked-file.js
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
// matters: pi asks its CredentialStore for every registered provider (~75) whenever it
|
|
13
13
|
// builds a model runtime, and routing those through the lock made each boot serialize
|
|
14
14
|
// behind seconds of lock acquisition backoff.
|
|
15
|
-
import { chmodSync, existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs';
|
|
15
|
+
import { chmodSync, existsSync, fsyncSync, mkdirSync, openSync, readFileSync, renameSync, writeFileSync, closeSync } from 'node:fs';
|
|
16
16
|
import { dirname } from 'node:path';
|
|
17
17
|
import lockfile from 'proper-lockfile';
|
|
18
18
|
const WRITE_OPTIONS = { encoding: 'utf-8', mode: 0o600 };
|
|
@@ -24,8 +24,12 @@ const LOCK_UPDATE_MS = 5_000;
|
|
|
24
24
|
/** A 0600 JSON file guarded by a cross-process `proper-lockfile` lock on its own path. */
|
|
25
25
|
export class LockedJsonFile {
|
|
26
26
|
path;
|
|
27
|
-
|
|
27
|
+
durable;
|
|
28
|
+
initialContent;
|
|
29
|
+
constructor(path, durable = false, initialContent = '{}') {
|
|
28
30
|
this.path = path;
|
|
31
|
+
this.durable = durable;
|
|
32
|
+
this.initialContent = initialContent;
|
|
29
33
|
}
|
|
30
34
|
readUnlocked() {
|
|
31
35
|
return existsSync(this.path) ? readFileSync(this.path, 'utf-8') : undefined;
|
|
@@ -35,7 +39,7 @@ export class LockedJsonFile {
|
|
|
35
39
|
if (!existsSync(dir))
|
|
36
40
|
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
37
41
|
if (!existsSync(this.path)) {
|
|
38
|
-
writeFileSync(this.path,
|
|
42
|
+
writeFileSync(this.path, this.initialContent, WRITE_OPTIONS);
|
|
39
43
|
chmodSync(this.path, 0o600);
|
|
40
44
|
}
|
|
41
45
|
}
|
|
@@ -64,16 +68,39 @@ export class LockedJsonFile {
|
|
|
64
68
|
});
|
|
65
69
|
throwIfCompromised();
|
|
66
70
|
const current = existsSync(this.path) ? readFileSync(this.path, 'utf-8') : undefined;
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
71
|
+
let published = false;
|
|
72
|
+
const publish = (next) => {
|
|
73
|
+
if (published)
|
|
74
|
+
throw new Error(`locked file was published twice: ${this.path}`);
|
|
75
|
+
throwIfCompromised();
|
|
72
76
|
const tmp = `${this.path}.${process.pid}.${Date.now()}.tmp`;
|
|
73
77
|
writeFileSync(tmp, next, WRITE_OPTIONS);
|
|
74
78
|
chmodSync(tmp, 0o600);
|
|
79
|
+
if (this.durable) {
|
|
80
|
+
const fd = openSync(tmp, 'r');
|
|
81
|
+
try {
|
|
82
|
+
fsyncSync(fd);
|
|
83
|
+
}
|
|
84
|
+
finally {
|
|
85
|
+
closeSync(fd);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
75
88
|
renameSync(tmp, this.path);
|
|
76
|
-
|
|
89
|
+
if (this.durable) {
|
|
90
|
+
const fd = openSync(dirname(this.path), 'r');
|
|
91
|
+
try {
|
|
92
|
+
fsyncSync(fd);
|
|
93
|
+
}
|
|
94
|
+
finally {
|
|
95
|
+
closeSync(fd);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
published = true;
|
|
99
|
+
};
|
|
100
|
+
const { result, next } = await fn(current, throwIfCompromised, publish);
|
|
101
|
+
throwIfCompromised();
|
|
102
|
+
if (next !== undefined)
|
|
103
|
+
publish(next);
|
|
77
104
|
throwIfCompromised();
|
|
78
105
|
return result;
|
|
79
106
|
}
|
|
@@ -134,6 +134,8 @@ function catalogForPlugins(groups, enabledOnly, candidate) {
|
|
|
134
134
|
/** Declarations for a native document. Project documents use their owning
|
|
135
135
|
* project scope only, then user scope; profile/node/user docs use user scope. */
|
|
136
136
|
function pluginGroupsForDocument(doc) {
|
|
137
|
+
if (doc.scope === 'builtin')
|
|
138
|
+
return [];
|
|
137
139
|
if (doc.scope === 'project') {
|
|
138
140
|
const marker = `${sep}.crouter${sep}`;
|
|
139
141
|
const markerIndex = doc.path.lastIndexOf(marker);
|
|
@@ -10,6 +10,7 @@ import { mkdtempSync, rmSync, writeFileSync } from 'node:fs';
|
|
|
10
10
|
import { tmpdir } from 'node:os';
|
|
11
11
|
import { join } from 'node:path';
|
|
12
12
|
import { createProfile } from '../manifest.js';
|
|
13
|
+
import { initializeFreshScopedStore } from '../../scoped-state/migrate.js';
|
|
13
14
|
import { resetScopeCache } from '../../scope.js';
|
|
14
15
|
import { isReservedEnvName, listProfileEnvNames, readProfileEnvVars, removeProfileEnvVar, setProfileEnvVar, } from '../env-store.js';
|
|
15
16
|
import { envBranch } from '../../../commands/profile/env.js';
|
|
@@ -32,6 +33,7 @@ beforeEach(() => {
|
|
|
32
33
|
home = mkdtempSync(join(tmpdir(), 'crtr-env-store-home-'));
|
|
33
34
|
process.env.HOME = home;
|
|
34
35
|
resetScopeCache();
|
|
36
|
+
initializeFreshScopedStore({ kind: 'user', root: join(home, '.crouter') });
|
|
35
37
|
});
|
|
36
38
|
afterEach(() => {
|
|
37
39
|
rmSync(home, { recursive: true, force: true });
|
|
@@ -1,10 +1,6 @@
|
|
|
1
|
-
/** Resolve cwd to the same absolute, realpath'd form the profile selector and
|
|
2
|
-
* manifest use. Falls back to the plain resolved path when it cannot be stat'd. */
|
|
3
1
|
export declare function resolveBindingCwd(cwd: string): string;
|
|
4
2
|
export declare function getDefaultProfileId(cwd: string): string | null;
|
|
5
3
|
export declare function setDefaultProfileId(cwd: string, profileId: string): void;
|
|
6
4
|
export declare function clearDefaultProfile(cwd: string): void;
|
|
7
|
-
/** Every directory currently pinned to `profileId`, in deterministic order. */
|
|
8
5
|
export declare function defaultProfileDirs(profileId: string): string[];
|
|
9
|
-
/** Clear every per-directory default that names `profileId`. */
|
|
10
6
|
export declare function clearDefaultProfileId(profileId: string): string[];
|
|
@@ -1,13 +1,9 @@
|
|
|
1
|
-
//
|
|
2
|
-
//
|
|
3
|
-
// which covering profile is preferred for one realpath'd directory.
|
|
1
|
+
// Per-directory default-profile pins are user-root SQL state. Profile identity
|
|
2
|
+
// remains stable across renames, so the pin stores only the generated id.
|
|
4
3
|
import { existsSync, realpathSync } from 'node:fs';
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import { readJsonIfExists, writeJson, removePath } from '../fs-utils.js';
|
|
9
|
-
/** Resolve cwd to the same absolute, realpath'd form the profile selector and
|
|
10
|
-
* manifest use. Falls back to the plain resolved path when it cannot be stat'd. */
|
|
4
|
+
import { resolve as resolvePath } from 'node:path';
|
|
5
|
+
import { userScopeRoot } from '../scope.js';
|
|
6
|
+
import { mutateStoredDefaults, readStoredDefaults } from '../scoped-state/profiles.js';
|
|
11
7
|
export function resolveBindingCwd(cwd) {
|
|
12
8
|
const abs = resolvePath(cwd);
|
|
13
9
|
if (!existsSync(abs))
|
|
@@ -19,52 +15,10 @@ export function resolveBindingCwd(cwd) {
|
|
|
19
15
|
return abs;
|
|
20
16
|
}
|
|
21
17
|
}
|
|
22
|
-
function
|
|
23
|
-
|
|
24
|
-
}
|
|
25
|
-
function
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
return Object.fromEntries(Object.entries(value).filter(([, profileId]) => typeof profileId === 'string' && profileId !== ''));
|
|
30
|
-
}
|
|
31
|
-
export function getDefaultProfileId(cwd) {
|
|
32
|
-
return bindings()[resolveBindingCwd(cwd)] ?? null;
|
|
33
|
-
}
|
|
34
|
-
export function setDefaultProfileId(cwd, profileId) {
|
|
35
|
-
const value = bindings();
|
|
36
|
-
value[resolveBindingCwd(cwd)] = profileId;
|
|
37
|
-
writeJson(bindingsPath(), value);
|
|
38
|
-
}
|
|
39
|
-
export function clearDefaultProfile(cwd) {
|
|
40
|
-
const value = bindings();
|
|
41
|
-
delete value[resolveBindingCwd(cwd)];
|
|
42
|
-
if (Object.keys(value).length === 0)
|
|
43
|
-
removePath(bindingsPath());
|
|
44
|
-
else
|
|
45
|
-
writeJson(bindingsPath(), value);
|
|
46
|
-
}
|
|
47
|
-
/** Every directory currently pinned to `profileId`, in deterministic order. */
|
|
48
|
-
export function defaultProfileDirs(profileId) {
|
|
49
|
-
return Object.entries(bindings())
|
|
50
|
-
.filter(([, pinnedProfileId]) => pinnedProfileId === profileId)
|
|
51
|
-
.map(([dir]) => dir)
|
|
52
|
-
.sort();
|
|
53
|
-
}
|
|
54
|
-
/** Clear every per-directory default that names `profileId`. */
|
|
55
|
-
export function clearDefaultProfileId(profileId) {
|
|
56
|
-
const value = bindings();
|
|
57
|
-
const cleared = Object.entries(value)
|
|
58
|
-
.filter(([, pinnedProfileId]) => pinnedProfileId === profileId)
|
|
59
|
-
.map(([dir]) => dir)
|
|
60
|
-
.sort();
|
|
61
|
-
if (cleared.length === 0)
|
|
62
|
-
return [];
|
|
63
|
-
for (const dir of cleared)
|
|
64
|
-
delete value[dir];
|
|
65
|
-
if (Object.keys(value).length === 0)
|
|
66
|
-
removePath(bindingsPath());
|
|
67
|
-
else
|
|
68
|
-
writeJson(bindingsPath(), value);
|
|
69
|
-
return cleared;
|
|
70
|
-
}
|
|
18
|
+
function bindings() { return readStoredDefaults(userScopeRoot()); }
|
|
19
|
+
export function getDefaultProfileId(cwd) { return bindings()[resolveBindingCwd(cwd)] ?? null; }
|
|
20
|
+
export function setDefaultProfileId(cwd, profileId) { const directory = resolveBindingCwd(cwd); mutateStoredDefaults(userScopeRoot(), (current) => ({ ...current, [directory]: profileId })); }
|
|
21
|
+
export function clearDefaultProfile(cwd) { const directory = resolveBindingCwd(cwd); mutateStoredDefaults(userScopeRoot(), (current) => { const next = { ...current }; delete next[directory]; return next; }); }
|
|
22
|
+
export function defaultProfileDirs(profileId) { return Object.entries(bindings()).filter(([, id]) => id === profileId).map(([directory]) => directory).sort(); }
|
|
23
|
+
export function clearDefaultProfileId(profileId) { let cleared = []; mutateStoredDefaults(userScopeRoot(), (current) => { cleared = Object.entries(current).filter(([, id]) => id === profileId).map(([directory]) => directory).sort(); const next = { ...current }; for (const directory of cleared)
|
|
24
|
+
delete next[directory]; return next; }); return cleared; }
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
// and no caller should log or echo what `readProfileEnvVars` returns.
|
|
12
12
|
import { existsSync, readFileSync, renameSync, writeFileSync, chmodSync } from 'node:fs';
|
|
13
13
|
import { join } from 'node:path';
|
|
14
|
-
import {
|
|
14
|
+
import { loadExactProfileManifest, profileRoot, withProfileManifestLock } from './manifest.js';
|
|
15
15
|
import { ensureDir } from '../fs-utils.js';
|
|
16
16
|
import { notFound, usage } from '../errors.js';
|
|
17
17
|
const ENV_FILE = 'env.json';
|
|
@@ -87,8 +87,13 @@ function writeStoreAtomic(profileId, store) {
|
|
|
87
87
|
renameSync(tmp, p);
|
|
88
88
|
}
|
|
89
89
|
function requireProfileExists(profileId) {
|
|
90
|
-
|
|
91
|
-
|
|
90
|
+
try {
|
|
91
|
+
loadExactProfileManifest(profileId);
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
if (error instanceof Error && error.message.startsWith('profile not found:'))
|
|
95
|
+
throw notFound(`profile not found: ${profileId}`, { received: profileId });
|
|
96
|
+
throw error;
|
|
92
97
|
}
|
|
93
98
|
}
|
|
94
99
|
/** Every stored variable NAME for a profile, sorted. Never returns values. */
|
|
@@ -5,62 +5,27 @@ export declare function profilesRoot(): string;
|
|
|
5
5
|
export declare function profileRoot(profileId: string): string;
|
|
6
6
|
export declare function profileManifestPath(profileId: string): string;
|
|
7
7
|
export declare function profileMemoryDir(profileId: string): string;
|
|
8
|
-
/** Reject anything a valid project array may not carry. Shape only: takes
|
|
9
|
-
* `unknown` because an API body and a hand-edited manifest both prove nothing
|
|
10
|
-
* at runtime, and deliberately says nothing about whether a path exists —
|
|
11
|
-
* existence and realpath resolution belong to the create/add paths alone, so
|
|
12
|
-
* a request naming a since-deleted directory still validates. */
|
|
13
8
|
export declare function assertProfileProjects(entries: unknown): asserts entries is ProfileProject[];
|
|
14
|
-
/** The directory a node running under `profileId` is pinned to — the profile's
|
|
15
|
-
* home, but only while it still exists on disk (a node pinned to a deleted dir
|
|
16
|
-
* cannot boot). Null for the root profile, a profile with no projects, a home
|
|
17
|
-
* that has since been deleted, and an unresolvable id.
|
|
18
|
-
*
|
|
19
|
-
* This is the whole of the profile→cwd direction: cwd SELECTS a profile at the
|
|
20
|
-
* front door, and the selected profile then SUPPLIES the node's cwd. Never
|
|
21
|
-
* throws — it sits on the node-create path. */
|
|
22
9
|
export declare function profileHome(profileId: string | null): string | null;
|
|
23
10
|
export interface ProfileEntry {
|
|
24
11
|
profileId: string;
|
|
25
12
|
manifest: ProfileManifest;
|
|
26
13
|
}
|
|
27
14
|
export interface ProfileEnumeration {
|
|
28
|
-
/** Every profile with a readable manifest, in directory-listing order. */
|
|
29
15
|
entries: ProfileEntry[];
|
|
30
|
-
/** Ids whose directory is present under the profiles root but whose manifest
|
|
31
|
-
* did not read — corrupt JSON, a pre-object project shape, an unreadable or
|
|
32
|
-
* missing `profile.json`. These are NOT deleted profiles, and a caller that
|
|
33
|
-
* cannot tell the two apart silently substitutes another identity. */
|
|
34
16
|
unreadableIds: string[];
|
|
35
17
|
}
|
|
36
|
-
/** Every profile with a readable manifest, in directory-listing order. A
|
|
37
|
-
* profile whose manifest is missing or corrupt is skipped rather than
|
|
38
|
-
* crashing the whole listing — `lookupProfile` is how a caller that must not
|
|
39
|
-
* confuse "skipped" with "gone" asks. */
|
|
40
18
|
export declare function listProfiles(): ProfileEntry[];
|
|
41
|
-
/** What a stored profile id resolves to — including the case every
|
|
42
|
-
* null-returning resolver here erases: the profile is THERE and could not be
|
|
43
|
-
* read. A caller that treats that as "deleted" substitutes another identity
|
|
44
|
-
* (root) for the one its work was pinned to. */
|
|
45
19
|
export type ProfileLookup = {
|
|
46
20
|
kind: 'resolved';
|
|
47
21
|
entry: ProfileEntry;
|
|
48
|
-
}
|
|
49
|
-
/** Nothing on this host answers to the id or name — a deleted profile. */
|
|
50
|
-
| {
|
|
22
|
+
} | {
|
|
51
23
|
kind: 'absent';
|
|
52
|
-
}
|
|
53
|
-
/** The id's directory is present; its manifest did not read. */
|
|
54
|
-
| {
|
|
24
|
+
} | {
|
|
55
25
|
kind: 'unreadable';
|
|
56
26
|
profileId: string;
|
|
57
27
|
manifestPath: string;
|
|
58
28
|
};
|
|
59
|
-
/** Exact resolution (generated id, else a unique manifest `name`) that reports
|
|
60
|
-
* WHY it failed. Only an ID can come back `unreadable`: a name lives inside
|
|
61
|
-
* the manifest that could not be read, so an unreadable profile has no name to
|
|
62
|
-
* match on. Throws on an ambiguous name, exactly as `loadProfileManifest`
|
|
63
|
-
* does. */
|
|
64
29
|
export declare function lookupProfile(profileIdOrName: string): ProfileLookup;
|
|
65
30
|
/** Read one exact profile id without falling back to manifest-name matching.
|
|
66
31
|
* Used at persistence gates that already hold a resolved durable identity. */
|
|
@@ -6,12 +6,13 @@
|
|
|
6
6
|
// here, so no caller ever passes a raw CLI operand or `CRTR_PROFILE_ID`
|
|
7
7
|
// straight into `join(profilesRoot(), value)`.
|
|
8
8
|
import { randomUUID } from 'node:crypto';
|
|
9
|
-
import { existsSync,
|
|
10
|
-
import {
|
|
9
|
+
import { existsSync, realpathSync, rmSync, statSync, } from 'node:fs';
|
|
10
|
+
import { join, relative, resolve as resolvePath, sep } from 'node:path';
|
|
11
11
|
import { SCHEMA_VERSION, PROFILE_DIR } from '../../types.js';
|
|
12
12
|
import { PROFILE_PROJECT_MEMORY_VALUES } from '../../api/dto/profiles.js';
|
|
13
13
|
import { userScopeRoot, resetScopeCache } from '../scope.js';
|
|
14
14
|
import { ensureDir, nowIso } from '../fs-utils.js';
|
|
15
|
+
import { deleteStoredProfile, getStoredProfile, insertStoredProfile, listStoredProfiles, updateStoredProfile } from '../scoped-state/profiles.js';
|
|
15
16
|
import { usage, notFound, ambiguous, general } from '../errors.js';
|
|
16
17
|
import { withExclusiveDirectoryLock } from '../exclusive-lock.js';
|
|
17
18
|
import { fuzzyMatchProfile } from './fuzzy-match.js';
|
|
@@ -24,11 +25,10 @@ import { fuzzyMatchProfile } from './fuzzy-match.js';
|
|
|
24
25
|
const ID_SHAPE = /^[a-z0-9]+(?:-[a-z0-9]+)*-[0-9a-f]{8}$/;
|
|
25
26
|
export const ROOT_PROFILE_ID = 'root-00000000';
|
|
26
27
|
const ROOT_PROFILE_NAME = 'root';
|
|
27
|
-
function scaffoldProfile(profileId,
|
|
28
|
+
function scaffoldProfile(profileId, _manifest) {
|
|
28
29
|
const root = profileRoot(profileId);
|
|
29
30
|
ensureDir(root);
|
|
30
31
|
ensureDir(join(root, 'memory'));
|
|
31
|
-
writeManifestAtomic(profileManifestPath(profileId), manifest);
|
|
32
32
|
}
|
|
33
33
|
export function profilesRoot() {
|
|
34
34
|
return join(userScopeRoot(), PROFILE_DIR);
|
|
@@ -82,144 +82,36 @@ export function profileMemoryDir(profileId) {
|
|
|
82
82
|
* the user started them, not in whatever dir was last added to its purview. */
|
|
83
83
|
function normalizeHome(profileId, manifest) {
|
|
84
84
|
const stored = typeof manifest.home === 'string' && manifest.home !== '' ? manifest.home : null;
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
return { ...manifest, home, paused_at: pausedAt };
|
|
88
|
-
}
|
|
89
|
-
/** Reject anything a valid project array may not carry. Shape only: takes
|
|
90
|
-
* `unknown` because an API body and a hand-edited manifest both prove nothing
|
|
91
|
-
* at runtime, and deliberately says nothing about whether a path exists —
|
|
92
|
-
* existence and realpath resolution belong to the create/add paths alone, so
|
|
93
|
-
* a request naming a since-deleted directory still validates. */
|
|
85
|
+
return { ...manifest, home: profileId === ROOT_PROFILE_ID ? stored : stored ?? manifest.projects[0]?.path ?? null, paused_at: typeof manifest.paused_at === 'string' && manifest.paused_at !== '' ? manifest.paused_at : null };
|
|
86
|
+
}
|
|
94
87
|
export function assertProfileProjects(entries) {
|
|
95
88
|
const memories = PROFILE_PROJECT_MEMORY_VALUES.join(', ');
|
|
96
|
-
if (!Array.isArray(entries))
|
|
97
|
-
throw usage('projects must be an array of {path, memory} objects', {
|
|
98
|
-
received: typeof entries,
|
|
99
|
-
field: 'projects',
|
|
100
|
-
next: `Pass entries like {"path": "/abs/dir", "memory": "content"} — memory is one of: ${memories}.`,
|
|
101
|
-
});
|
|
102
|
-
}
|
|
89
|
+
if (!Array.isArray(entries))
|
|
90
|
+
throw usage('projects must be an array of {path, memory} objects', { received: typeof entries, field: 'projects', next: `Pass entries like {"path": "/abs/dir", "memory": "content"} — memory is one of: ${memories}.` });
|
|
103
91
|
for (const entry of entries) {
|
|
104
|
-
if (typeof entry !== 'object' || entry === null || Array.isArray(entry))
|
|
105
|
-
throw usage(`invalid project entry: ${JSON.stringify(entry)}`, {
|
|
106
|
-
field: 'projects',
|
|
107
|
-
next: 'Every project is an object like {"path": "/abs/dir", "memory": "content"}.',
|
|
108
|
-
});
|
|
109
|
-
}
|
|
92
|
+
if (typeof entry !== 'object' || entry === null || Array.isArray(entry))
|
|
93
|
+
throw usage(`invalid project entry: ${JSON.stringify(entry)}`, { field: 'projects', next: 'Every project is an object like {"path": "/abs/dir", "memory": "content"}.' });
|
|
110
94
|
const { path, memory } = entry;
|
|
111
|
-
if (typeof path !== 'string' || path.trim() === '')
|
|
112
|
-
throw usage(`project entry has no path: ${JSON.stringify(entry)}`, {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
});
|
|
116
|
-
}
|
|
117
|
-
if (typeof memory !== 'string' || !PROFILE_PROJECT_MEMORY_VALUES.includes(memory)) {
|
|
118
|
-
throw usage(`invalid project memory value: ${JSON.stringify(memory)}`, {
|
|
119
|
-
received: String(memory),
|
|
120
|
-
field: 'projects',
|
|
121
|
-
next: `Set memory on ${path} to one of: ${memories}.`,
|
|
122
|
-
});
|
|
123
|
-
}
|
|
95
|
+
if (typeof path !== 'string' || path.trim() === '')
|
|
96
|
+
throw usage(`project entry has no path: ${JSON.stringify(entry)}`, { field: 'projects', next: 'Give every project entry a non-empty directory path.' });
|
|
97
|
+
if (typeof memory !== 'string' || !PROFILE_PROJECT_MEMORY_VALUES.includes(memory))
|
|
98
|
+
throw usage(`invalid project memory value: ${JSON.stringify(memory)}`, { received: String(memory), field: 'projects', next: `Set memory on ${path} to one of: ${memories}.` });
|
|
124
99
|
}
|
|
125
100
|
}
|
|
126
|
-
function hasCurrentProjectShape(projects) {
|
|
127
|
-
try {
|
|
128
|
-
assertProfileProjects(projects);
|
|
129
|
-
return true;
|
|
130
|
-
}
|
|
131
|
-
catch {
|
|
132
|
-
return false;
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
/** A manifest whose projects are not the current object shape is unreadable —
|
|
136
|
-
* the same treatment as corrupt JSON, so nothing downstream ever guesses a
|
|
137
|
-
* memory value. `crtr sys migrate` reads raw bytes and is the only converter
|
|
138
|
-
* of pre-object manifests. */
|
|
139
|
-
function readManifestFile(path, profileId) {
|
|
140
|
-
if (!existsSync(path))
|
|
141
|
-
return null;
|
|
142
|
-
try {
|
|
143
|
-
const parsed = JSON.parse(readFileSync(path, 'utf8'));
|
|
144
|
-
if (!hasCurrentProjectShape(parsed.projects))
|
|
145
|
-
return null;
|
|
146
|
-
return normalizeHome(profileId, parsed);
|
|
147
|
-
}
|
|
148
|
-
catch {
|
|
149
|
-
return null;
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
/** The directory a node running under `profileId` is pinned to — the profile's
|
|
153
|
-
* home, but only while it still exists on disk (a node pinned to a deleted dir
|
|
154
|
-
* cannot boot). Null for the root profile, a profile with no projects, a home
|
|
155
|
-
* that has since been deleted, and an unresolvable id.
|
|
156
|
-
*
|
|
157
|
-
* This is the whole of the profile→cwd direction: cwd SELECTS a profile at the
|
|
158
|
-
* front door, and the selected profile then SUPPLIES the node's cwd. Never
|
|
159
|
-
* throws — it sits on the node-create path. */
|
|
160
101
|
export function profileHome(profileId) {
|
|
161
102
|
if (profileId === null || profileId === '')
|
|
162
103
|
return null;
|
|
163
104
|
try {
|
|
164
|
-
const
|
|
165
|
-
|
|
166
|
-
if (home === null)
|
|
167
|
-
return null;
|
|
168
|
-
return existsSync(home) && statSync(home).isDirectory() ? home : null;
|
|
105
|
+
const home = loadProfileManifest(profileId).manifest.home;
|
|
106
|
+
return home !== null && existsSync(home) && statSync(home).isDirectory() ? home : null;
|
|
169
107
|
}
|
|
170
108
|
catch {
|
|
171
109
|
return null;
|
|
172
110
|
}
|
|
173
111
|
}
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
function enumerateProfiles() {
|
|
178
|
-
const root = profilesRoot();
|
|
179
|
-
if (!existsSync(root))
|
|
180
|
-
return { entries: [], unreadableIds: [] };
|
|
181
|
-
const entries = [];
|
|
182
|
-
const unreadableIds = [];
|
|
183
|
-
for (const dirent of readdirSync(root, { withFileTypes: true })) {
|
|
184
|
-
if (!dirent.isDirectory())
|
|
185
|
-
continue;
|
|
186
|
-
const profileId = dirent.name;
|
|
187
|
-
if (!ID_SHAPE.test(profileId))
|
|
188
|
-
continue;
|
|
189
|
-
const manifest = readManifestFile(join(root, profileId, 'profile.json'), profileId);
|
|
190
|
-
if (manifest === null)
|
|
191
|
-
unreadableIds.push(profileId);
|
|
192
|
-
else
|
|
193
|
-
entries.push({ profileId, manifest });
|
|
194
|
-
}
|
|
195
|
-
return { entries, unreadableIds };
|
|
196
|
-
}
|
|
197
|
-
/** Every profile with a readable manifest, in directory-listing order. A
|
|
198
|
-
* profile whose manifest is missing or corrupt is skipped rather than
|
|
199
|
-
* crashing the whole listing — `lookupProfile` is how a caller that must not
|
|
200
|
-
* confuse "skipped" with "gone" asks. */
|
|
201
|
-
export function listProfiles() {
|
|
202
|
-
return enumerateProfiles().entries;
|
|
203
|
-
}
|
|
204
|
-
/** Exact resolution (generated id, else a unique manifest `name`) that reports
|
|
205
|
-
* WHY it failed. Only an ID can come back `unreadable`: a name lives inside
|
|
206
|
-
* the manifest that could not be read, so an unreadable profile has no name to
|
|
207
|
-
* match on. Throws on an ambiguous name, exactly as `loadProfileManifest`
|
|
208
|
-
* does. */
|
|
209
|
-
export function lookupProfile(profileIdOrName) {
|
|
210
|
-
const { entries, unreadableIds } = enumerateProfiles();
|
|
211
|
-
const exact = findExactProfile(entries, profileIdOrName);
|
|
212
|
-
if (exact !== null)
|
|
213
|
-
return { kind: 'resolved', entry: exact };
|
|
214
|
-
if (unreadableIds.includes(profileIdOrName)) {
|
|
215
|
-
return {
|
|
216
|
-
kind: 'unreadable',
|
|
217
|
-
profileId: profileIdOrName,
|
|
218
|
-
manifestPath: join(profilesRoot(), profileIdOrName, 'profile.json'),
|
|
219
|
-
};
|
|
220
|
-
}
|
|
221
|
-
return { kind: 'absent' };
|
|
222
|
-
}
|
|
112
|
+
function enumerateProfiles() { return { entries: listStoredProfiles(userScopeRoot()).map(({ profileId, manifest }) => ({ profileId, manifest: normalizeHome(profileId, manifest) })), unreadableIds: [] }; }
|
|
113
|
+
export function listProfiles() { return enumerateProfiles().entries; }
|
|
114
|
+
export function lookupProfile(profileIdOrName) { const entries = listProfiles(); const exact = findExactProfile(entries, profileIdOrName); return exact ? { kind: 'resolved', entry: exact } : { kind: 'absent' }; }
|
|
223
115
|
// Three resolvers, in descending tolerance. `resolveProfileOperand` is what a
|
|
224
116
|
// command leaf calls for a value the USER TYPED: exact id, exact name, then a
|
|
225
117
|
// fuzzy fallback. `loadProfileManifest` is the strict middle — exact id or
|
|
@@ -233,13 +125,10 @@ export function lookupProfile(profileIdOrName) {
|
|
|
233
125
|
* Used at persistence gates that already hold a resolved durable identity. */
|
|
234
126
|
export function loadExactProfileManifest(profileId) {
|
|
235
127
|
assertSafeProfileId(profileId);
|
|
236
|
-
const
|
|
237
|
-
if (
|
|
238
|
-
return { profileId, manifest };
|
|
239
|
-
throw notFound(`profile not found: ${profileId}`, {
|
|
240
|
-
received: profileId,
|
|
241
|
-
next: 'Run `crtr profile list` to see available profiles.',
|
|
242
|
-
});
|
|
128
|
+
const stored = getStoredProfile(userScopeRoot(), profileId);
|
|
129
|
+
if (stored !== null)
|
|
130
|
+
return { profileId, manifest: normalizeHome(profileId, stored.manifest) };
|
|
131
|
+
throw notFound(`profile not found: ${profileId}`, { received: profileId, next: 'Run `crtr profile list` to see available profiles.' });
|
|
243
132
|
}
|
|
244
133
|
/** Exact resolution only: the generated id, else a unique manifest `name`.
|
|
245
134
|
* Returns `null` when nothing matches exactly; still THROWS when a name is
|
|
@@ -334,12 +223,6 @@ export function withProfileManifestLock(profileId, fn) {
|
|
|
334
223
|
}),
|
|
335
224
|
});
|
|
336
225
|
}
|
|
337
|
-
function writeManifestAtomic(path, manifest) {
|
|
338
|
-
ensureDir(dirname(path));
|
|
339
|
-
const tmp = `${path}.tmp.${process.pid}.${Math.random().toString(36).slice(2)}`;
|
|
340
|
-
writeFileSync(tmp, JSON.stringify(manifest, null, 2) + '\n', 'utf8');
|
|
341
|
-
renameSync(tmp, path);
|
|
342
|
-
}
|
|
343
226
|
// Project dirs — resolved to absolute real paths, must exist + be a directory
|
|
344
227
|
// on add/create, deduped by real path, stored in manifest order.
|
|
345
228
|
function resolveExistingProjectDir(dir) {
|
|
@@ -391,16 +274,11 @@ function generateProfileId(name) {
|
|
|
391
274
|
// (never for a bare last-used-at touch).
|
|
392
275
|
export function ensureRootProfile() {
|
|
393
276
|
return withProfileManifestLock(ROOT_PROFILE_ID, () => {
|
|
394
|
-
const
|
|
395
|
-
|
|
396
|
-
const manifest = manifestExists ? readManifestFile(manifestPath, ROOT_PROFILE_ID) : null;
|
|
397
|
-
if (manifestExists && manifest === null) {
|
|
398
|
-
throw general(`root profile manifest is unreadable: ${manifestPath}`);
|
|
399
|
-
}
|
|
400
|
-
if (manifest !== null) {
|
|
277
|
+
const existing = getStoredProfile(userScopeRoot(), ROOT_PROFILE_ID);
|
|
278
|
+
if (existing !== null) {
|
|
401
279
|
ensureDir(profileRoot(ROOT_PROFILE_ID));
|
|
402
280
|
ensureDir(profileMemoryDir(ROOT_PROFILE_ID));
|
|
403
|
-
return { profileId: ROOT_PROFILE_ID, manifest };
|
|
281
|
+
return { profileId: ROOT_PROFILE_ID, manifest: normalizeHome(ROOT_PROFILE_ID, existing.manifest) };
|
|
404
282
|
}
|
|
405
283
|
const next = {
|
|
406
284
|
schema_version: SCHEMA_VERSION,
|
|
@@ -412,6 +290,7 @@ export function ensureRootProfile() {
|
|
|
412
290
|
last_used_at: nowIso(),
|
|
413
291
|
};
|
|
414
292
|
scaffoldProfile(ROOT_PROFILE_ID, next);
|
|
293
|
+
insertStoredProfile(userScopeRoot(), { profileId: ROOT_PROFILE_ID, manifest: next }, profileRoot(ROOT_PROFILE_ID));
|
|
415
294
|
resetScopeCache();
|
|
416
295
|
return { profileId: ROOT_PROFILE_ID, manifest: next };
|
|
417
296
|
});
|
|
@@ -515,30 +394,23 @@ export function createProfile(name, projects = [], opts = {}) {
|
|
|
515
394
|
last_used_at: null,
|
|
516
395
|
};
|
|
517
396
|
scaffoldProfile(profileId, manifest);
|
|
397
|
+
insertStoredProfile(userScopeRoot(), { profileId, manifest }, profileRoot(profileId));
|
|
518
398
|
resetScopeCache();
|
|
519
399
|
return { profileId, manifest };
|
|
520
400
|
});
|
|
521
401
|
}
|
|
522
402
|
function requireExistingProfile(profileId) {
|
|
523
403
|
assertSafeProfileId(profileId);
|
|
524
|
-
if (
|
|
525
|
-
throw notFound(`profile not found: ${profileId}`, {
|
|
526
|
-
received: profileId,
|
|
527
|
-
next: 'Run `crtr profile list` to see available profiles.',
|
|
528
|
-
});
|
|
529
|
-
}
|
|
404
|
+
if (getStoredProfile(userScopeRoot(), profileId) === null)
|
|
405
|
+
throw notFound(`profile not found: ${profileId}`, { received: profileId, next: 'Run `crtr profile list` to see available profiles.' });
|
|
530
406
|
}
|
|
531
407
|
function mutateManifest(profileId, mutate) {
|
|
532
408
|
requireExistingProfile(profileId);
|
|
533
409
|
return withProfileManifestLock(profileId, () => {
|
|
534
|
-
const
|
|
535
|
-
|
|
536
|
-
if (current === null) {
|
|
410
|
+
const result = updateStoredProfile(userScopeRoot(), profileId, mutate);
|
|
411
|
+
if (result === null)
|
|
537
412
|
throw notFound(`profile not found: ${profileId}`, { received: profileId });
|
|
538
|
-
}
|
|
539
|
-
const next = mutate(current);
|
|
540
|
-
writeManifestAtomic(path, next);
|
|
541
|
-
return { profileId, manifest: next };
|
|
413
|
+
return { profileId, manifest: normalizeHome(profileId, result.manifest) };
|
|
542
414
|
});
|
|
543
415
|
}
|
|
544
416
|
export function updateProfileLastUsed(profileId) {
|
|
@@ -694,6 +566,8 @@ export function removeProfileProject(profileId, dir) {
|
|
|
694
566
|
export function deleteProfile(profileId) {
|
|
695
567
|
requireExistingProfile(profileId);
|
|
696
568
|
withProfileManifestLock(profileId, () => {
|
|
569
|
+
if (!deleteStoredProfile(userScopeRoot(), profileId))
|
|
570
|
+
throw notFound(`profile not found: ${profileId}`, { received: profileId });
|
|
697
571
|
rmSync(profileRoot(profileId), { recursive: true, force: true });
|
|
698
572
|
});
|
|
699
573
|
resetScopeCache();
|
|
@@ -12,6 +12,8 @@ import { existsSync, realpathSync } from 'node:fs';
|
|
|
12
12
|
import { basename, resolve as resolvePath, sep } from 'node:path';
|
|
13
13
|
import { createInterface } from 'node:readline/promises';
|
|
14
14
|
import { emitKeypressEvents } from 'node:readline';
|
|
15
|
+
import { initializeFreshScopedStore } from '../scoped-state/migrate.js';
|
|
16
|
+
import { userScopeRoot } from '../scope.js';
|
|
15
17
|
import { listProfiles, loadProfileManifest, resolveProfileOperand, updateProfileLastUsed, createProfile, addProfileProject, ensureRootProfile, ROOT_PROFILE_ID, } from './manifest.js';
|
|
16
18
|
import { getDefaultProfileId, setDefaultProfileId, clearDefaultProfile, } from './default-binding.js';
|
|
17
19
|
import { tildify } from '../fs-utils.js';
|
|
@@ -668,6 +670,7 @@ async function promptPickProfileOrCreate(candidates, cwd, exact, pinnedId, bindi
|
|
|
668
670
|
* default to the root profile and print the recovery instruction to STDERR —
|
|
669
671
|
* never stdout, which the caller may be piping. */
|
|
670
672
|
export async function selectProfileForCwd(cwd, explicitProfile, forcePicker = false) {
|
|
673
|
+
initializeFreshScopedStore({ kind: 'user', root: userScopeRoot() });
|
|
671
674
|
const resolvedCwd = resolveCwd(cwd);
|
|
672
675
|
const bindings = resolveUserKeybindings();
|
|
673
676
|
if (explicitProfile !== undefined && explicitProfile !== null && explicitProfile !== '') {
|