@north-light/crouter 0.3.227 → 0.3.228
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/05-kinds/design/00-base.md +3 -4
- package/dist/builtin-memory/05-kinds/design/01-orchestrator.md +4 -3
- package/dist/builtin-memory/05-kinds/design/design-contract.md +3 -6
- package/dist/builtin-memory/05-kinds/plan/00-base.md +3 -4
- package/dist/builtin-memory/05-kinds/plan/01-orchestrator.md +4 -5
- package/dist/builtin-memory/05-kinds/plan/plan-contract.md +5 -13
- package/dist/builtin-memory/design/guide.md +38 -16
- package/dist/builtin-memory/design/roadmap.md +4 -4
- package/dist/builtin-memory/insights/init.md +5 -5
- package/dist/builtin-memory/internal/INDEX.md +1 -1
- 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-memory/plan/guide.md +53 -0
- package/dist/builtin-memory/plan/roadmap.md +10 -8
- 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/lifecycle.js +2 -2
- 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__/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/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/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/package.json +5 -4
- package/runtime.lock.json +2 -2
- /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,18 +6,33 @@ class FakeSocket extends EventEmitter {
|
|
|
6
6
|
pings = 0;
|
|
7
7
|
terminated = 0;
|
|
8
8
|
ping() { this.pings += 1; }
|
|
9
|
-
terminate() {
|
|
9
|
+
terminate() {
|
|
10
|
+
this.terminated += 1;
|
|
11
|
+
this.emit('terminated');
|
|
12
|
+
}
|
|
10
13
|
}
|
|
11
14
|
function sleep(ms) {
|
|
12
15
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
13
16
|
}
|
|
17
|
+
function waitForTermination(ws, timeoutMs = 1_000) {
|
|
18
|
+
return new Promise((resolve, reject) => {
|
|
19
|
+
const timeout = setTimeout(() => reject(new Error('heartbeat did not terminate the peer')), timeoutMs);
|
|
20
|
+
timeout.unref();
|
|
21
|
+
ws.once('terminated', () => {
|
|
22
|
+
clearTimeout(timeout);
|
|
23
|
+
resolve();
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
}
|
|
14
27
|
test('a quiet attach puts nothing on the wire', async () => {
|
|
15
28
|
// Regression: an unconditional 25s ping made a hosted guest's connection never
|
|
16
29
|
// idle, so the sandbox never suspended and whole fleets billed for 15h awake.
|
|
17
30
|
const ws = new FakeSocket();
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
31
|
+
// The first timer tick is deliberately after the quiet window, so this test
|
|
32
|
+
// observes the contract without depending on scheduler timing.
|
|
33
|
+
const heartbeat = startRemoteAttachHeartbeat(ws, 20, 15);
|
|
34
|
+
await sleep(40);
|
|
35
|
+
assert.equal(ws.pings, 0, 'a quiet attach sends no heartbeat after its quiet window');
|
|
21
36
|
assert.equal(ws.terminated, 0, 'a quiet attach is left open, never terminated by the heartbeat');
|
|
22
37
|
heartbeat.stop();
|
|
23
38
|
});
|
|
@@ -35,8 +50,9 @@ test('relayed traffic arms the heartbeat and a pong keeps a relaying observer al
|
|
|
35
50
|
test('an unresponsive peer is dropped only while the relay is active', async () => {
|
|
36
51
|
const ws = new FakeSocket();
|
|
37
52
|
const heartbeat = startRemoteAttachHeartbeat(ws, 5, 10_000);
|
|
53
|
+
const terminated = waitForTermination(ws);
|
|
38
54
|
heartbeat.noteActivity();
|
|
39
|
-
await
|
|
55
|
+
await terminated;
|
|
40
56
|
assert.equal(ws.terminated, 1, 'two missed heartbeat intervals terminate the detached viewer');
|
|
41
57
|
heartbeat.stop();
|
|
42
58
|
});
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
// Broker-originated canvas operations. The broker sends Pi lifecycle facts;
|
|
2
2
|
// crtrd validates and commits their durable effects while the handler stays
|
|
3
3
|
// strictly canvas-write-only — no broker launch, kill, or view.sock round trip.
|
|
4
|
-
import { getNode, isWarmSpare, listNodes, recordPid, setPresence, subscriptionsOf, updateNode } from '../../../core/canvas/canvas.js';
|
|
5
|
-
import { isSafeNodeId } from '../../../core/canvas/paths.js';
|
|
4
|
+
import { canonicalSessionFile, findNodeBySessionFile, getNode, isWarmSpare, listNodes, recordPid, setPresence, subscriptionsOf, updateNode } from '../../../core/canvas/canvas.js';
|
|
6
5
|
import { editorLabel } from '../../../core/canvas/labels.js';
|
|
7
6
|
import { assembleNodeSubject } from '../../../core/substrate/subject.js';
|
|
8
7
|
import { withCanvasWrite } from '../../../core/canvas/db.js';
|
|
@@ -128,9 +127,9 @@ function extensionState(nodeId) {
|
|
|
128
127
|
.filter((child) => child !== null && child.kind !== 'human')
|
|
129
128
|
.sort((a, b) => (a.status === b.status ? 0 : a.status === 'active' ? -1 : b.status === 'active' ? 1 : 0))
|
|
130
129
|
.map(extensionNode);
|
|
131
|
-
const source =
|
|
132
|
-
?
|
|
133
|
-
:
|
|
130
|
+
const source = typeof node.fork_source_file === 'string'
|
|
131
|
+
? findNodeBySessionFile(node.fork_source_file)
|
|
132
|
+
: null;
|
|
134
133
|
const subject = assembleNodeSubject(nodeId);
|
|
135
134
|
if (subject === null)
|
|
136
135
|
throw notFound(`unknown node: ${nodeId}`, { received: nodeId });
|
|
@@ -146,7 +145,7 @@ function extensionState(nodeId) {
|
|
|
146
145
|
};
|
|
147
146
|
}
|
|
148
147
|
function samePersona(a, b) {
|
|
149
|
-
return a?.mode === b.mode && a?.lifecycle === b.lifecycle;
|
|
148
|
+
return a?.kind === b.kind && a?.mode === b.mode && a?.lifecycle === b.lifecycle;
|
|
150
149
|
}
|
|
151
150
|
function parseGeneratedNameBody(body) {
|
|
152
151
|
const value = objectBody(body, 'broker generated-name');
|
|
@@ -169,6 +168,7 @@ function parsePersonaAckBody(body) {
|
|
|
169
168
|
const parse = (key) => {
|
|
170
169
|
const persona = value[key];
|
|
171
170
|
if (typeof persona !== 'object' || persona === null || Array.isArray(persona)
|
|
171
|
+
|| typeof persona['kind'] !== 'string'
|
|
172
172
|
|| (persona['mode'] !== 'base' && persona['mode'] !== 'orchestrator')
|
|
173
173
|
|| (persona['lifecycle'] !== 'terminal' && persona['lifecycle'] !== 'resident')) {
|
|
174
174
|
throw usage(`${key} must be a persona state`);
|
|
@@ -180,6 +180,7 @@ function parsePersonaAckBody(body) {
|
|
|
180
180
|
function handleSessionBound(ctx) {
|
|
181
181
|
const nodeId = ctx.params['id'];
|
|
182
182
|
const request = parseSessionBoundBody(ctx.body);
|
|
183
|
+
const sessionFile = request.sessionFile === null ? null : canonicalSessionFile(request.sessionFile);
|
|
183
184
|
const result = withCanvasWrite(() => {
|
|
184
185
|
const before = requireNode(nodeId);
|
|
185
186
|
// The broker reports the markers present in Pi's current branch; crtrd owns
|
|
@@ -196,10 +197,10 @@ function handleSessionBound(ctx) {
|
|
|
196
197
|
action = 'relaunch_root';
|
|
197
198
|
}
|
|
198
199
|
else {
|
|
199
|
-
handleNewSession(nodeId, request.piSessionId,
|
|
200
|
+
handleNewSession(nodeId, request.piSessionId, sessionFile);
|
|
200
201
|
}
|
|
201
202
|
}
|
|
202
|
-
else if (before.fork_from != null && before.pi_session_id == null &&
|
|
203
|
+
else if (before.fork_from != null && before.pi_session_id == null && sessionFile === null) {
|
|
203
204
|
// Pi has not exposed complete writable coordinates for this ordinary fork.
|
|
204
205
|
// Leave it unbound so recovery cannot fork provenance twice.
|
|
205
206
|
action = 'shutdown';
|
|
@@ -210,7 +211,7 @@ function handleSessionBound(ctx) {
|
|
|
210
211
|
clearYieldMessage(nodeId);
|
|
211
212
|
updateNode(nodeId, {
|
|
212
213
|
pi_session_id: request.piSessionId,
|
|
213
|
-
pi_session_file:
|
|
214
|
+
pi_session_file: sessionFile,
|
|
214
215
|
cycle_pending: false,
|
|
215
216
|
});
|
|
216
217
|
recordPid(nodeId, request.pid);
|
|
@@ -378,20 +379,24 @@ function handleGeneratedName(ctx) {
|
|
|
378
379
|
});
|
|
379
380
|
return { status: 200, body: result };
|
|
380
381
|
}
|
|
381
|
-
/** Ack after
|
|
382
|
-
* stale broker from acknowledging a later
|
|
382
|
+
/** Ack after the matching baseline or transition context is durable. The
|
|
383
|
+
* expected pair prevents a stale broker from acknowledging a later change. */
|
|
383
384
|
function handlePersonaAck(ctx) {
|
|
384
385
|
const nodeId = ctx.params['id'];
|
|
385
386
|
const request = parsePersonaAckBody(ctx.body);
|
|
386
|
-
withCanvasWrite(() => {
|
|
387
|
+
const result = withCanvasWrite(() => {
|
|
387
388
|
const node = requireNode(nodeId);
|
|
388
|
-
const current = { mode: node.mode, lifecycle: node.lifecycle };
|
|
389
|
-
|
|
389
|
+
const current = { kind: node.kind, mode: node.mode, lifecycle: node.lifecycle };
|
|
390
|
+
// A pre-kind ack reads its kind as the node's current one, matching how the
|
|
391
|
+
// broker resolved the `from` it is acknowledging.
|
|
392
|
+
const ack = node.persona_ack;
|
|
393
|
+
const acknowledged = ack === undefined ? current : { kind: ack.kind ?? node.kind, mode: ack.mode, lifecycle: ack.lifecycle };
|
|
390
394
|
if (!samePersona(current, request.to) || !samePersona(acknowledged, request.from))
|
|
391
|
-
return;
|
|
395
|
+
return { applied: false };
|
|
392
396
|
updateNode(nodeId, { persona_ack: request.to });
|
|
397
|
+
return { applied: true };
|
|
393
398
|
});
|
|
394
|
-
return { status:
|
|
399
|
+
return { status: 200, body: result };
|
|
395
400
|
}
|
|
396
401
|
export const brokerOperationRoutes = [
|
|
397
402
|
{ method: 'POST', pattern: '/v1/nodes/:id/broker/session-bound', handler: handleSessionBound },
|
|
@@ -39,6 +39,8 @@ function handleResolve(ctx) {
|
|
|
39
39
|
name: doc.name,
|
|
40
40
|
scope: doc.scope,
|
|
41
41
|
path: doc.path,
|
|
42
|
+
store_root: doc.store.storeRoot,
|
|
43
|
+
physical_relative_path: doc.physicalRelativePath,
|
|
42
44
|
...(doc.plugin === undefined ? {} : { plugin: doc.plugin }),
|
|
43
45
|
};
|
|
44
46
|
return { status: 200, body };
|
package/dist/daemon/crtrd.js
CHANGED
|
@@ -75,6 +75,7 @@ import { migrateLegacyInboxIdentities } from '../core/feed/inbox-migrate.js';
|
|
|
75
75
|
import { emitEvent } from '../core/events/emit.js';
|
|
76
76
|
import { operationIdContext } from '../core/events/operation-id.js';
|
|
77
77
|
import { bindDaemonEventSource } from '../core/events/source.js';
|
|
78
|
+
import { ensureOnDiskMigrations } from '../migrations/activation.js';
|
|
78
79
|
// A broker DECLARES its owning canvas in argv at spawn (host.ts launch:
|
|
79
80
|
// `broker-cli.js --canvas-home <home> --epoch <id> <nodeId>`), so ownership is
|
|
80
81
|
// an exact match on this daemon's own canvas home — no path inference. An
|
|
@@ -350,6 +351,7 @@ export async function superviseTick(now = Date.now(), lifecycle = directTickLife
|
|
|
350
351
|
* quiesces admitted work, removes its readiness mirror, and releases its exact
|
|
351
352
|
* claim. */
|
|
352
353
|
export async function runDaemon(opts = {}) {
|
|
354
|
+
await ensureOnDiskMigrations();
|
|
353
355
|
const ownership = claimDaemonOwnership(randomBytes(16).toString('hex'));
|
|
354
356
|
if (!ownership.claimed) {
|
|
355
357
|
// A losing claim isn't always a singleton race: `own_identity_indeterminate`
|
|
@@ -282,7 +282,14 @@ export async function deliverTerminalResult(ticketId) {
|
|
|
282
282
|
}
|
|
283
283
|
if (failedTo.length > 0)
|
|
284
284
|
throw new Error(`cancellation notice failed for ${failedTo.join(', ')}`);
|
|
285
|
-
|
|
285
|
+
// Parking the bridge done is the cancellation's END STATE, not a step it
|
|
286
|
+
// owes: a bridge already done — parked by an earlier cancel replay, or by a
|
|
287
|
+
// close that finished it while the page was still pending — is already
|
|
288
|
+
// there, and `finish` is illegal from done. Re-running it would turn a
|
|
289
|
+
// recorded, delivered cancellation into delivery_failed and make every
|
|
290
|
+
// retry repeat that error.
|
|
291
|
+
if (node.status !== 'done')
|
|
292
|
+
transition(bridgeNodeId, 'finish');
|
|
286
293
|
return true;
|
|
287
294
|
}
|
|
288
295
|
if (result.kind === 'page') {
|
package/dist/daemon/manage.d.ts
CHANGED
|
@@ -47,7 +47,6 @@ export interface SpawnDaemonResult {
|
|
|
47
47
|
/** PID of the already-running daemon, if it was already up. */
|
|
48
48
|
existing_pid?: number;
|
|
49
49
|
}
|
|
50
|
-
export declare const DAEMON_VERIFY_WINDOW_MS = 20000;
|
|
51
50
|
export interface DaemonWaitDeps {
|
|
52
51
|
readPidfile?: () => number | null;
|
|
53
52
|
isPidAlive?: (pid: number) => boolean;
|
package/dist/daemon/manage.js
CHANGED
|
@@ -14,6 +14,7 @@ import { hostExecPath } from '../core/runtime/branded-host.js';
|
|
|
14
14
|
// Pulled from the lean db-free pidfile module (NOT crtrd.js, whose module graph
|
|
15
15
|
// reaches openDb) so the CLI daemon front door stays canvas.db-free (plan B-0).
|
|
16
16
|
import { isDaemonRunning, readPidfile, isPidAlive } from './pidfile.js';
|
|
17
|
+
import { DAEMON_STARTUP_WINDOW_MS } from './startup-policy.js';
|
|
17
18
|
// ---------------------------------------------------------------------------
|
|
18
19
|
// Daemon env sanitization
|
|
19
20
|
// ---------------------------------------------------------------------------
|
|
@@ -204,18 +205,8 @@ export async function execDaemon() {
|
|
|
204
205
|
const launchArgs = await resolveDaemonLaunch();
|
|
205
206
|
return execve(executable, [executable, ...launchArgs, '--canvas-home', crtrHome()], sanitizedDaemonEnv());
|
|
206
207
|
}
|
|
207
|
-
//
|
|
208
|
-
|
|
209
|
-
//
|
|
210
|
-
// A cold boot right after `install-runtime` (empty module cache, fresh
|
|
211
|
-
// generation, possible pending db migration) can take several seconds to reach
|
|
212
|
-
// writePidfile(), so the window is wide enough to tolerate that slow-but-valid
|
|
213
|
-
// cold start rather than report a false "did not become ready"; a process exit
|
|
214
|
-
// (signal/non-zero code) still fails immediately regardless of this window.
|
|
215
|
-
// Exported so `commands/api-client.ts` can align the CLI-side `CrtrClient`'s
|
|
216
|
-
// cold-start `/healthz` poll window with this authoritative valid-startup bound
|
|
217
|
-
// instead of the two windows drifting independently.
|
|
218
|
-
export const DAEMON_VERIFY_WINDOW_MS = 20_000;
|
|
208
|
+
// Shutdown stays short even though startup may include corpus migration.
|
|
209
|
+
const DAEMON_SHUTDOWN_WINDOW_MS = 20_000;
|
|
219
210
|
const DAEMON_VERIFY_POLL_MS = 10;
|
|
220
211
|
function sleepMs(ms) {
|
|
221
212
|
return new Promise((resolve) => {
|
|
@@ -235,7 +226,7 @@ function sleepMs(ms) {
|
|
|
235
226
|
*
|
|
236
227
|
* Returns null when the spawned pid owns the pidfile; returns a different live
|
|
237
228
|
* daemon pid when startup lost the race to an already-running daemon. */
|
|
238
|
-
export async function verifyDaemonStartup(pid, timeoutMs =
|
|
229
|
+
export async function verifyDaemonStartup(pid, timeoutMs = DAEMON_STARTUP_WINDOW_MS, deps = {}) {
|
|
239
230
|
const read = deps.readPidfile ?? readPidfile;
|
|
240
231
|
const alive = deps.isPidAlive ?? isPidAlive;
|
|
241
232
|
const exited = deps.childExited;
|
|
@@ -265,7 +256,7 @@ export async function verifyDaemonStartup(pid, timeoutMs = DAEMON_VERIFY_WINDOW_
|
|
|
265
256
|
/** Wait until a signaled daemon has exited and relinquished its pidfile. This
|
|
266
257
|
* makes a following start safe to claim the singleton rather than racing its
|
|
267
258
|
* previous owner. */
|
|
268
|
-
export async function waitForDaemonExit(pid, timeoutMs =
|
|
259
|
+
export async function waitForDaemonExit(pid, timeoutMs = DAEMON_SHUTDOWN_WINDOW_MS, deps = {}) {
|
|
269
260
|
const read = deps.readPidfile ?? readPidfile;
|
|
270
261
|
const alive = deps.isPidAlive ?? isPidAlive;
|
|
271
262
|
const sleep = deps.sleepMs ?? sleepMs;
|
|
@@ -298,7 +289,7 @@ const DAEMON_KILL_WINDOW_MS = 2_000;
|
|
|
298
289
|
* waits on process death alone after a kill, never on pidfile release.
|
|
299
290
|
*
|
|
300
291
|
* Returns how the daemon went down, for a truthful report. */
|
|
301
|
-
export async function stopDaemonProcess(pid, timeoutMs =
|
|
292
|
+
export async function stopDaemonProcess(pid, timeoutMs = DAEMON_SHUTDOWN_WINDOW_MS, deps = {}) {
|
|
302
293
|
const alive = deps.isPidAlive ?? isPidAlive;
|
|
303
294
|
const sleep = deps.sleepMs ?? sleepMs;
|
|
304
295
|
const now = deps.now ?? Date.now;
|
|
@@ -377,7 +368,7 @@ export async function spawnDaemon() {
|
|
|
377
368
|
exitState = { code, signal };
|
|
378
369
|
});
|
|
379
370
|
child.unref();
|
|
380
|
-
const existingPid = await verifyDaemonStartup(pid,
|
|
371
|
+
const existingPid = await verifyDaemonStartup(pid, DAEMON_STARTUP_WINDOW_MS, {
|
|
381
372
|
childExited: () => exitState,
|
|
382
373
|
});
|
|
383
374
|
if (existingPid !== null) {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const DAEMON_STARTUP_WINDOW_MS: number;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const DAEMON_STARTUP_WINDOW_MS = 5 * 60 * 1_000;
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
// 001 — the surfaces cut's frontmatter codemod. Folds the four old routing
|
|
2
2
|
// fields (`system-prompt-visibility`, `file-read-visibility`, `applies-to`,
|
|
3
|
-
// `read-when`) into explicit `surfaces` entries
|
|
4
|
-
// each doc's boot rung (per store)
|
|
5
|
-
// their `[[dir/INDEX]]` docs (a bare-dir ref used to deliver the INDEX body;
|
|
6
|
-
// after the cut it returns the directory listing).
|
|
3
|
+
// `read-when`) into explicit `surfaces` entries and bakes INDEX boot ceilings
|
|
4
|
+
// into each doc's boot rung (per store).
|
|
7
5
|
//
|
|
8
6
|
// Only docs with a valid substrate `kind` are touched. The old-schema parsing
|
|
9
7
|
// and ceiling walk are FROZEN COPIES of the pre-cut substrate code: the live
|
|
@@ -13,14 +11,13 @@
|
|
|
13
11
|
// Serialization is a textual splice: the dead keys' exact line spans are cut
|
|
14
12
|
// from the raw frontmatter and a rendered `surfaces:` block is appended, so
|
|
15
13
|
// every other byte survives verbatim and a migrated doc's diff shows only the
|
|
16
|
-
// dead fields dying
|
|
17
|
-
//
|
|
18
|
-
// folded scalars). Each splice is validated by re-parsing: the result must
|
|
14
|
+
// dead fields dying and `surfaces` appearing — never unrelated reformatting
|
|
15
|
+
// (re-serializing through the Document API would unfold folded scalars). Each splice is validated by re-parsing: the result must
|
|
19
16
|
// equal the original record minus the dead fields plus `surfaces`, or the
|
|
20
17
|
// migration throws naming the doc.
|
|
21
|
-
import {
|
|
18
|
+
import { parse as parseYaml } from 'yaml';
|
|
22
19
|
import { parseFrontmatterGeneric } from '../core/frontmatter.js';
|
|
23
|
-
import {
|
|
20
|
+
import { appendRenderedKey, dropTopLevelKeys, proveFrontmatterRoundTrip, rebuildDocSource, } from './frontmatter-splice.js';
|
|
24
21
|
const OLD_FIELDS = ['system-prompt-visibility', 'file-read-visibility', 'applies-to', 'read-when'];
|
|
25
22
|
// ---------------------------------------------------------------------------
|
|
26
23
|
// Frozen old-schema parsing (pre-cut substrate/schema.ts semantics).
|
|
@@ -133,122 +130,37 @@ function planEntries(d, bootRung) {
|
|
|
133
130
|
return entries;
|
|
134
131
|
}
|
|
135
132
|
// ---------------------------------------------------------------------------
|
|
136
|
-
//
|
|
137
|
-
//
|
|
138
|
-
//
|
|
139
|
-
// to one migration target; profile-local names never leak across stores.
|
|
133
|
+
// Serialization: cut the dead keys' exact line spans out of the raw
|
|
134
|
+
// frontmatter text, append the rendered `surfaces:` block, re-parse to prove
|
|
135
|
+
// the splice is meaning-preserving.
|
|
140
136
|
// ---------------------------------------------------------------------------
|
|
141
|
-
function rewriteBareDirRefs(body, context, decisions) {
|
|
142
|
-
const links = findDocLinks(body);
|
|
143
|
-
if (links.length === 0)
|
|
144
|
-
return body;
|
|
145
|
-
let out = '';
|
|
146
|
-
let pos = 0;
|
|
147
|
-
for (const link of links) {
|
|
148
|
-
let repl = decisions.get(link.name);
|
|
149
|
-
if (repl === undefined) {
|
|
150
|
-
repl = context?.legacyDirectoryIndex(link.name) ?? null;
|
|
151
|
-
decisions.set(link.name, repl);
|
|
152
|
-
}
|
|
153
|
-
if (repl === null)
|
|
154
|
-
continue;
|
|
155
|
-
out += body.slice(pos, link.start) + `[[${repl}]]`;
|
|
156
|
-
pos = link.end;
|
|
157
|
-
}
|
|
158
|
-
return out + body.slice(pos);
|
|
159
|
-
}
|
|
160
|
-
function deepEqual(a, b) {
|
|
161
|
-
if (a === b)
|
|
162
|
-
return true;
|
|
163
|
-
if (Array.isArray(a) || Array.isArray(b)) {
|
|
164
|
-
if (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length)
|
|
165
|
-
return false;
|
|
166
|
-
return a.every((v, i) => deepEqual(v, b[i]));
|
|
167
|
-
}
|
|
168
|
-
if (a !== null && b !== null && typeof a === 'object' && typeof b === 'object') {
|
|
169
|
-
const ak = Object.keys(a);
|
|
170
|
-
const bk = Object.keys(b);
|
|
171
|
-
if (ak.length !== bk.length)
|
|
172
|
-
return false;
|
|
173
|
-
return ak.every((k) => deepEqual(a[k], b[k]));
|
|
174
|
-
}
|
|
175
|
-
return false;
|
|
176
|
-
}
|
|
177
137
|
function migratedYaml(rawYaml, entries, docPath) {
|
|
178
|
-
|
|
179
|
-
if (
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
// the value's node-end bounds its last continuation line).
|
|
184
|
-
const spans = [];
|
|
185
|
-
for (const item of ydoc.contents.items) {
|
|
186
|
-
if (!OLD_FIELDS.includes(String(item.key)))
|
|
187
|
-
continue;
|
|
188
|
-
const keyRange = item.key.range;
|
|
189
|
-
const valueRange = item.value?.range;
|
|
190
|
-
if (keyRange === undefined)
|
|
191
|
-
throw new Error(`surfaces migration: rangeless key in ${docPath}`);
|
|
192
|
-
const start = rawYaml.lastIndexOf('\n', keyRange[0] - 1) + 1;
|
|
193
|
-
let end = valueRange?.[2] ?? keyRange[2];
|
|
194
|
-
// Consume through end-of-line unless a block value already owns its newline.
|
|
195
|
-
if (!(end > 0 && rawYaml[end - 1] === '\n')) {
|
|
196
|
-
while (end < rawYaml.length && (rawYaml[end] === ' ' || rawYaml[end] === '\t' || rawYaml[end] === '\r'))
|
|
197
|
-
end++;
|
|
198
|
-
if (rawYaml[end] === '\n')
|
|
199
|
-
end++;
|
|
200
|
-
}
|
|
201
|
-
spans.push([start, end]);
|
|
202
|
-
}
|
|
203
|
-
spans.sort((a, b) => b[0] - a[0]);
|
|
204
|
-
let out = rawYaml;
|
|
205
|
-
for (const [s, e] of spans)
|
|
206
|
-
out = out.slice(0, s) + out.slice(e);
|
|
207
|
-
if (entries.length > 0) {
|
|
208
|
-
// lineWidth 0: render each entry's scalars on one line, never folded.
|
|
209
|
-
const block = stringify({ surfaces: entries }, { lineWidth: 0 });
|
|
210
|
-
out = out === '' ? block : (out.endsWith('\n') ? out : out + '\n') + block;
|
|
211
|
-
}
|
|
212
|
-
out = out.replace(/\r?\n$/, '');
|
|
138
|
+
let out = dropTopLevelKeys(rawYaml, OLD_FIELDS, docPath);
|
|
139
|
+
if (entries.length > 0)
|
|
140
|
+
out = appendRenderedKey(out, 'surfaces', entries, docPath);
|
|
141
|
+
else
|
|
142
|
+
out = out.replace(/\r?\n$/, '');
|
|
213
143
|
const expected = { ...parseYaml(rawYaml) };
|
|
214
144
|
for (const k of OLD_FIELDS)
|
|
215
145
|
delete expected[k];
|
|
216
146
|
if (entries.length > 0)
|
|
217
147
|
expected['surfaces'] = entries;
|
|
218
|
-
|
|
219
|
-
if (!deepEqual(actual ?? {}, expected)) {
|
|
220
|
-
throw new Error(`surfaces migration: spliced frontmatter does not round-trip in ${docPath}`);
|
|
221
|
-
}
|
|
148
|
+
proveFrontmatterRoundTrip(out, expected, docPath);
|
|
222
149
|
return out;
|
|
223
150
|
}
|
|
224
|
-
function rebuildSource(d, newYaml, newBody) {
|
|
225
|
-
const { doc } = d;
|
|
226
|
-
const bodyStart = doc.source.length - doc.body.length;
|
|
227
|
-
const fmBlock = doc.source.slice(0, bodyStart);
|
|
228
|
-
if (newYaml === null)
|
|
229
|
-
return fmBlock + newBody;
|
|
230
|
-
const { raw } = parseFrontmatterGeneric(doc.source);
|
|
231
|
-
const at = fmBlock.indexOf(raw);
|
|
232
|
-
if (raw === '' || at < 0)
|
|
233
|
-
throw new Error(`surfaces migration: cannot locate frontmatter block in ${doc.path}`);
|
|
234
|
-
return fmBlock.slice(0, at) + newYaml + fmBlock.slice(at + raw.length) + newBody;
|
|
235
|
-
}
|
|
236
151
|
export const surfacesFrontmatterMigration = {
|
|
152
|
+
id: '001-surfaces-frontmatter',
|
|
237
153
|
lane: 'convergent',
|
|
238
|
-
description: 'surfaces frontmatter: fold visibility/applies-to/read-when routing into surfaces entries
|
|
239
|
-
apply(store
|
|
154
|
+
description: 'surfaces frontmatter: fold visibility/applies-to/read-when routing into surfaces entries',
|
|
155
|
+
apply(store) {
|
|
240
156
|
const docs = store.docs.map(classify).filter((d) => d !== null);
|
|
241
157
|
const ceiling = buildCeiling(docs);
|
|
242
|
-
const decisions = new Map();
|
|
243
158
|
const changes = [];
|
|
244
159
|
for (const d of docs) {
|
|
245
|
-
|
|
246
|
-
if (!d.hasOldFields && newBody === d.doc.body)
|
|
160
|
+
if (!d.hasOldFields)
|
|
247
161
|
continue;
|
|
248
|
-
const newYaml = d.
|
|
249
|
-
|
|
250
|
-
: null;
|
|
251
|
-
changes.push({ path: d.doc.path, after: rebuildSource(d, newYaml, newBody) });
|
|
162
|
+
const newYaml = migratedYaml(parseFrontmatterGeneric(d.doc.source).raw, planEntries(d, effectiveBootRung(d, ceiling)), d.doc.path);
|
|
163
|
+
changes.push({ path: d.doc.path, after: rebuildDocSource(d.doc.source, newYaml, d.doc.path) });
|
|
252
164
|
}
|
|
253
165
|
return changes;
|
|
254
166
|
},
|
|
@@ -32,6 +32,7 @@ function isMemory(value) {
|
|
|
32
32
|
return typeof value === 'string' && PROFILE_PROJECT_MEMORY_VALUES.includes(value);
|
|
33
33
|
}
|
|
34
34
|
export const profileProjectMemoryMigration = {
|
|
35
|
+
id: '002-profile-project-memory',
|
|
35
36
|
lane: 'profile-manifest',
|
|
36
37
|
description: 'profile projects carry an explicit memory value',
|
|
37
38
|
apply(input) {
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { CorpusBlocker, CorpusSnapshot, FrontDoorAction } from '../types.js';
|
|
2
|
+
import type { RepositoryDecision, StorePrefixFacts } from './repository-facts.js';
|
|
3
|
+
export interface FrontDoorPlan {
|
|
4
|
+
repositoryRoot: string;
|
|
5
|
+
/** The repository-root store's key. */
|
|
6
|
+
storeKey: string;
|
|
7
|
+
rootDocPath: string;
|
|
8
|
+
rootAction: 'kept' | 'created' | 'completed';
|
|
9
|
+
/** The unique legacy front door whose workspace-open entries this run removes. It may live
|
|
10
|
+
* in a nested store of the same repository, so it carries its own store key. */
|
|
11
|
+
leafDocPath: string | null;
|
|
12
|
+
leafStoreKey: string | null;
|
|
13
|
+
/** The leaf's FINAL canonical name, for the created root body's `[[link]]`. */
|
|
14
|
+
leafCanonicalName: string | null;
|
|
15
|
+
action: FrontDoorAction;
|
|
16
|
+
}
|
|
17
|
+
export declare function planFrontDoors(repositories: readonly RepositoryDecision[], prefixes: ReadonlyMap<string, StorePrefixFacts>, corpus: CorpusSnapshot, finalNameOf: (realPath: string) => string | undefined): {
|
|
18
|
+
plans: FrontDoorPlan[];
|
|
19
|
+
blockers: CorpusBlocker[];
|
|
20
|
+
};
|
|
21
|
+
/** New repository-root INDEX.md source. `leafCanonicalName` null yields the generic minimal root body. */
|
|
22
|
+
export declare function rootIndexSource(namespace: string, leafCanonicalName: string | null): string;
|
|
23
|
+
/** Add the missing half or halves of the root front-door pair to a complete document source. */
|
|
24
|
+
export declare function completeRootFrontDoor(source: string, docPath: string): string;
|
|
25
|
+
/** Remove every workspace-open entry while preserving the body and every retained authored YAML byte. */
|
|
26
|
+
export declare function demoteLeafSurfaces(source: string, docPath: string): string;
|