@north-light/crouter 0.3.227 → 0.3.229
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 +5 -5
- package/dist/api/client.js +3 -3
- package/dist/api/dto/broker-ops.d.ts +8 -0
- package/dist/api/dto/memory.d.ts +8 -7
- package/dist/api/dto/memory.js +2 -2
- package/dist/builtin-memory/04-base-worker.md +1 -1
- package/dist/builtin-memory/insights/init.md +5 -5
- package/dist/builtin-memory/internal/INDEX.md +1 -1
- package/dist/builtin-memory/internal/agent-shaping.md +11 -11
- package/dist/builtin-memory/internal/examples/INDEX.md +1 -1
- package/dist/builtin-memory/internal/memory-loading.md +6 -6
- package/dist/builtin-memory/internal/plugins.md +1 -1
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/memory-slash-commands.ts +50 -37
- package/dist/clients/attach/__tests__/pane-tag-successor.test.js +56 -0
- package/dist/clients/attach/__tests__/profile-files.test.js +21 -0
- package/dist/clients/attach/chrome/inbox-strip.js +11 -7
- package/dist/clients/attach/session/pane-tag.d.ts +28 -2
- package/dist/clients/attach/session/pane-tag.js +48 -22
- package/dist/clients/attach/session/profile-files.d.ts +6 -0
- package/dist/clients/attach/session/profile-files.js +44 -11
- package/dist/clients/attach/slash/dispatch.js +4 -7
- package/dist/clients/attach/viewer.js +588 -596
- package/dist/commands/__tests__/surface-reload-target.test.js +21 -0
- package/dist/commands/api-client.d.ts +3 -7
- package/dist/commands/api-client.js +7 -12
- package/dist/commands/memory/__tests__/command-selector-and-mutation-guards.test.js +292 -0
- package/dist/commands/memory/__tests__/repository-root-lint.test.js +146 -0
- package/dist/commands/memory/delete.js +51 -24
- package/dist/commands/memory/edit.js +50 -10
- package/dist/commands/memory/find.js +105 -56
- package/dist/commands/memory/history.js +51 -31
- package/dist/commands/memory/lint.d.ts +0 -9
- package/dist/commands/memory/lint.js +78 -322
- package/dist/commands/memory/list.d.ts +12 -4
- package/dist/commands/memory/list.js +64 -25
- package/dist/commands/memory/move.js +103 -73
- package/dist/commands/memory/origin.js +35 -5
- package/dist/commands/memory/read.d.ts +4 -0
- package/dist/commands/memory/read.js +132 -80
- package/dist/commands/memory/shared.d.ts +115 -25
- package/dist/commands/memory/shared.js +331 -74
- package/dist/commands/memory/write.js +72 -21
- package/dist/commands/memory.js +2 -2
- package/dist/commands/node/create.d.ts +1 -1
- package/dist/commands/node/create.js +1 -1
- package/dist/commands/node/inspect.js +1 -1
- package/dist/commands/node/lifecycle.js +5 -5
- package/dist/commands/pkg/market-manage.js +25 -24
- package/dist/commands/pkg/plugin-manage.d.ts +22 -6
- package/dist/commands/pkg/plugin-manage.js +118 -25
- package/dist/commands/pkg/shared.d.ts +8 -0
- package/dist/commands/pkg/shared.js +23 -20
- package/dist/commands/surface-reload.d.ts +5 -0
- package/dist/commands/surface-reload.js +9 -1
- package/dist/commands/sys/__tests__/migrate.test.js +1140 -22
- package/dist/commands/sys/__tests__/sync-project-guidance.test.js +218 -0
- package/dist/commands/sys/migrate.js +126 -140
- package/dist/commands/sys/panels/profiles-panel.d.ts +66 -0
- package/dist/commands/sys/panels/profiles-panel.js +599 -0
- package/dist/commands/sys/settings-shell.d.ts +4 -2
- package/dist/commands/sys/settings-shell.js +35 -4
- package/dist/commands/sys/settings.js +21 -5
- package/dist/commands/sys/sync-deps.d.ts +2 -0
- package/dist/commands/sys/sync-deps.js +26 -15
- package/dist/commands/sys/sync-project-guidance.js +228 -145
- package/dist/commands/sys/sync-skills.js +28 -17
- package/dist/commands/sys/update.js +11 -3
- package/dist/core/__tests__/canvas-inbox-watcher-hold.test.js +15 -2
- package/dist/core/__tests__/config-change-delta.test.js +106 -0
- package/dist/core/__tests__/context-intro.test.js +13 -9
- package/dist/core/__tests__/daemon-boot.test.js +22 -16
- package/dist/core/__tests__/fixtures/memory-slash-live-probe.js +5 -1
- package/dist/core/__tests__/human-deliver.test.js +19 -0
- package/dist/core/__tests__/inline-memory-refs.test.js +50 -46
- package/dist/core/__tests__/{serial → integration}/broker-fork-seam.test.js +1 -1
- package/dist/core/__tests__/{serial → integration}/broker-sdk-wiring.test.js +1 -1
- package/dist/core/__tests__/{serial → integration}/broker-snapshot-history.test.js +1 -1
- package/dist/core/__tests__/{serial → integration}/command-plugins.test.js +94 -3
- package/dist/core/__tests__/{serial → integration}/deferred-no-wake.test.js +1 -1
- package/dist/core/__tests__/{serial → integration}/flagship-lifecycle.test.js +13 -27
- package/dist/core/__tests__/{serial → integration}/host-teardown-process-group.test.js +1 -1
- package/dist/core/__tests__/{serial → integration}/human-deliver-e2e.test.js +1 -1
- package/dist/core/__tests__/{live-mutation-verbs.test.js → integration/live-mutation-verbs.test.js} +22 -33
- package/dist/core/__tests__/{serial → integration}/live-mutation.test.js +21 -41
- package/dist/core/__tests__/integration/refresh-stall-recycle.test.d.ts +1 -0
- package/dist/core/__tests__/{serial → integration}/refresh-stall-recycle.test.js +1 -1
- package/dist/core/__tests__/integration/revive.test.d.ts +1 -0
- package/dist/core/__tests__/{serial → integration}/revive.test.js +38 -19
- package/dist/core/__tests__/integration/spawn-root.test.d.ts +1 -0
- package/dist/core/__tests__/{serial → integration}/spawn-root.test.js +104 -1
- package/dist/core/__tests__/integration/subscription-delivery.test.d.ts +1 -0
- package/dist/core/__tests__/{serial → integration}/subscription-delivery.test.js +1 -1
- package/dist/core/__tests__/integration/tmux-surface.test.d.ts +1 -0
- package/dist/core/__tests__/{serial → integration}/tmux-surface.test.js +1 -1
- package/dist/core/__tests__/integration/worktree-land.test.d.ts +1 -0
- package/dist/core/__tests__/integration/worktree-land.test.js +400 -0
- package/dist/core/__tests__/integration/worktree-reap.test.d.ts +1 -0
- package/dist/core/__tests__/{serial/worktree.test.js → integration/worktree-reap.test.js} +6 -338
- package/dist/core/__tests__/kickoff.test.js +16 -5
- package/dist/core/__tests__/memory-resolver-precedence.test.js +122 -91
- package/dist/core/__tests__/nested-store-discovery.test.js +5 -3
- package/dist/core/__tests__/on-read-crouter-home-fence.test.js +2 -1
- package/dist/core/__tests__/on-read-dedup-resume.test.js +39 -27
- package/dist/core/__tests__/on-read-nested-store.test.js +19 -13
- package/dist/core/__tests__/profile-project-memory-delivery.test.js +138 -44
- package/dist/core/__tests__/repository-association.test.d.ts +1 -0
- package/dist/core/__tests__/repository-association.test.js +153 -0
- package/dist/core/__tests__/repository-root-identity.test.d.ts +1 -0
- package/dist/core/__tests__/repository-root-identity.test.js +219 -0
- package/dist/core/__tests__/review-model-floor.test.js +12 -4
- package/dist/core/__tests__/seam/memory-slash-node-relative-inventory.test.js +27 -11
- package/dist/core/__tests__/warm-claim-preference-snapshot.test.d.ts +1 -0
- package/dist/core/__tests__/warm-claim-preference-snapshot.test.js +40 -0
- package/dist/core/canvas/canvas.d.ts +3 -0
- package/dist/core/canvas/canvas.js +30 -10
- package/dist/core/canvas/db.js +28 -1
- package/dist/core/canvas/paths.d.ts +4 -6
- package/dist/core/canvas/paths.js +8 -6
- package/dist/core/canvas/render-source.js +2 -2
- package/dist/core/canvas/types.d.ts +9 -13
- package/dist/core/config.d.ts +3 -3
- package/dist/core/config.js +3 -3
- package/dist/core/exclusive-lock.d.ts +2 -0
- package/dist/core/exclusive-lock.js +21 -0
- package/dist/core/git.d.ts +0 -1
- package/dist/core/git.js +0 -3
- package/dist/core/human/__tests__/integration/inbox-core.test.d.ts +1 -0
- package/dist/core/human/feedback-companion.js +3 -0
- package/dist/core/human/scan.js +8 -1
- package/dist/core/keybindings/catalog.d.ts +2 -2
- package/dist/core/keybindings/catalog.js +2 -1
- package/dist/core/memory/doc-link-grammar.js +2 -2
- package/dist/core/memory/history.d.ts +24 -0
- package/dist/core/memory/history.js +66 -1
- package/dist/core/memory/identity.d.ts +65 -0
- package/dist/core/memory/identity.js +185 -0
- package/dist/core/memory/inline-ref-guidance.d.ts +1 -1
- package/dist/core/memory/inline-ref-guidance.js +1 -1
- package/dist/core/memory/inline-ref-inventory.d.ts +3 -10
- package/dist/core/memory/inline-ref-inventory.js +30 -62
- package/dist/core/memory/lint.d.ts +129 -0
- package/dist/core/memory/lint.js +517 -0
- package/dist/core/memory/project-namespace.d.ts +31 -0
- package/dist/core/memory/project-namespace.js +85 -0
- package/dist/core/memory/repository-association.d.ts +31 -0
- package/dist/core/memory/repository-association.js +129 -0
- package/dist/core/memory/tree.d.ts +39 -0
- package/dist/core/memory/tree.js +93 -0
- package/dist/core/memory-resolver.d.ts +193 -90
- package/dist/core/memory-resolver.js +461 -375
- package/dist/core/nested-stores.js +6 -13
- package/dist/core/profiles/select.d.ts +4 -1
- package/dist/core/profiles/select.js +108 -48
- package/dist/core/review/__tests__/capture-origin.test.js +2 -2
- package/dist/core/review/__tests__/stage-identity.test.js +2 -2
- package/dist/core/review/companion.js +11 -2
- package/dist/core/runtime/bearings.d.ts +2 -2
- package/dist/core/runtime/bearings.js +3 -3
- package/dist/core/runtime/broker/daemon-ops.d.ts +2 -2
- package/dist/core/runtime/broker/rebind.js +5 -0
- package/dist/core/runtime/broker-extension-render.d.ts +7 -3
- package/dist/core/runtime/broker-extension-render.js +10 -5
- package/dist/core/runtime/broker-persona-guidance.d.ts +19 -5
- package/dist/core/runtime/broker-persona-guidance.js +122 -27
- package/dist/core/runtime/deliver-live.d.ts +16 -4
- package/dist/core/runtime/deliver-live.js +29 -15
- package/dist/core/runtime/kickoff.d.ts +3 -3
- package/dist/core/runtime/kickoff.js +8 -16
- package/dist/core/runtime/launch.js +1 -1
- package/dist/core/runtime/lifecycle.js +2 -3
- package/dist/core/runtime/nodes.d.ts +3 -4
- package/dist/core/runtime/nodes.js +3 -4
- package/dist/core/runtime/persona.d.ts +8 -12
- package/dist/core/runtime/persona.js +24 -96
- package/dist/core/runtime/promote.d.ts +2 -2
- package/dist/core/runtime/promote.js +8 -21
- package/dist/core/runtime/revive.js +20 -17
- package/dist/core/runtime/spawn.js +18 -7
- package/dist/core/runtime/tmux-bindings.js +2 -3
- package/dist/core/runtime/warm-pool.js +3 -4
- package/dist/core/scope.js +2 -0
- package/dist/core/self-update.d.ts +0 -2
- package/dist/core/self-update.js +2 -35
- package/dist/core/substrate/__tests__/surface-match-memory-read.test.d.ts +1 -0
- package/dist/core/substrate/__tests__/surface-match-memory-read.test.js +28 -0
- package/dist/core/substrate/index.d.ts +2 -2
- package/dist/core/substrate/index.js +1 -1
- package/dist/core/substrate/injected-store.d.ts +43 -27
- package/dist/core/substrate/injected-store.js +208 -104
- package/dist/core/substrate/listings.d.ts +19 -12
- package/dist/core/substrate/listings.js +75 -52
- package/dist/core/substrate/on-read-node.d.ts +4 -7
- package/dist/core/substrate/on-read-node.js +6 -8
- package/dist/core/substrate/on-read.d.ts +22 -25
- package/dist/core/substrate/on-read.js +103 -147
- package/dist/core/substrate/render-node.d.ts +4 -7
- package/dist/core/substrate/render-node.js +5 -7
- package/dist/core/substrate/render.d.ts +21 -3
- package/dist/core/substrate/render.js +291 -223
- package/dist/core/substrate/schema.d.ts +1 -13
- package/dist/core/substrate/schema.js +5 -40
- package/dist/core/substrate/session-cache.d.ts +14 -4
- package/dist/core/substrate/session-cache.js +40 -22
- package/dist/core/substrate/surface-match.d.ts +9 -7
- package/dist/core/substrate/surface-match.js +26 -25
- package/dist/daemon/__tests__/helpers/source-daemon.d.ts +30 -0
- package/dist/daemon/__tests__/helpers/source-daemon.js +174 -0
- package/dist/daemon/__tests__/integration/migration-startup.test.d.ts +1 -0
- package/dist/daemon/__tests__/integration/migration-startup.test.js +97 -0
- package/dist/daemon/api/__tests__/bridge-heartbeat.test.js +21 -5
- package/dist/daemon/api/handlers/broker-ops.js +21 -16
- package/dist/daemon/api/handlers/memory.js +2 -0
- package/dist/daemon/crtrd.js +2 -0
- package/dist/daemon/human/finish.js +8 -1
- package/dist/daemon/manage.d.ts +0 -1
- package/dist/daemon/manage.js +7 -16
- package/dist/daemon/startup-policy.d.ts +1 -0
- package/dist/daemon/startup-policy.js +1 -0
- package/dist/migrations/001-surfaces-frontmatter.js +21 -109
- package/dist/migrations/002-profile-project-memory.js +1 -0
- package/dist/migrations/003-repository-root-memory-identity/front-door.d.ts +26 -0
- package/dist/migrations/003-repository-root-memory-identity/front-door.js +231 -0
- package/dist/migrations/003-repository-root-memory-identity/index.d.ts +2 -0
- package/dist/migrations/003-repository-root-memory-identity/index.js +513 -0
- package/dist/migrations/003-repository-root-memory-identity/references.d.ts +95 -0
- package/dist/migrations/003-repository-root-memory-identity/references.js +469 -0
- package/dist/migrations/003-repository-root-memory-identity/repository-facts.d.ts +39 -0
- package/dist/migrations/003-repository-root-memory-identity/repository-facts.js +349 -0
- package/dist/migrations/__tests__/activation-concurrency.test.d.ts +1 -0
- package/dist/migrations/__tests__/activation-concurrency.test.js +145 -0
- package/dist/migrations/__tests__/activation.test.d.ts +1 -0
- package/dist/migrations/__tests__/activation.test.js +149 -0
- package/dist/migrations/__tests__/deletion-and-root-declaration.test.d.ts +1 -0
- package/dist/migrations/__tests__/deletion-and-root-declaration.test.js +149 -0
- package/dist/migrations/activation.d.ts +16 -0
- package/dist/migrations/activation.js +78 -0
- package/dist/migrations/convergent.d.ts +14 -3
- package/dist/migrations/convergent.js +21 -10
- package/dist/migrations/corpus.d.ts +78 -0
- package/dist/migrations/corpus.js +497 -0
- package/dist/migrations/frontmatter-splice.d.ts +15 -0
- package/dist/migrations/frontmatter-splice.js +176 -0
- package/dist/migrations/registry.d.ts +6 -1
- package/dist/migrations/registry.js +7 -2
- package/dist/migrations/runner.d.ts +41 -0
- package/dist/migrations/runner.js +81 -0
- package/dist/migrations/types.d.ts +148 -9
- package/dist/migrations/types.js +9 -2
- package/dist/pi-extensions/__tests__/canvas-context-intro.test.js +225 -17
- package/dist/pi-extensions/__tests__/canvas-goal-capture-envelope.test.js +11 -3
- package/dist/pi-extensions/canvas-context-intro.d.ts +3 -5
- package/dist/pi-extensions/canvas-context-intro.js +50 -46
- package/dist/pi-extensions/canvas-doc-substrate.d.ts +1 -8
- package/dist/pi-extensions/canvas-doc-substrate.js +55 -122
- package/dist/pi-extensions/canvas-stophook.js +6 -13
- package/dist/shared/generated-context.d.ts +0 -3
- package/dist/shared/generated-context.js +0 -57
- package/dist/shared/tool-groups.js +2 -3
- package/dist/types.d.ts +8 -11
- package/dist/types.js +4 -31
- package/package.json +5 -4
- package/runtime.lock.json +2 -2
- package/dist/builtin-memory/05-kinds/design/00-base.md +0 -17
- package/dist/builtin-memory/05-kinds/design/01-orchestrator.md +0 -15
- package/dist/builtin-memory/05-kinds/design/design-contract.md +0 -19
- package/dist/builtin-memory/05-kinds/developer/00-base.md +0 -17
- package/dist/builtin-memory/05-kinds/developer/01-orchestrator.md +0 -15
- package/dist/builtin-memory/05-kinds/plan/00-base.md +0 -17
- package/dist/builtin-memory/05-kinds/plan/01-orchestrator.md +0 -17
- package/dist/builtin-memory/05-kinds/plan/plan-contract.md +0 -28
- package/dist/builtin-memory/05-kinds/plan/reviewers/architecture-fit.md +0 -15
- package/dist/builtin-memory/05-kinds/plan/reviewers/code-smells.md +0 -15
- package/dist/builtin-memory/05-kinds/plan/reviewers/lens-contract.md +0 -13
- package/dist/builtin-memory/05-kinds/plan/reviewers/pattern-consistency.md +0 -17
- package/dist/builtin-memory/05-kinds/plan/reviewers/requirements-coverage.md +0 -17
- package/dist/builtin-memory/05-kinds/plan/reviewers/security.md +0 -17
- package/dist/builtin-memory/05-kinds/spec/00-base.md +0 -17
- package/dist/builtin-memory/05-kinds/spec/01-orchestrator.md +0 -15
- package/dist/builtin-memory/05-kinds/spec/requirements.md +0 -15
- package/dist/builtin-memory/design/guide.md +0 -35
- package/dist/builtin-memory/design/roadmap.md +0 -21
- package/dist/builtin-memory/development.md +0 -113
- package/dist/builtin-memory/plan/roadmap.md +0 -25
- package/dist/builtin-memory/spec/guide.md +0 -53
- package/dist/builtin-memory/spec/requirements.md +0 -29
- package/dist/builtin-memory/spec/roadmap.md +0 -36
- package/dist/builtin-memory/testing.md +0 -39
- /package/dist/api/__tests__/{serial → integration}/client.test.d.ts +0 -0
- /package/dist/api/__tests__/{serial → integration}/client.test.js +0 -0
- /package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/__tests__/{serial → integration}/provider-rotation.test.ts +0 -0
- /package/dist/clients/{inbox/__tests__/serial/inbox-controller.test.d.ts → attach/__tests__/pane-tag-successor.test.d.ts} +0 -0
- /package/dist/clients/{inbox/__tests__/serial/mount-panel.test.d.ts → attach/__tests__/profile-files.test.d.ts} +0 -0
- /package/dist/{core/__tests__/live-mutation-verbs.test.d.ts → clients/inbox/__tests__/integration/inbox-controller.test.d.ts} +0 -0
- /package/dist/clients/inbox/__tests__/{serial → integration}/inbox-controller.test.js +0 -0
- /package/dist/{core/__tests__/serial/broker-fork-seam.test.d.ts → clients/inbox/__tests__/integration/mount-panel.test.d.ts} +0 -0
- /package/dist/clients/inbox/__tests__/{serial → integration}/mount-panel.test.js +0 -0
- /package/dist/{core/__tests__/serial/broker-sdk-wiring.test.d.ts → commands/__tests__/surface-reload-target.test.d.ts} +0 -0
- /package/dist/{core/__tests__/serial/broker-snapshot-history.test.d.ts → commands/memory/__tests__/command-selector-and-mutation-guards.test.d.ts} +0 -0
- /package/dist/{core/__tests__/serial/command-plugins.test.d.ts → commands/memory/__tests__/repository-root-lint.test.d.ts} +0 -0
- /package/dist/{core/__tests__/serial/deferred-no-wake.test.d.ts → commands/sys/__tests__/sync-project-guidance.test.d.ts} +0 -0
- /package/dist/core/__tests__/{serial/flagship-lifecycle.test.d.ts → config-change-delta.test.d.ts} +0 -0
- /package/dist/core/__tests__/{serial/host-teardown-process-group.test.d.ts → integration/broker-fork-seam.test.d.ts} +0 -0
- /package/dist/core/__tests__/{serial/human-deliver-e2e.test.d.ts → integration/broker-sdk-wiring.test.d.ts} +0 -0
- /package/dist/core/__tests__/{serial/live-mutation.test.d.ts → integration/broker-snapshot-history.test.d.ts} +0 -0
- /package/dist/core/__tests__/{serial/refresh-stall-recycle.test.d.ts → integration/command-plugins.test.d.ts} +0 -0
- /package/dist/core/__tests__/{serial/revive.test.d.ts → integration/deferred-no-wake.test.d.ts} +0 -0
- /package/dist/core/__tests__/{serial/spawn-root.test.d.ts → integration/flagship-lifecycle.test.d.ts} +0 -0
- /package/dist/core/__tests__/{serial/subscription-delivery.test.d.ts → integration/host-teardown-process-group.test.d.ts} +0 -0
- /package/dist/core/__tests__/{serial/tmux-surface.test.d.ts → integration/human-deliver-e2e.test.d.ts} +0 -0
- /package/dist/core/__tests__/{serial/worktree.test.d.ts → integration/live-mutation-verbs.test.d.ts} +0 -0
- /package/dist/core/{human/__tests__/serial/inbox-core.test.d.ts → __tests__/integration/live-mutation.test.d.ts} +0 -0
- /package/dist/core/human/__tests__/{serial → integration}/inbox-core.test.js +0 -0
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
// flat ancestor+profile stack (on-read delivery finds nested stores through
|
|
7
7
|
// its own read-file walk instead).
|
|
8
8
|
//
|
|
9
|
-
// Two discovery modes per owner dir,
|
|
9
|
+
// Two discovery modes per owner dir, each under its own 500 ms budget:
|
|
10
10
|
// • Git root — `git ls-files` over tracked+untracked (respecting .gitignore),
|
|
11
11
|
// so junk dirs and ignored trees cost nothing and embedded repos are
|
|
12
12
|
// auto-excluded (ls-files does not descend into submodules).
|
|
@@ -55,12 +55,7 @@ export function descendantStoreRoots(ancestorRoots) {
|
|
|
55
55
|
ownerSeen.add(real);
|
|
56
56
|
owners.push(owner);
|
|
57
57
|
}
|
|
58
|
-
const deadline = Date.now() + TIME_BUDGET_MS;
|
|
59
|
-
let warned = false;
|
|
60
58
|
const tripBudget = (owner) => {
|
|
61
|
-
if (warned)
|
|
62
|
-
return;
|
|
63
|
-
warned = true;
|
|
64
59
|
warn(`memory: nested-store discovery under ${owner} exceeded its ${TIME_BUDGET_MS}ms budget — nested stores may be missing from this listing; register deep stores explicitly (add their dirs to the selected profile's projects)`);
|
|
65
60
|
};
|
|
66
61
|
const found = [];
|
|
@@ -72,17 +67,15 @@ export function descendantStoreRoots(ancestorRoots) {
|
|
|
72
67
|
foundSeen.add(real);
|
|
73
68
|
found.push(storeRoot);
|
|
74
69
|
};
|
|
70
|
+
// Each owner gets the full budget: owners are independent trees, so one
|
|
71
|
+
// pathological tree must neither starve the owners after it nor pin the
|
|
72
|
+
// warning on whichever owner happened to be next when a shared clock ran out.
|
|
75
73
|
for (const owner of owners) {
|
|
76
|
-
const remaining = deadline - Date.now();
|
|
77
|
-
if (remaining <= 0) {
|
|
78
|
-
tripBudget(owner);
|
|
79
|
-
break;
|
|
80
|
-
}
|
|
81
74
|
if (pathExists(join(owner, '.git'))) {
|
|
82
|
-
collectGitStores(owner, add,
|
|
75
|
+
collectGitStores(owner, add, TIME_BUDGET_MS, () => tripBudget(owner));
|
|
83
76
|
}
|
|
84
77
|
else {
|
|
85
|
-
collectWalkStores(owner, add,
|
|
78
|
+
collectWalkStores(owner, add, Date.now() + TIME_BUDGET_MS, () => tripBudget(owner));
|
|
86
79
|
}
|
|
87
80
|
}
|
|
88
81
|
cache.set(key, found);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type ProfileEntry } from './manifest.js';
|
|
2
2
|
import { type BindingId, type BindingResolution, type RawTerminalInput } from '../keybindings/index.js';
|
|
3
|
-
declare const PROFILE_MENU_ACTIONS: readonly ["crtr.profile.menu.abort", "crtr.profile.menu.up", "crtr.profile.menu.down", "crtr.profile.menu.select", "crtr.profile.menu.accept-default", "crtr.profile.menu.slot.1", "crtr.profile.menu.slot.2", "crtr.profile.menu.slot.3", "crtr.profile.menu.slot.4", "crtr.profile.menu.slot.5", "crtr.profile.menu.slot.6", "crtr.profile.menu.slot.7", "crtr.profile.menu.slot.8", "crtr.profile.menu.slot.9", "crtr.profile.menu.create", "crtr.profile.menu.search-existing", "crtr.profile.menu.use-root", "crtr.profile.menu.set-default", "crtr.profile.menu.add-directory", "crtr.profile.menu.unpin"];
|
|
3
|
+
declare const PROFILE_MENU_ACTIONS: readonly ["crtr.profile.menu.abort", "crtr.profile.menu.up", "crtr.profile.menu.down", "crtr.profile.menu.select", "crtr.profile.menu.accept-default", "crtr.profile.menu.slot.1", "crtr.profile.menu.slot.2", "crtr.profile.menu.slot.3", "crtr.profile.menu.slot.4", "crtr.profile.menu.slot.5", "crtr.profile.menu.slot.6", "crtr.profile.menu.slot.7", "crtr.profile.menu.slot.8", "crtr.profile.menu.slot.9", "crtr.profile.menu.create", "crtr.profile.menu.search-existing", "crtr.profile.menu.use-root", "crtr.profile.menu.set-default", "crtr.profile.menu.add-directory", "crtr.profile.menu.unpin", "crtr.profile.menu.manage"];
|
|
4
4
|
declare const PROFILE_SEARCH_ACTIONS: readonly ["crtr.profile.search.abort", "crtr.profile.search.back", "crtr.profile.search.pick", "crtr.profile.search.up", "crtr.profile.search.down", "crtr.profile.search.delete"];
|
|
5
5
|
export declare function resolveProfileMenuAction(bindings: BindingResolution<BindingId>, raw: RawTerminalInput): (typeof PROFILE_MENU_ACTIONS)[number] | null;
|
|
6
6
|
export declare function resolveProfileSearchAction(bindings: BindingResolution<BindingId>, raw: RawTerminalInput): (typeof PROFILE_SEARCH_ACTIONS)[number] | null;
|
|
@@ -11,6 +11,9 @@ export declare function resolveProfileSearchAction(bindings: BindingResolution<B
|
|
|
11
11
|
export declare function profileCoversCwd(entry: ProfileEntry, cwd: string): boolean;
|
|
12
12
|
/** Resolve the headless selector against existing state without changing it. */
|
|
13
13
|
export declare function selectProfileForCwdReadOnly(cwd: string): string;
|
|
14
|
+
/** Collapse the home prefix to `~` so project paths read short. Exported so the
|
|
15
|
+
* Profiles settings panel prints a project dir exactly as this menu does. */
|
|
16
|
+
export declare function tildify(p: string): string;
|
|
14
17
|
/** Select the profile a node about to boot at `cwd` should run under.
|
|
15
18
|
*
|
|
16
19
|
* 1. `explicitProfile` present → resolve id/name via `loadProfileManifest`. If
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
// root decision when nothing covers. This is the ONLY place that decision
|
|
8
8
|
// runs; front-door.ts/
|
|
9
9
|
// spawn.ts call it, never re-derive it.
|
|
10
|
+
import { spawnSync } from 'node:child_process';
|
|
10
11
|
import { existsSync, realpathSync } from 'node:fs';
|
|
11
12
|
import { homedir } from 'node:os';
|
|
12
13
|
import { basename, resolve as resolvePath, sep } from 'node:path';
|
|
@@ -15,6 +16,8 @@ import { emitKeypressEvents } from 'node:readline';
|
|
|
15
16
|
import { listProfiles, loadProfileManifest, updateProfileLastUsed, createProfile, addProfileProject, ensureRootProfile, ROOT_PROFILE_ID, } from './manifest.js';
|
|
16
17
|
import { getDefaultProfileId, setDefaultProfileId, clearDefaultProfile, } from './default-binding.js';
|
|
17
18
|
import { stdoutColor } from '../output.js';
|
|
19
|
+
import { inTmux } from '../runtime/placement-tmux.js';
|
|
20
|
+
import { surfaceTmuxStyleArgs } from '../runtime/surface-bg.js';
|
|
18
21
|
import { formatBinding, matchesTerminalInput, resolveUserKeybindings, } from '../keybindings/index.js';
|
|
19
22
|
const PROFILE_MENU_ACTIONS = [
|
|
20
23
|
'crtr.profile.menu.abort', 'crtr.profile.menu.up', 'crtr.profile.menu.down',
|
|
@@ -24,6 +27,7 @@ const PROFILE_MENU_ACTIONS = [
|
|
|
24
27
|
'crtr.profile.menu.slot.7', 'crtr.profile.menu.slot.8', 'crtr.profile.menu.slot.9',
|
|
25
28
|
'crtr.profile.menu.create', 'crtr.profile.menu.search-existing', 'crtr.profile.menu.use-root',
|
|
26
29
|
'crtr.profile.menu.set-default', 'crtr.profile.menu.add-directory', 'crtr.profile.menu.unpin',
|
|
30
|
+
'crtr.profile.menu.manage',
|
|
27
31
|
];
|
|
28
32
|
const PROFILE_SEARCH_ACTIONS = [
|
|
29
33
|
'crtr.profile.search.abort', 'crtr.profile.search.back', 'crtr.profile.search.pick',
|
|
@@ -133,8 +137,9 @@ const accent = stdoutColor.cyan;
|
|
|
133
137
|
function key(k) {
|
|
134
138
|
return accent(bold(k));
|
|
135
139
|
}
|
|
136
|
-
/** Collapse the home prefix to `~` so project paths read short.
|
|
137
|
-
|
|
140
|
+
/** Collapse the home prefix to `~` so project paths read short. Exported so the
|
|
141
|
+
* Profiles settings panel prints a project dir exactly as this menu does. */
|
|
142
|
+
export function tildify(p) {
|
|
138
143
|
const home = homedir();
|
|
139
144
|
if (p === home)
|
|
140
145
|
return '~';
|
|
@@ -305,6 +310,34 @@ function runMenu(bindings, title, subtitle, rows, opts = {}) {
|
|
|
305
310
|
draw();
|
|
306
311
|
});
|
|
307
312
|
}
|
|
313
|
+
// ---------------------------------------------------------------------------
|
|
314
|
+
// The profile manager. `v` on either selection gate opens the Profiles page of
|
|
315
|
+
// `crtr sys settings` in a tmux popup: this menu is a CHOOSER filtered to cwd,
|
|
316
|
+
// while that page is the whole map — every profile, every directory each one
|
|
317
|
+
// owns, every pin. The popup runs to completion with the raw-mode menu already
|
|
318
|
+
// torn down (runMenu cleans up before resolving an action), and the caller then
|
|
319
|
+
// re-runs the whole selector, so a directory just adopted or a default just
|
|
320
|
+
// pinned decides the menu you come back to.
|
|
321
|
+
// ---------------------------------------------------------------------------
|
|
322
|
+
/** Open the profiles page in a tmux popup and block until it closes. False when
|
|
323
|
+
* there is no tmux to host it — possible only on the `crtr node new` path, as
|
|
324
|
+
* the front door requires tmux before it ever selects — after printing the
|
|
325
|
+
* pointer, so the caller can simply redraw its menu. */
|
|
326
|
+
function openProfileManager(cwd) {
|
|
327
|
+
if (!inTmux()) {
|
|
328
|
+
process.stdout.write(` ${dim('the profile manager needs tmux \u2014 run `crtr sys settings` instead')}\n`);
|
|
329
|
+
return false;
|
|
330
|
+
}
|
|
331
|
+
spawnSync('tmux', [
|
|
332
|
+
'display-popup', '-E', '-T', ' profiles ', '-w', '90%', '-h', '85%', '-d', cwd,
|
|
333
|
+
...surfaceTmuxStyleArgs(),
|
|
334
|
+
'crtr sys settings --page profiles',
|
|
335
|
+
], { stdio: 'inherit' });
|
|
336
|
+
return true;
|
|
337
|
+
}
|
|
338
|
+
/** The gate answering "the user managed their profiles" — every prior reading of
|
|
339
|
+
* this directory is stale, so `selectProfileForCwd` decides again from the top. */
|
|
340
|
+
const MANAGED = Symbol('profile-manager-ran');
|
|
308
341
|
/** The trailing readline prompt: ` › <dim hint> `. */
|
|
309
342
|
function caret(hint) {
|
|
310
343
|
return ` ${accent('\u203a')} ${dim(hint)} `;
|
|
@@ -484,7 +517,17 @@ async function promptCreateOrRoot(cwd, bindings) {
|
|
|
484
517
|
for (;;) {
|
|
485
518
|
const res = await runMenu(bindings, 'No profile covers this directory', undefined, rows, {
|
|
486
519
|
initialIndex: 2,
|
|
520
|
+
actionBindingIds: ['crtr.profile.menu.manage'],
|
|
521
|
+
hint: `${formatBinding(bindings, 'crtr.profile.menu.manage')}=manage profiles`,
|
|
487
522
|
});
|
|
523
|
+
// Managing may have given this directory an owner — re-decide from the top
|
|
524
|
+
// rather than re-showing a menu the manager just made wrong. With no tmux to
|
|
525
|
+
// host the manager nothing changed, so fall through to a redraw.
|
|
526
|
+
if (res.action === 'crtr.profile.menu.manage') {
|
|
527
|
+
if (openProfileManager(cwd))
|
|
528
|
+
return MANAGED;
|
|
529
|
+
continue;
|
|
530
|
+
}
|
|
488
531
|
if (res.index === 0) {
|
|
489
532
|
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
490
533
|
try {
|
|
@@ -559,7 +602,7 @@ async function promptPickProfileOrCreate(candidates, cwd, exact, pinnedId, bindi
|
|
|
559
602
|
rows.push({ label: dim('create a new profile here'), detail: '', bindingId: 'crtr.profile.menu.create' });
|
|
560
603
|
// Row-scoped actions pin the highlighted profile, widen its purview (hidden
|
|
561
604
|
// when candidates already claim cwd exactly), or clear an existing pin.
|
|
562
|
-
const actionBindingIds = ['crtr.profile.menu.set-default'];
|
|
605
|
+
const actionBindingIds = ['crtr.profile.menu.set-default', 'crtr.profile.menu.manage'];
|
|
563
606
|
if (!exact)
|
|
564
607
|
actionBindingIds.push('crtr.profile.menu.add-directory');
|
|
565
608
|
if (pinned !== null)
|
|
@@ -569,9 +612,18 @@ async function promptPickProfileOrCreate(candidates, cwd, exact, pinnedId, bindi
|
|
|
569
612
|
hintParts.push(`${formatBinding(bindings, 'crtr.profile.menu.add-directory')}=add dir here`);
|
|
570
613
|
if (pinned !== null)
|
|
571
614
|
hintParts.push(`${formatBinding(bindings, 'crtr.profile.menu.unpin')}=unpin`);
|
|
615
|
+
hintParts.push(`${formatBinding(bindings, 'crtr.profile.menu.manage')}=manage profiles`);
|
|
572
616
|
const res = await runMenu(bindings, exact ? 'Choose a profile' : 'Select a profile', exact
|
|
573
617
|
? 'Several profiles claim this directory as their project'
|
|
574
618
|
: 'This directory falls under existing profile(s)', rows, { actionBindingIds, hint: hintParts.join(' ') });
|
|
619
|
+
// The manager can adopt dirs, pin a default, create or delete profiles — every
|
|
620
|
+
// row here may be stale, so the caller re-resolves from the top. Without tmux
|
|
621
|
+
// nothing changed: re-show this same menu.
|
|
622
|
+
if (res.action === 'crtr.profile.menu.manage') {
|
|
623
|
+
return openProfileManager(cwd)
|
|
624
|
+
? MANAGED
|
|
625
|
+
: await promptPickProfileOrCreate(candidates, cwd, exact, pinnedId, bindings);
|
|
626
|
+
}
|
|
575
627
|
// The create row is last; selecting it (Enter on it, or `c`) creates here.
|
|
576
628
|
if (res.index >= ordered.length) {
|
|
577
629
|
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
@@ -640,51 +692,59 @@ export async function selectProfileForCwd(cwd, explicitProfile, forcePicker = fa
|
|
|
640
692
|
updateProfileLastUsed(entry.profileId);
|
|
641
693
|
return entry.profileId;
|
|
642
694
|
}
|
|
643
|
-
|
|
644
|
-
//
|
|
645
|
-
//
|
|
646
|
-
//
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
695
|
+
// Looped for the one gate that changes the world before it answers: `v` opens
|
|
696
|
+
// the profile manager, which can adopt this directory, pin a default, or
|
|
697
|
+
// create a profile — so the decision is taken again from the top rather than
|
|
698
|
+
// resumed inside a menu the manager just invalidated.
|
|
699
|
+
for (;;) {
|
|
700
|
+
const { covering, exact, pinnedId, pinned } = profileSelectionState(resolvedCwd);
|
|
701
|
+
// A per-cwd pinned default (set from the menu with `d`) is the user's
|
|
702
|
+
// explicit "default to THIS profile HERE". It outranks both the exact-single
|
|
703
|
+
// auto-pick and global-MRU, so long as it still covers cwd; a stale pin
|
|
704
|
+
// (profile deleted, or its dir removed from purview) is self-healed away.
|
|
705
|
+
if (pinnedId !== null && pinned === null)
|
|
706
|
+
clearDefaultProfile(resolvedCwd);
|
|
707
|
+
// A valid pin decides it outright and STOPS ASKING — the whole point of
|
|
708
|
+
// setting a default. Auto-pick it silently: the crouton banner the viewer
|
|
709
|
+
// paints a beat later shows the active profile and the `crtr --pick-profile`
|
|
710
|
+
// hint, so a boot-time breadcrumb here would just be redundant.
|
|
711
|
+
// `crtr --pick-profile` (forcePicker) re-opens the menu to re-pin/unpin.
|
|
712
|
+
if (pinned !== null && !forcePicker) {
|
|
713
|
+
updateProfileLastUsed(pinned.profileId);
|
|
714
|
+
return pinned.profileId;
|
|
715
|
+
}
|
|
716
|
+
// Exactly one profile's project dir IS cwd — unambiguous project root, use it
|
|
717
|
+
// silently, never a prompt. (Several exact claims fall through to the menu.)
|
|
718
|
+
// Suppressed under forcePicker so `--pick-profile` can pin even a lone owner.
|
|
719
|
+
if (!forcePicker && pinned === null && exact.length === 1) {
|
|
720
|
+
updateProfileLastUsed(exact[0].profileId);
|
|
721
|
+
return exact[0].profileId;
|
|
722
|
+
}
|
|
723
|
+
// Non-interactive: cannot prompt. Prefer an exact claimant, else any covering
|
|
724
|
+
// profile (both MRU), else root.
|
|
725
|
+
if (!isInteractive()) {
|
|
726
|
+
const pool = exact.length > 0 ? exact : covering;
|
|
727
|
+
if (pool.length > 0) {
|
|
728
|
+
const winner = pickMostRecent(pool);
|
|
729
|
+
updateProfileLastUsed(winner.profileId);
|
|
730
|
+
return winner.profileId;
|
|
731
|
+
}
|
|
732
|
+
const root = ensureRootProfile();
|
|
733
|
+
process.stderr.write(rootProfileMessage(resolvedCwd));
|
|
734
|
+
return root.profileId;
|
|
674
735
|
}
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
736
|
+
// Interactive. Several exact claimants → choose among them. Else covered from
|
|
737
|
+
// a parent/workspace dir → menu of covering profiles. Else nothing covers →
|
|
738
|
+
// the create-or-root prompt (root is only ever offered there).
|
|
739
|
+
const validPinnedId = pinned !== null ? pinned.profileId : null;
|
|
740
|
+
const chosen = exact.length > 1
|
|
741
|
+
? await promptPickProfileOrCreate(exact, resolvedCwd, true, validPinnedId, bindings)
|
|
742
|
+
: covering.length > 0
|
|
743
|
+
? await promptPickProfileOrCreate(covering, resolvedCwd, false, validPinnedId, bindings)
|
|
744
|
+
: await promptCreateOrRoot(resolvedCwd, bindings);
|
|
745
|
+
if (chosen === MANAGED)
|
|
746
|
+
continue;
|
|
747
|
+
updateProfileLastUsed(chosen);
|
|
748
|
+
return chosen;
|
|
678
749
|
}
|
|
679
|
-
// Interactive. Several exact claimants → choose among them. Else covered from
|
|
680
|
-
// a parent/workspace dir → menu of covering profiles. Else nothing covers →
|
|
681
|
-
// the create-or-root prompt (root is only ever offered there).
|
|
682
|
-
const validPinnedId = pinned !== null ? pinned.profileId : null;
|
|
683
|
-
const chosen = exact.length > 1
|
|
684
|
-
? await promptPickProfileOrCreate(exact, resolvedCwd, true, validPinnedId, bindings)
|
|
685
|
-
: covering.length > 0
|
|
686
|
-
? await promptPickProfileOrCreate(covering, resolvedCwd, false, validPinnedId, bindings)
|
|
687
|
-
: await promptCreateOrRoot(resolvedCwd, bindings);
|
|
688
|
-
updateProfileLastUsed(chosen);
|
|
689
|
-
return chosen;
|
|
690
750
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import assert from 'node:assert/strict';
|
|
2
|
-
import { existsSync, mkdtempSync, readdirSync, rmSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { existsSync, mkdtempSync, readdirSync, realpathSync, rmSync, writeFileSync } from 'node:fs';
|
|
3
3
|
import { tmpdir } from 'node:os';
|
|
4
4
|
import { join } from 'node:path';
|
|
5
5
|
import { afterEach, test } from 'node:test';
|
|
@@ -92,7 +92,7 @@ test('detached capture takes provider/id and explicit thinking from the launch r
|
|
|
92
92
|
const { session, sourceFile } = seededOrigin({ launchModel: 'p/m:high', thinking: 'low' });
|
|
93
93
|
const captured = await capture({ launchModel: 'p/m:high', thinking: 'low' });
|
|
94
94
|
assert.deepEqual(captured, {
|
|
95
|
-
sourceFile,
|
|
95
|
+
sourceFile: realpathSync(sourceFile),
|
|
96
96
|
sourceSessionId: session.getSessionId(),
|
|
97
97
|
leafId: session.getLeafId(),
|
|
98
98
|
modelSpec: 'p/m:high',
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import assert from 'node:assert/strict';
|
|
2
|
-
import { mkdtempSync, mkdirSync, readdirSync, renameSync, rmSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { mkdtempSync, mkdirSync, readdirSync, realpathSync, renameSync, rmSync, writeFileSync } from 'node:fs';
|
|
3
3
|
import { tmpdir } from 'node:os';
|
|
4
4
|
import { join } from 'node:path';
|
|
5
5
|
import { afterEach, test } from 'node:test';
|
|
@@ -63,7 +63,7 @@ function setup() {
|
|
|
63
63
|
const original = SessionManager.create(sessions);
|
|
64
64
|
original.appendThinkingLevelChange('low');
|
|
65
65
|
original.appendMessage(assistant('m'));
|
|
66
|
-
const sourceFile = original.getSessionFile();
|
|
66
|
+
const sourceFile = realpathSync(original.getSessionFile());
|
|
67
67
|
createNode({
|
|
68
68
|
node_id: 'origin',
|
|
69
69
|
name: 'origin',
|
|
@@ -2,7 +2,7 @@ import { randomUUID } from 'node:crypto';
|
|
|
2
2
|
import { existsSync } from 'node:fs';
|
|
3
3
|
import { basename, isAbsolute, resolve } from 'node:path';
|
|
4
4
|
import { BrokerClient } from '../broker-client/index.js';
|
|
5
|
-
import { getNode } from '../canvas/index.js';
|
|
5
|
+
import { deleteNode, getNode } from '../canvas/index.js';
|
|
6
6
|
import { ensureReviewDir, reviewBranchPath } from '../canvas/paths.js';
|
|
7
7
|
import { expandModelCandidates, selectInitialModelRoute } from '../model-routes.js';
|
|
8
8
|
import { buildLaunchSpec } from '../runtime/launch.js';
|
|
@@ -12,6 +12,7 @@ import { spawnNode } from '../runtime/nodes.js';
|
|
|
12
12
|
import { SessionManager } from '../runtime/broker-sdk.js';
|
|
13
13
|
import { materializeSessionBranchAt } from '../runtime/session-branch.js';
|
|
14
14
|
import { isReviewBoundary } from '../runtime/session-visibility.js';
|
|
15
|
+
import { initializeForkContextExposure } from '../substrate/injected-store.js';
|
|
15
16
|
import { ReviewOperationError } from './types.js';
|
|
16
17
|
const EXACT_MODEL_SPEC = /^[^/\s:]+\/[^/\s:]+:(?:off|minimal|low|medium|high|xhigh|max)$/;
|
|
17
18
|
const BIND_POLL_MS = 100;
|
|
@@ -155,7 +156,7 @@ export function spawnReviewCompanion(spec) {
|
|
|
155
156
|
cwd: spec.cwd,
|
|
156
157
|
profileId: spec.profileId,
|
|
157
158
|
});
|
|
158
|
-
spawnNode({
|
|
159
|
+
const node = spawnNode({
|
|
159
160
|
nodeId: spec.nodeId,
|
|
160
161
|
kind: 'review/companion',
|
|
161
162
|
mode: 'base',
|
|
@@ -165,6 +166,7 @@ export function spawnReviewCompanion(spec) {
|
|
|
165
166
|
parent: spec.originNodeId,
|
|
166
167
|
subscribe: false,
|
|
167
168
|
forkFrom: spec.branchFile,
|
|
169
|
+
forkSourceFile: spec.branchFile,
|
|
168
170
|
modelOverride: spec.modelSpec,
|
|
169
171
|
reviewBinding: {
|
|
170
172
|
review_id: spec.reviewId,
|
|
@@ -175,6 +177,13 @@ export function spawnReviewCompanion(spec) {
|
|
|
175
177
|
name: `review ${basename(spec.targetFile)}`,
|
|
176
178
|
launch,
|
|
177
179
|
});
|
|
180
|
+
try {
|
|
181
|
+
initializeForkContextExposure(node.node_id, spec.originNodeId);
|
|
182
|
+
}
|
|
183
|
+
catch (error) {
|
|
184
|
+
deleteNode(node.node_id);
|
|
185
|
+
throw error;
|
|
186
|
+
}
|
|
178
187
|
}
|
|
179
188
|
/** A companion is bound only when its session coordinates and visible boundary are durable. */
|
|
180
189
|
export function isReviewCompanionBound(nodeId) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type Cron } from '../canvas/index.js';
|
|
2
|
-
import type {
|
|
2
|
+
import type { ExposureTarget } from '../substrate/injected-store.js';
|
|
3
3
|
/** The bearings custom type is shared with every attached renderer. */
|
|
4
4
|
export { CONTEXT_INTRO_CUSTOM_TYPE } from '../../shared/generated-context.js';
|
|
5
5
|
/** The `<project_context>` block — the `<environment>` snapshot only: a
|
|
@@ -78,4 +78,4 @@ export declare function buildWakeBearings(origin: WakeOrigin): string;
|
|
|
78
78
|
* AGENTS.md/CLAUDE.md injection stays suppressed (`noContextFiles` in
|
|
79
79
|
* broker.ts); `crtr sys sync project-guidance` imports that guidance into
|
|
80
80
|
* the directory's `.crouter/memory/INDEX.md` front door. */
|
|
81
|
-
export declare function buildContextBearings(nodeId: string,
|
|
81
|
+
export declare function buildContextBearings(nodeId: string, target?: ExposureTarget): string;
|
|
@@ -346,7 +346,7 @@ function managedWorktreeNote(node) {
|
|
|
346
346
|
* AGENTS.md/CLAUDE.md injection stays suppressed (`noContextFiles` in
|
|
347
347
|
* broker.ts); `crtr sys sync project-guidance` imports that guidance into
|
|
348
348
|
* the directory's `.crouter/memory/INDEX.md` front door. */
|
|
349
|
-
export function buildContextBearings(nodeId,
|
|
349
|
+
export function buildContextBearings(nodeId, target) {
|
|
350
350
|
const node = getNode(nodeId);
|
|
351
351
|
const bearings = ['<crtr-bearings>', buildIdentityAssertion(nodeId)];
|
|
352
352
|
const map = buildGraphMap(nodeId);
|
|
@@ -365,9 +365,9 @@ export function buildContextBearings(nodeId, seen) {
|
|
|
365
365
|
bearings.push('', orchestratorContextNote(nodeId));
|
|
366
366
|
bearings.push('</crtr-bearings>');
|
|
367
367
|
// The consultable catalog rides BESIDE the bearings, not inside them.
|
|
368
|
-
const knowledge = renderKnowledgeBlock(nodeId,
|
|
368
|
+
const knowledge = renderKnowledgeBlock(nodeId, target);
|
|
369
369
|
// A workspace mount is the initial read of its root (`on: workspace-open`).
|
|
370
|
-
const workspaceContext = renderWorkspaceOpenDocs(nodeId,
|
|
370
|
+
const workspaceContext = renderWorkspaceOpenDocs(nodeId, target);
|
|
371
371
|
// Hidden applet/situation-origin ambient context (see situational-context.ts)
|
|
372
372
|
// — the stored `situational` card, placed in the bearings BODY, so it is a
|
|
373
373
|
// nested card inside the outer envelope. Never routed through the visible
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { BrokerExtensionStateDTO, BrokerGeneratedNameRequest, BrokerGeneratedNameResultDTO, BrokerInboxCursorDirective, BrokerInboxCursorRequest, BrokerModelCommitRequest, BrokerModelCommitResultDTO, BrokerPersonaAckRequest, BrokerSessionBoundRequest, BrokerSessionBoundResultDTO, BrokerSettleDirective, BrokerSettleRequest } from '../../../api/dto/broker-ops.js';
|
|
1
|
+
import type { BrokerExtensionStateDTO, BrokerGeneratedNameRequest, BrokerGeneratedNameResultDTO, BrokerInboxCursorDirective, BrokerInboxCursorRequest, BrokerModelCommitRequest, BrokerModelCommitResultDTO, BrokerPersonaAckRequest, BrokerPersonaAckResultDTO, BrokerSessionBoundRequest, BrokerSessionBoundResultDTO, BrokerSettleDirective, BrokerSettleRequest } from '../../../api/dto/broker-ops.js';
|
|
2
2
|
import type { RelaunchRootResultDTO } from '../../../api/dto/lifecycle.js';
|
|
3
3
|
import type { PushReportRequest } from '../../../api/dto/reports.js';
|
|
4
4
|
export declare function bindBrokerSession(nodeId: string, request: BrokerSessionBoundRequest): Promise<BrokerSessionBoundResultDTO>;
|
|
@@ -9,7 +9,7 @@ export declare function advanceBrokerInboxCursor(nodeId: string, request: Broker
|
|
|
9
9
|
export declare function commitBrokerModel(nodeId: string, request: BrokerModelCommitRequest): Promise<BrokerModelCommitResultDTO>;
|
|
10
10
|
export declare function brokerExtensionState(nodeId: string): Promise<BrokerExtensionStateDTO>;
|
|
11
11
|
export declare function commitBrokerGeneratedName(nodeId: string, request: BrokerGeneratedNameRequest): Promise<BrokerGeneratedNameResultDTO>;
|
|
12
|
-
export declare function commitBrokerPersonaAck(nodeId: string, request: BrokerPersonaAckRequest): Promise<
|
|
12
|
+
export declare function commitBrokerPersonaAck(nodeId: string, request: BrokerPersonaAckRequest): Promise<BrokerPersonaAckResultDTO>;
|
|
13
13
|
/** Reports still use the canonical daemon report handler; this broker adapter
|
|
14
14
|
* only preserves terminal structured output's idempotent finalization result. */
|
|
15
15
|
export declare function publishBrokerReport(nodeId: string, request: PushReportRequest): Promise<void>;
|
|
@@ -3,6 +3,7 @@ import { join } from 'node:path';
|
|
|
3
3
|
import { jobDir } from '../../canvas/paths.js';
|
|
4
4
|
import { emitEvent } from '../../events/emit.js';
|
|
5
5
|
import { operationIdContext } from '../../events/operation-id.js';
|
|
6
|
+
import { installPersonaTransitionGate } from '../broker-persona-guidance.js';
|
|
6
7
|
import { abortSessionFromExtension } from './extension-abort.js';
|
|
7
8
|
const MAX_ADMITTED_REPLACEMENTS = 2;
|
|
8
9
|
const REPLACEMENT_DEADLINE_MS = 30_000;
|
|
@@ -79,6 +80,10 @@ export class RebindDriver {
|
|
|
79
80
|
// fake-engine fixture has no `.agent`.
|
|
80
81
|
const agent = candidateSession.agent;
|
|
81
82
|
if (agent) {
|
|
83
|
+
installPersonaTransitionGate(this.deps.nodeId, {
|
|
84
|
+
agent,
|
|
85
|
+
sessionManager: candidateSession.sessionManager,
|
|
86
|
+
});
|
|
82
87
|
agent.steeringMode = 'all';
|
|
83
88
|
agent.followUpMode = 'all';
|
|
84
89
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { NodeConfigSubject } from '../substrate/subject-fields.js';
|
|
2
|
+
import type { ExposureTarget } from '../substrate/injected-store.js';
|
|
2
3
|
import type { BrokerExtensionNodeDTO, BrokerExtensionStateDTO } from '../../api/dto/broker-ops.js';
|
|
3
4
|
export declare function editorLabelForBrokerNode(node: BrokerExtensionNodeDTO): string;
|
|
4
5
|
/** Same environment-only project context rendered at normal boot, without a
|
|
@@ -7,9 +8,12 @@ export declare function buildProjectContextBlockForBroker(cwd: string): string;
|
|
|
7
8
|
/** `situational` is the node's stored situational card, placed in the bearings
|
|
8
9
|
* BODY — the one place in the system where a runtime card nests inside
|
|
9
10
|
* another (see situational-context.ts). '' when none is set. */
|
|
10
|
-
export declare function buildContextBearingsFromState(state: BrokerExtensionStateDTO, projectContext: string, situational?: string,
|
|
11
|
+
export declare function buildContextBearingsFromState(state: BrokerExtensionStateDTO, projectContext: string, situational?: string, target?: ExposureTarget): string;
|
|
11
12
|
export declare function buildForkBearingsFromState(state: BrokerExtensionStateDTO, situational?: string): string;
|
|
12
|
-
export declare function renderPreferencesFromState(state: BrokerExtensionStateDTO,
|
|
13
|
+
export declare function renderPreferencesFromState(state: BrokerExtensionStateDTO, target?: ExposureTarget): string;
|
|
14
|
+
/** The same preference block without the extension-state DTO, for the daemon-side
|
|
15
|
+
* claim path that holds a node's subject directly. */
|
|
16
|
+
export declare function renderPreferencesForNodeSubject(nodeId: string, subject: NodeConfigSubject | null, target?: ExposureTarget): string;
|
|
13
17
|
/** A canonical report ref has already been validated by crtrd in state. The
|
|
14
18
|
* broker reads only its local filesystem content; no canvas accessor is needed. */
|
|
15
19
|
export declare function reportPathFromRef(ref: string, reportNodes: ReadonlyMap<string, unknown>): string | null;
|
|
@@ -142,7 +142,7 @@ function reviewNote(node) {
|
|
|
142
142
|
/** `situational` is the node's stored situational card, placed in the bearings
|
|
143
143
|
* BODY — the one place in the system where a runtime card nests inside
|
|
144
144
|
* another (see situational-context.ts). '' when none is set. */
|
|
145
|
-
export function buildContextBearingsFromState(state, projectContext, situational = '',
|
|
145
|
+
export function buildContextBearingsFromState(state, projectContext, situational = '', target) {
|
|
146
146
|
const { node } = state;
|
|
147
147
|
const bearings = ['<crtr-bearings>', identity(state)];
|
|
148
148
|
const map = graphMap(state);
|
|
@@ -158,8 +158,8 @@ export function buildContextBearingsFromState(state, projectContext, situational
|
|
|
158
158
|
if (node.mode === 'orchestrator')
|
|
159
159
|
bearings.push('', `Because you persist across refresh cycles, your context directory (${contextDir(node.node_id)}) is also where a future cycle of you resumes the work — keep the working notes and decisions a refreshed you would need there, alongside the docs you share with the nodes you spawn.`);
|
|
160
160
|
bearings.push('</crtr-bearings>');
|
|
161
|
-
const knowledge = renderKnowledgeForSubject(state.subject, node.node_id,
|
|
162
|
-
const workspace = renderWorkspaceOpenDocsForSubject(state.subject, node.cwd, node.profile_id,
|
|
161
|
+
const knowledge = renderKnowledgeForSubject(state.subject, node.node_id, target);
|
|
162
|
+
const workspace = renderWorkspaceOpenDocsForSubject(state.subject, node.cwd, node.profile_id, target);
|
|
163
163
|
return [bearings.join('\n'), knowledge, workspace, situational, projectContext].filter((part) => part !== '').join('\n');
|
|
164
164
|
}
|
|
165
165
|
export function buildForkBearingsFromState(state, situational = '') {
|
|
@@ -186,8 +186,13 @@ export function buildForkBearingsFromState(state, situational = '') {
|
|
|
186
186
|
bearings.push('', 'The first real user message after these bearings is your mandate.', '</crtr-bearings>');
|
|
187
187
|
return [bearings.join('\n'), situational].filter((part) => part !== '').join('\n');
|
|
188
188
|
}
|
|
189
|
-
export function renderPreferencesFromState(state,
|
|
190
|
-
return
|
|
189
|
+
export function renderPreferencesFromState(state, target) {
|
|
190
|
+
return renderPreferencesForNodeSubject(state.node.node_id, state.subject, target);
|
|
191
|
+
}
|
|
192
|
+
/** The same preference block without the extension-state DTO, for the daemon-side
|
|
193
|
+
* claim path that holds a node's subject directly. */
|
|
194
|
+
export function renderPreferencesForNodeSubject(nodeId, subject, target) {
|
|
195
|
+
return interpolateNodePaths(renderPreferencesForSubject(subject, target).block, nodeId);
|
|
191
196
|
}
|
|
192
197
|
/** A canonical report ref has already been validated by crtrd in state. The
|
|
193
198
|
* broker reads only its local filesystem content; no canvas accessor is needed. */
|
|
@@ -1,13 +1,27 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { Agent } from '@earendil-works/pi-agent-core';
|
|
2
|
+
import type { BrokerExtensionStateDTO } from '../../api/dto/broker-ops.js';
|
|
2
3
|
export interface BrokerPersona {
|
|
4
|
+
kind: string;
|
|
3
5
|
mode: 'base' | 'orchestrator';
|
|
4
6
|
lifecycle: 'terminal' | 'resident';
|
|
5
7
|
}
|
|
6
8
|
export interface BrokerPersonaDrift {
|
|
7
9
|
from: BrokerPersona;
|
|
8
10
|
to: BrokerPersona;
|
|
9
|
-
guidance: string;
|
|
10
11
|
}
|
|
11
|
-
export declare function
|
|
12
|
-
/**
|
|
13
|
-
export declare function
|
|
12
|
+
export declare function personaDriftFromBrokerState(state: BrokerExtensionStateDTO): BrokerPersonaDrift | null;
|
|
13
|
+
/** A new context's current snapshots make a rank delta unnecessary. */
|
|
14
|
+
export declare function acknowledgePersonaBaseline(state: BrokerExtensionStateDTO): Promise<boolean>;
|
|
15
|
+
/** Append pending transitions until the delivered persona matches current canvas state. */
|
|
16
|
+
export declare function deliverPendingPersonaTransition(initialState: BrokerExtensionStateDTO, deliver: (content: string) => void | Promise<void>): Promise<boolean>;
|
|
17
|
+
interface PersonaTransitionSession {
|
|
18
|
+
agent: Pick<Agent, 'state' | 'transformContext'>;
|
|
19
|
+
sessionManager: {
|
|
20
|
+
appendCustomMessageEntry: (customType: string, content: string, display: boolean, details?: {
|
|
21
|
+
nodeId: string;
|
|
22
|
+
}) => unknown;
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
/** Gate each provider request on durable delivery of the current persona delta. */
|
|
26
|
+
export declare function installPersonaTransitionGate(nodeId: string, session: PersonaTransitionSession): void;
|
|
27
|
+
export {};
|