@north-light/crouter 0.3.226 → 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 +37 -9
- package/dist/daemon/api/bridge.d.ts +35 -4
- package/dist/daemon/api/bridge.js +50 -8
- 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
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { existsSync, statSync } from 'node:fs';
|
|
2
|
+
import { homedir } from 'node:os';
|
|
3
|
+
import { dirname, isAbsolute, join, relative, resolve, sep } from 'node:path';
|
|
4
|
+
import { gitSync } from '../git.js';
|
|
5
|
+
import { realpathOrSelf } from '../fs-utils.js';
|
|
6
|
+
import { CRTR_DIR_NAME } from '../../types.js';
|
|
7
|
+
import { INDEX_SEGMENT, slugCanonicalSegment, validateNamespace } from './identity.js';
|
|
8
|
+
const associationCache = new Map();
|
|
9
|
+
const GIT_LOOKUP_TIMEOUT_MS = 5000;
|
|
10
|
+
/** Normalize a POSIX-slash relative owner path into canonical segments. */
|
|
11
|
+
export function normalizeOwnerRelativePath(relPosix) {
|
|
12
|
+
const normalizedSeparators = relPosix.replace(/\\/g, '/');
|
|
13
|
+
if (normalizedSeparators === '' || normalizedSeparators === '.')
|
|
14
|
+
return { ok: true, path: '' };
|
|
15
|
+
const rawSegments = normalizedSeparators.split('/');
|
|
16
|
+
for (const segment of rawSegments) {
|
|
17
|
+
if (segment === '' || segment === '.' || segment === '..') {
|
|
18
|
+
return { ok: false, reason: `owner path contains invalid segment \`${segment}\`` };
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
const segments = rawSegments.map(slugCanonicalSegment);
|
|
22
|
+
for (let i = 0; i < segments.length; i++) {
|
|
23
|
+
if (segments[i] === '') {
|
|
24
|
+
return { ok: false, reason: `directory \`${rawSegments[i]}\` normalizes to an empty name segment` };
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
const path = segments.join('/');
|
|
28
|
+
if (segments[segments.length - 1].toLowerCase() === INDEX_SEGMENT.toLowerCase()) {
|
|
29
|
+
return { ok: false, reason: `owner path ends in reserved segment \`${INDEX_SEGMENT}\`` };
|
|
30
|
+
}
|
|
31
|
+
const check = validateNamespace(path);
|
|
32
|
+
return check.ok ? { ok: true, path } : { ok: false, reason: check.reason };
|
|
33
|
+
}
|
|
34
|
+
/** Associate one physical project-store owner with its repository identity. */
|
|
35
|
+
export function associateRepository(ownerDir) {
|
|
36
|
+
const owner = realpathOrSelf(resolve(ownerDir));
|
|
37
|
+
const cached = associationCache.get(owner);
|
|
38
|
+
if (cached !== undefined)
|
|
39
|
+
return { ok: true, association: cached };
|
|
40
|
+
const git = gitSync(['rev-parse', '--path-format=absolute', '--show-toplevel', '--git-common-dir'], owner, undefined, { timeoutMs: GIT_LOOKUP_TIMEOUT_MS });
|
|
41
|
+
if (git.status === 0 || git.timedOut === true || !/not a git repository/i.test(git.stderr)) {
|
|
42
|
+
if (git.timedOut === true) {
|
|
43
|
+
return failure('git-lookup-failed', owner, `git lookup timed out after ${GIT_LOOKUP_TIMEOUT_MS}ms`);
|
|
44
|
+
}
|
|
45
|
+
if (git.status !== 0) {
|
|
46
|
+
const detail = git.stderr.trim() || `git rev-parse exited with status ${git.status}`;
|
|
47
|
+
return failure('git-lookup-failed', owner, `git lookup failed: ${detail}`);
|
|
48
|
+
}
|
|
49
|
+
const lines = git.stdout.split(/\r?\n/);
|
|
50
|
+
const rootLine = lines[0]?.trim() ?? '';
|
|
51
|
+
const commonLine = lines[1]?.trim() ?? '';
|
|
52
|
+
if (rootLine === '' || commonLine === '') {
|
|
53
|
+
return failure('git-lookup-failed', owner, 'git lookup returned an empty repository root or common directory');
|
|
54
|
+
}
|
|
55
|
+
const repositoryRoot = realpathOrSelf(resolve(rootLine));
|
|
56
|
+
const repositoryKey = `git:${realpathOrSelf(resolve(commonLine))}`;
|
|
57
|
+
const rel = relative(repositoryRoot, owner).split(sep).join('/');
|
|
58
|
+
if (isAbsolute(rel) || rel === '..' || rel.startsWith('../')) {
|
|
59
|
+
return failure('owner-outside-root', owner, `owner ${owner} is outside repository root ${repositoryRoot}`, repositoryRoot);
|
|
60
|
+
}
|
|
61
|
+
const ownerPath = normalizeOwnerRelativePath(rel);
|
|
62
|
+
if (!ownerPath.ok)
|
|
63
|
+
return failure('owner-path-invalid', owner, ownerPath.reason, repositoryRoot);
|
|
64
|
+
return remember({
|
|
65
|
+
kind: 'git',
|
|
66
|
+
repositoryRoot,
|
|
67
|
+
repositoryKey,
|
|
68
|
+
ownerRelativePath: ownerPath.path,
|
|
69
|
+
declarationPath: join(repositoryRoot, CRTR_DIR_NAME, 'memory', 'INDEX.md'),
|
|
70
|
+
}, owner);
|
|
71
|
+
}
|
|
72
|
+
const repositoryRoot = nonGitRepositoryRoot(owner);
|
|
73
|
+
if (repositoryRoot === null)
|
|
74
|
+
return failure('no-project-root', owner, `no ancestor ${CRTR_DIR_NAME}/memory store found for ${owner}`);
|
|
75
|
+
const ownerPath = normalizeOwnerRelativePath(relative(repositoryRoot, owner).split(sep).join('/'));
|
|
76
|
+
if (!ownerPath.ok)
|
|
77
|
+
return failure('owner-path-invalid', owner, ownerPath.reason, repositoryRoot);
|
|
78
|
+
return remember({
|
|
79
|
+
kind: 'non-git',
|
|
80
|
+
repositoryRoot,
|
|
81
|
+
repositoryKey: `path:${repositoryRoot}`,
|
|
82
|
+
ownerRelativePath: ownerPath.path,
|
|
83
|
+
declarationPath: join(repositoryRoot, CRTR_DIR_NAME, 'memory', 'INDEX.md'),
|
|
84
|
+
}, owner);
|
|
85
|
+
}
|
|
86
|
+
/** Clear successful associations; failures are deliberately never cached. */
|
|
87
|
+
export function resetRepositoryAssociationCache() {
|
|
88
|
+
associationCache.clear();
|
|
89
|
+
}
|
|
90
|
+
function remember(association, owner) {
|
|
91
|
+
associationCache.set(owner, association);
|
|
92
|
+
return { ok: true, association };
|
|
93
|
+
}
|
|
94
|
+
function failure(code, ownerDir, reason, repositoryRoot) {
|
|
95
|
+
return repositoryRoot === undefined
|
|
96
|
+
? { ok: false, code, ownerDir, reason }
|
|
97
|
+
: { ok: false, code, ownerDir, repositoryRoot, reason };
|
|
98
|
+
}
|
|
99
|
+
function nonGitRepositoryRoot(owner) {
|
|
100
|
+
const home = realpathOrSelf(homedir());
|
|
101
|
+
const ownerIsUnderHome = isWithin(owner, home);
|
|
102
|
+
let dir = owner;
|
|
103
|
+
let outermost = null;
|
|
104
|
+
while (true) {
|
|
105
|
+
// The user's own .crouter/memory is a separate scope, never a project root.
|
|
106
|
+
if ((!ownerIsUnderHome || dir !== home) && hasProjectMemoryStore(dir))
|
|
107
|
+
outermost = dir;
|
|
108
|
+
if (ownerIsUnderHome && dir === home)
|
|
109
|
+
break;
|
|
110
|
+
const parent = dirname(dir);
|
|
111
|
+
if (parent === dir)
|
|
112
|
+
break;
|
|
113
|
+
dir = parent;
|
|
114
|
+
}
|
|
115
|
+
return outermost;
|
|
116
|
+
}
|
|
117
|
+
function hasProjectMemoryStore(owner) {
|
|
118
|
+
const memory = join(owner, CRTR_DIR_NAME, 'memory');
|
|
119
|
+
try {
|
|
120
|
+
return existsSync(memory) && statSync(memory).isDirectory();
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
function isWithin(child, parent) {
|
|
127
|
+
const rel = relative(parent, child);
|
|
128
|
+
return rel === '' || (rel !== '..' && !rel.startsWith(`..${sep}`) && !isAbsolute(rel));
|
|
129
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { MemoryDoc } from '../memory-resolver.js';
|
|
2
|
+
/** One canonical directory row: its own document (when it has one) plus its
|
|
3
|
+
* immediate members. */
|
|
4
|
+
export interface MemoryTreeNode {
|
|
5
|
+
/** Exact canonical identity. `''` is the corpus root, which holds no
|
|
6
|
+
* document — every store's documents merge beneath it. */
|
|
7
|
+
name: string;
|
|
8
|
+
/** Sort key among siblings: the stored physical path segment, `NN-` ordering
|
|
9
|
+
* prefix retained, or this node's canonical segment when no physical
|
|
10
|
+
* segment aligns. */
|
|
11
|
+
order: string;
|
|
12
|
+
/** The winning document attached to this row, or null for a directory that
|
|
13
|
+
* carries none. */
|
|
14
|
+
document: MemoryDoc | null;
|
|
15
|
+
/** Every physical document sharing this identity, in source order. */
|
|
16
|
+
documentCandidates: readonly MemoryDoc[];
|
|
17
|
+
/** Immediate children that have members of their own, ordered. Each may also
|
|
18
|
+
* carry its own `document`. */
|
|
19
|
+
childDirectories: readonly MemoryTreeNode[];
|
|
20
|
+
/** Immediate childless members, ordered. A node's own document never appears
|
|
21
|
+
* among its children. */
|
|
22
|
+
childDocuments: readonly MemoryTreeDocumentNode[];
|
|
23
|
+
}
|
|
24
|
+
/** A childless node: it exists only because a document landed on it. */
|
|
25
|
+
export interface MemoryTreeDocumentNode extends MemoryTreeNode {
|
|
26
|
+
document: MemoryDoc;
|
|
27
|
+
}
|
|
28
|
+
export interface MemoryTree {
|
|
29
|
+
root: MemoryTreeNode;
|
|
30
|
+
/** The node at an exact canonical name, or null when nothing lives there. */
|
|
31
|
+
node(name: string): MemoryTreeNode | null;
|
|
32
|
+
/** Does this canonical name have members? True for the corpus root when the
|
|
33
|
+
* corpus is non-empty. */
|
|
34
|
+
isDirectory(name: string): boolean;
|
|
35
|
+
}
|
|
36
|
+
/** Merge a precedence-ordered corpus into the canonical tree. Documents sharing
|
|
37
|
+
* one identity stay in source order behind that node, so its `document` is the
|
|
38
|
+
* address winner. */
|
|
39
|
+
export declare function buildMemoryTree(docs: readonly MemoryDoc[]): MemoryTree;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
// tree.ts — the ONE canonical directory model. A canonical name is a path in a
|
|
2
|
+
// tree whose nodes merge across stores: a node holds the winning document at
|
|
3
|
+
// that exact identity (with every physical candidate behind it) AND its
|
|
4
|
+
// immediate children, so a directory that carries its own document is one row,
|
|
5
|
+
// never a document plus a separate directory of the same name. Listing
|
|
6
|
+
// generation, boot render, inline inventory, and lint all read structure from
|
|
7
|
+
// here instead of scanning name prefixes.
|
|
8
|
+
import { canonicalSegments, normalizeNameSegment } from './identity.js';
|
|
9
|
+
/** The stored physical segments a document supplies as ordering keys for itself
|
|
10
|
+
* and its canonical ancestors. Both names are walked from the TAIL and stop at
|
|
11
|
+
* the first mismatch, because no canonical segment index addresses a physical
|
|
12
|
+
* one: a store's namespace has no physical counterpart at all, and an explicit
|
|
13
|
+
* `name:` detaches identity from the path entirely. */
|
|
14
|
+
function physicalOrderSegments(doc) {
|
|
15
|
+
const canonical = canonicalSegments(doc.name);
|
|
16
|
+
const physical = canonicalSegments(doc.physicalRelativePath.replace(/\.md$/i, ''));
|
|
17
|
+
// The INDEX filename names its directory, not a segment of its own.
|
|
18
|
+
if (doc.representation === 'directory-index')
|
|
19
|
+
physical.pop();
|
|
20
|
+
const keys = [];
|
|
21
|
+
for (let i = canonical.length - 1, j = physical.length - 1; i >= 0 && j >= 0; i--, j--) {
|
|
22
|
+
const segment = physical[j];
|
|
23
|
+
if (normalizeNameSegment(segment) !== canonical[i])
|
|
24
|
+
break;
|
|
25
|
+
keys.push([canonical.slice(0, i + 1).join('/'), segment]);
|
|
26
|
+
}
|
|
27
|
+
return keys;
|
|
28
|
+
}
|
|
29
|
+
function hasMembers(node) {
|
|
30
|
+
return node.childDirectories.length > 0 || node.childDocuments.length > 0;
|
|
31
|
+
}
|
|
32
|
+
function compareNodes(a, b) {
|
|
33
|
+
return a.order.localeCompare(b.order) || a.name.localeCompare(b.name);
|
|
34
|
+
}
|
|
35
|
+
function asDocumentNode(node) {
|
|
36
|
+
if (node.document === null)
|
|
37
|
+
throw new Error(`memory tree: ${node.name} has neither a document nor members`);
|
|
38
|
+
return node;
|
|
39
|
+
}
|
|
40
|
+
function finalize(pending, order, index) {
|
|
41
|
+
const children = [...pending.children.values()]
|
|
42
|
+
.map((child) => finalize(child, order, index))
|
|
43
|
+
.sort(compareNodes);
|
|
44
|
+
const segments = canonicalSegments(pending.name);
|
|
45
|
+
const node = {
|
|
46
|
+
name: pending.name,
|
|
47
|
+
order: order.get(pending.name) ?? segments[segments.length - 1] ?? '',
|
|
48
|
+
document: pending.documents[0] ?? null,
|
|
49
|
+
documentCandidates: pending.documents,
|
|
50
|
+
childDirectories: children.filter(hasMembers),
|
|
51
|
+
childDocuments: children.filter((child) => !hasMembers(child)).map(asDocumentNode),
|
|
52
|
+
};
|
|
53
|
+
index.set(node.name, node);
|
|
54
|
+
return node;
|
|
55
|
+
}
|
|
56
|
+
/** Merge a precedence-ordered corpus into the canonical tree. Documents sharing
|
|
57
|
+
* one identity stay in source order behind that node, so its `document` is the
|
|
58
|
+
* address winner. */
|
|
59
|
+
export function buildMemoryTree(docs) {
|
|
60
|
+
const root = { name: '', documents: [], children: new Map() };
|
|
61
|
+
const order = new Map();
|
|
62
|
+
for (const doc of docs) {
|
|
63
|
+
const segments = canonicalSegments(doc.name);
|
|
64
|
+
if (segments.length === 0)
|
|
65
|
+
continue;
|
|
66
|
+
let node = root;
|
|
67
|
+
for (let i = 0; i < segments.length; i++) {
|
|
68
|
+
const segment = segments[i];
|
|
69
|
+
let child = node.children.get(segment);
|
|
70
|
+
if (child === undefined) {
|
|
71
|
+
child = { name: segments.slice(0, i + 1).join('/'), documents: [], children: new Map() };
|
|
72
|
+
node.children.set(segment, child);
|
|
73
|
+
}
|
|
74
|
+
node = child;
|
|
75
|
+
}
|
|
76
|
+
node.documents.push(doc);
|
|
77
|
+
for (const [name, segment] of physicalOrderSegments(doc)) {
|
|
78
|
+
if (!order.has(name))
|
|
79
|
+
order.set(name, segment);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
const index = new Map();
|
|
83
|
+
const rootNode = finalize(root, order, index);
|
|
84
|
+
const lookup = (name) => index.get(canonicalSegments(name).join('/')) ?? null;
|
|
85
|
+
return {
|
|
86
|
+
root: rootNode,
|
|
87
|
+
node: lookup,
|
|
88
|
+
isDirectory: (name) => {
|
|
89
|
+
const node = lookup(name);
|
|
90
|
+
return node !== null && hasMembers(node);
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
}
|
|
@@ -1,79 +1,144 @@
|
|
|
1
1
|
import { type InstalledPlugin, type Scope } from '../types.js';
|
|
2
2
|
import type { ProfileProjectMemory } from '../api/dto/profiles.js';
|
|
3
|
+
import { type DocRepresentation } from './memory/identity.js';
|
|
3
4
|
/**
|
|
4
|
-
*
|
|
5
|
-
* two passes. First, scopes/sources are tried NEAREST-FIRST (node > project
|
|
6
|
-
* stack nearest > ... > profile > user > builtin) for strong matches: (1) exact
|
|
7
|
-
* substrate identity (`doc.name === query` — the explicit frontmatter `name`,
|
|
8
|
-
* or its path-derived fallback), then (2) direct `memory/<name>.md` physical
|
|
9
|
-
* path. A directory name resolves to NO doc — the read leaf answers it with
|
|
10
|
-
* the directory's listing. Only when no source has a strong
|
|
11
|
-
* match does a second nearest-first pass try bare leaf-name fallback (final
|
|
12
|
-
* path segment only). Thus scope precedence resolves competing strong matches,
|
|
13
|
-
* while a nearer nested doc's coincidental leaf can never shadow a farther
|
|
14
|
-
* canonical identity. It returns the raw parsed frontmatter + body;
|
|
15
|
-
* it does NOT interpret the schema, kind, gate, or rungs — that is the
|
|
16
|
-
* schema/gate layer's job (callers filter by `frontmatter.kind`). Project
|
|
17
|
-
* resolution is a nearest-first stack of every ancestor `.crouter/` (widened by
|
|
18
|
-
* a selected profile's `projects` manifest entries — see `findProjectScopeRoots`
|
|
19
|
-
* in scope.ts), profile is the selected profile's own singleton `memory/` store
|
|
20
|
-
* (from `CRTR_PROFILE_ID`), and user/builtin remain singleton scopes.
|
|
5
|
+
* Memory-document loading and resolution for the document substrate.
|
|
21
6
|
*
|
|
22
|
-
* Every
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
7
|
+
* Every document belongs to exactly one physical STORE. A store declares a
|
|
8
|
+
* namespace — a project's `namespace:` on its root `INDEX.md`, an installed
|
|
9
|
+
* plugin's mount prefix, or empty for user/profile/node/builtin — and every
|
|
10
|
+
* document's CANONICAL name is that namespace composed with the document's
|
|
11
|
+
* store-local name (see memory/identity.ts). The canonical name is the only
|
|
12
|
+
* address: resolution compares the normalized query with canonical identities
|
|
13
|
+
* and nothing else. There is no physical-path pass, no bare-leaf pass, no
|
|
14
|
+
* scope-prefixed spelling, and no `<dir>/INDEX` address — a trailing `INDEX`
|
|
15
|
+
* segment collapses, so a directory's own document answers at the directory
|
|
16
|
+
* name and `memory find` is the discovery surface when the name is unknown.
|
|
17
|
+
*
|
|
18
|
+
* A project store whose repository root carries no valid `namespace:` does not mount: its
|
|
19
|
+
* documents are absent from every target view, and its descriptor carries the
|
|
20
|
+
* `crtr sys migrate --dir <repository root>` remedy. Exact-store inspection
|
|
21
|
+
* (`openProjectMemoryStore` + `loadMemoryStoreView`) still loads it, which is
|
|
22
|
+
* what lint and migration diagnose an unmounted store through.
|
|
23
|
+
*
|
|
24
|
+
* Two views exist over the same loader:
|
|
25
|
+
* - a TARGET view — the ordered source stack of one cwd/profile/node
|
|
26
|
+
* (node > project stores nearest-first > profile > user > builtin, native
|
|
27
|
+
* documents before enabled-plugin documents within each source). Alternate
|
|
28
|
+
* physical stores legitimately expose the same canonical identity (a linked
|
|
29
|
+
* worktree, a generated copy), so a name yields an ordered CANDIDATE set:
|
|
30
|
+
* source order picks the address winner, every later candidate stays
|
|
31
|
+
* inspectable.
|
|
32
|
+
* - an exact STORE view — one physical project store selected by owner
|
|
33
|
+
* directory, which still requires the full canonical query.
|
|
34
|
+
*
|
|
35
|
+
* Resolution never consults a project store's profile memory ceiling
|
|
36
|
+
* (`projectMemory`); the full corpus resolves and lists regardless, and only
|
|
37
|
+
* automatic delivery clamps against it.
|
|
26
38
|
*/
|
|
39
|
+
/** The memory-only scope union: the global `Scope` (`user|project|builtin`)
|
|
40
|
+
* plus `profile` and `node`. Confined to the memory resolver/list/read/write/
|
|
41
|
+
* render paths — deliberately NOT folded into the global `Scope` union, because
|
|
42
|
+
* that would leak these into config, plugin, marketplace, and sys-config
|
|
43
|
+
* surfaces the spec does not extend. `node` is the this-node store
|
|
44
|
+
* (`nodes/<id>/context/memory/`), available only inside a running node
|
|
45
|
+
* (`CRTR_NODE_ID`), and it is the NEAREST scope — a node doc overrides a
|
|
46
|
+
* same-named doc at any wider scope. */
|
|
47
|
+
export type MemoryScope = Scope | 'profile' | 'node';
|
|
48
|
+
/** Whether a store contributes to target views.
|
|
49
|
+
* `absent` — no `memory/` dir on disk (silent, the ordinary case).
|
|
50
|
+
* `undeclared`/`invalid` — a project store the runtime refuses to mount until
|
|
51
|
+
* its namespace is declared; `diagnostic` carries the migration remedy. */
|
|
52
|
+
export type MemoryStoreMountStatus = 'ready' | 'absent' | 'undeclared' | 'invalid';
|
|
53
|
+
/** One physical memory store: where its documents live, what namespace their
|
|
54
|
+
* canonical names compose under, and whether it mounts. */
|
|
55
|
+
export interface MemoryStoreDescriptor {
|
|
56
|
+
scope: MemoryScope;
|
|
57
|
+
/** Absolute path of the physical `memory/` dir. Store identity (and the
|
|
58
|
+
* dedup of one real store reached twice) uses its realpath. */
|
|
59
|
+
storeRoot: string;
|
|
60
|
+
/** The project directory containing `.crouter/`, for project stores only. */
|
|
61
|
+
ownerDir?: string;
|
|
62
|
+
/** Effective project prefix, repository-root namespace composed with the
|
|
63
|
+
* owner-relative path; installed-plugin mount prefix, or `''`. */
|
|
64
|
+
namespace: string;
|
|
65
|
+
/** The repository-root `INDEX.md` a project namespace is declared on, when
|
|
66
|
+
* association succeeds — present even for an undeclared/invalid store so
|
|
67
|
+
* lint and migration can point at it. */
|
|
68
|
+
namespacePath?: string;
|
|
69
|
+
/** Absolute realpath of the associated repository root, for project stores. */
|
|
70
|
+
repositoryRoot?: string;
|
|
71
|
+
/** Linked-worktree/non-Git grouping key, for project stores. */
|
|
72
|
+
repositoryKey?: string;
|
|
73
|
+
/** Valid namespace read from the repository-root declaration. */
|
|
74
|
+
repositoryNamespace?: string;
|
|
75
|
+
/** Canonical owner path relative to the repository root, empty at the root. */
|
|
76
|
+
ownerRelativePath?: string;
|
|
77
|
+
/** Structured cause for a project store that does not mount. */
|
|
78
|
+
mountFailure?: 'association' | 'collision' | 'undeclared-root' | 'invalid-root';
|
|
79
|
+
/** The owning plugin's name for a plugin-mounted store. Plugin docs surface
|
|
80
|
+
* within a source scope but live under the plugins dir and are managed by
|
|
81
|
+
* `crtr pkg`, so consumers that mutate the store gate on this. */
|
|
82
|
+
plugin?: string;
|
|
83
|
+
mountStatus: MemoryStoreMountStatus;
|
|
84
|
+
/** Why a non-`ready` store does not mount, with its actionable remedy. */
|
|
85
|
+
diagnostic?: string;
|
|
86
|
+
/** The selected profile relationship's ceiling for this store: the maximum
|
|
87
|
+
* rung AUTOMATIC boot and workspace-open delivery may disclose it at.
|
|
88
|
+
* Neutral (`content`) for every non-project store. */
|
|
89
|
+
projectMemory: ProfileProjectMemory;
|
|
90
|
+
}
|
|
27
91
|
export interface MemoryDoc {
|
|
28
|
-
/**
|
|
29
|
-
*
|
|
30
|
-
* memory/taste/foo.md → "taste/foo". */
|
|
92
|
+
/** Canonical identity — the store's namespace composed with `localName`, and
|
|
93
|
+
* the only address resolution accepts. */
|
|
31
94
|
name: string;
|
|
95
|
+
/** Store-local identity: the explicit frontmatter `name` when present, else
|
|
96
|
+
* derived from the store-relative path with ordering prefixes stripped and
|
|
97
|
+
* one trailing `INDEX` collapsed. Empty for a store's root document. */
|
|
98
|
+
localName: string;
|
|
32
99
|
scope: MemoryScope;
|
|
33
100
|
/** Absolute path to the resolved .md file. */
|
|
34
101
|
path: string;
|
|
35
102
|
/** Absolute path of the `memory/` dir this doc loaded from — the store root
|
|
36
|
-
* its
|
|
37
|
-
* revision-history log) are derived from `path` relative to this.
|
|
38
|
-
* plugin doc it is that plugin's own memory dir. */
|
|
103
|
+
* its physical path is relative to. Sidecar trees that mirror the doc tree
|
|
104
|
+
* (the revision-history log) are derived from `path` relative to this. */
|
|
39
105
|
root: string;
|
|
106
|
+
/** Store-relative markdown path, kept exactly: placement, ordering, origin,
|
|
107
|
+
* and history depend on the physical form, never on segment counts of the
|
|
108
|
+
* canonical name. */
|
|
109
|
+
physicalRelativePath: string;
|
|
110
|
+
/** Which physical form owns this identity — `foo.md` or `foo/INDEX.md`. */
|
|
111
|
+
representation: DocRepresentation;
|
|
112
|
+
/** The canonical directory this doc's `./` memory-read entries match against:
|
|
113
|
+
* its own name for a directory document, its parent for a leaf. */
|
|
114
|
+
routingAnchor: string;
|
|
115
|
+
store: MemoryStoreDescriptor;
|
|
40
116
|
/** Raw, uncoerced frontmatter record (null when the doc has no frontmatter). */
|
|
41
117
|
frontmatter: Record<string, unknown> | null;
|
|
42
118
|
/** Document body, with the frontmatter block stripped. */
|
|
43
119
|
body: string;
|
|
44
|
-
/** Set to the owning plugin's name when this doc is mounted from an installed
|
|
45
|
-
* plugin (under `<pluginName>/`), undefined for a native scope doc. Plugin
|
|
46
|
-
* docs surface within a source scope but live under the plugins dir and are
|
|
47
|
-
* managed by `crtr pkg`, not writable/deletable as scope docs — consumers
|
|
48
|
-
* that mutate the store gate on this. */
|
|
49
120
|
plugin?: string;
|
|
50
|
-
/** The selected profile relationship's ceiling for the project store this doc
|
|
51
|
-
* came from: the maximum rung AUTOMATIC boot and workspace-open delivery may
|
|
52
|
-
* disclose it at. Always present; `content` (neutral, i.e. uncapped) for
|
|
53
|
-
* every non-project scope and for a project root no profile entry
|
|
54
|
-
* contributes. Resolution, listing, and targeted reads ignore it entirely. */
|
|
55
121
|
projectMemory: ProfileProjectMemory;
|
|
56
122
|
}
|
|
57
|
-
/**
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
/** Restrict resolution to docs whose resolved kind matches. Threaded INTO
|
|
71
|
-
* precedence, not applied as a post-resolution filter: within each source,
|
|
72
|
-
* a doc whose kind doesn't match is skipped (not returned), so a nearer
|
|
73
|
-
* source's wrong-kind doc can no longer shadow a farther source's
|
|
74
|
-
* matching-kind doc into a false not_found — resolution simply continues
|
|
75
|
-
* to the next source. See `effectiveDocKind` for the kind coercion. */
|
|
123
|
+
/** Every physical document sharing one canonical identity in a view, in source
|
|
124
|
+
* order. `winner` is the address a deliberate read resolves to; automatic
|
|
125
|
+
* delivery filters the ordered candidates for its own event eligibility. */
|
|
126
|
+
export interface MemoryCandidateSet {
|
|
127
|
+
name: string;
|
|
128
|
+
winner: MemoryDoc;
|
|
129
|
+
candidates: readonly MemoryDoc[];
|
|
130
|
+
}
|
|
131
|
+
/** Restrict resolution to docs whose resolved kind matches. Threaded INTO
|
|
132
|
+
* candidate selection, not applied as a post-filter: a wrong-kind candidate is
|
|
133
|
+
* skipped so a nearer one cannot shadow a farther matching-kind document into
|
|
134
|
+
* a false not_found. */
|
|
135
|
+
export interface MemoryCandidateOpts {
|
|
76
136
|
kind?: string;
|
|
137
|
+
}
|
|
138
|
+
export interface MemoryResolutionOpts extends MemoryCandidateOpts {
|
|
139
|
+
/** Restrict resolution to a single scope. Narrows the source stack only — the
|
|
140
|
+
* query is still the full canonical name. */
|
|
141
|
+
scope?: MemoryScope;
|
|
77
142
|
/** Also consult `.crouter/memory` stores discovered BELOW the mounted
|
|
78
143
|
* project roots (bounded discovery — see nested-stores.ts). Opt-in for the
|
|
79
144
|
* addressing surfaces (`memory read/list/find/lint/delete/origin`); OFF for
|
|
@@ -81,17 +146,26 @@ export interface MemoryResolutionOpts {
|
|
|
81
146
|
* persona resolution, which stay on the flat ancestor+profile stack. */
|
|
82
147
|
includeDescendants?: boolean;
|
|
83
148
|
}
|
|
84
|
-
/**
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
|
|
149
|
+
/** A loaded corpus and the exact-identity queries over it. */
|
|
150
|
+
export interface MemoryView {
|
|
151
|
+
/** Every store the view discovered, mounted or not, in precedence order. */
|
|
152
|
+
stores: readonly MemoryStoreDescriptor[];
|
|
153
|
+
/** Every document of every MOUNTED store, in source order — candidates
|
|
154
|
+
* included, so a first-wins dedup by name yields the winners. */
|
|
155
|
+
docs: readonly MemoryDoc[];
|
|
156
|
+
/** The ordered candidate set for one exact canonical name, or null. */
|
|
157
|
+
candidates(name: string, opts?: MemoryCandidateOpts): MemoryCandidateSet | null;
|
|
158
|
+
/** One entry per canonical identity, sorted by name. */
|
|
159
|
+
candidateSets(opts?: MemoryCandidateOpts): MemoryCandidateSet[];
|
|
160
|
+
/** The address winner for one exact canonical name; throws not_found. */
|
|
161
|
+
resolve(name: string, opts?: MemoryCandidateOpts): MemoryDoc;
|
|
162
|
+
}
|
|
163
|
+
export interface MemoryTargetView extends MemoryView {
|
|
164
|
+
target: MemoryTarget;
|
|
165
|
+
}
|
|
166
|
+
export interface MemoryStoreView extends MemoryView {
|
|
167
|
+
store: MemoryStoreDescriptor;
|
|
168
|
+
}
|
|
95
169
|
/** Whose memory view is being resolved: the workspace dir, profile, and node
|
|
96
170
|
* id that decide which stores exist and in what order. Ambient resolution
|
|
97
171
|
* builds this from the process (`process.cwd()`, `CRTR_PROFILE_ID`,
|
|
@@ -110,16 +184,41 @@ export interface MemoryTarget {
|
|
|
110
184
|
* or null outside a node. */
|
|
111
185
|
nodeId: string | null;
|
|
112
186
|
}
|
|
113
|
-
/**
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
*
|
|
120
|
-
|
|
121
|
-
|
|
187
|
+
/** The exact project store owned by `ownerDir` — the `--dir` selector's store,
|
|
188
|
+
* loaded whatever its mount status so lint and migration can inspect a store
|
|
189
|
+
* the runtime refuses to mount. */
|
|
190
|
+
export declare function openProjectMemoryStore(ownerDir: string): MemoryStoreDescriptor;
|
|
191
|
+
/** Every store a target sees, in precedence order: node, each project store
|
|
192
|
+
* nearest-first (its enabled plugins after it), then profile, user, builtin.
|
|
193
|
+
* One real store reached twice contributes once, at its first position. */
|
|
194
|
+
export declare function memoryStoresInPrecedence(target: MemoryTarget, scope?: MemoryScope, includeDescendants?: boolean): MemoryStoreDescriptor[];
|
|
195
|
+
/** The native (non-plugin) MOUNTED store dirs in resolution precedence.
|
|
196
|
+
* Addresses a store directly when the document itself may be absent, which is
|
|
197
|
+
* how a DELETED doc's revision log is still found: history outlives the doc,
|
|
198
|
+
* so its lookup cannot go through document resolution. */
|
|
199
|
+
export declare function nativeMemoryStoresInPrecedence(scope?: MemoryScope, includeDescendants?: boolean): {
|
|
200
|
+
scope: MemoryScope;
|
|
201
|
+
memoryDir: string;
|
|
202
|
+
store: MemoryStoreDescriptor;
|
|
203
|
+
}[];
|
|
204
|
+
/** Every document in one store, sorted by canonical identity. SKILL.md bundles
|
|
205
|
+
* are Agent Skills, not memory docs. Enumeration stops at a nested `.crouter/`:
|
|
206
|
+
* that is another store's mount point, never this store's content. */
|
|
207
|
+
export declare function loadStoreMemoryDocs(store: MemoryStoreDescriptor, quiet?: boolean): MemoryDoc[];
|
|
208
|
+
/** All of one plugin's substrate docs, mounted under the plugin's own name:
|
|
209
|
+
* each doc's store-local name (explicit or path-derived) composes under that
|
|
210
|
+
* mount prefix. */
|
|
122
211
|
export declare function listPluginMemoryDocs(plugin: InstalledPlugin, scope: MemoryScope, quiet?: boolean, projectMemory?: ProfileProjectMemory): MemoryDoc[];
|
|
212
|
+
/** Load one target's whole corpus: every mounted store's documents in source
|
|
213
|
+
* order. A project store that does not mount is reported once (unless quiet)
|
|
214
|
+
* with its migration remedy and contributes nothing. */
|
|
215
|
+
export declare function loadMemoryTargetView(target: MemoryTarget, opts?: MemoryResolutionOpts & {
|
|
216
|
+
quiet?: boolean;
|
|
217
|
+
}): MemoryTargetView;
|
|
218
|
+
/** Load ONE exact physical store. An undeclared/invalid project store loads
|
|
219
|
+
* under the empty namespace so lint and migration can inspect what it holds;
|
|
220
|
+
* no target view ever sees those documents. */
|
|
221
|
+
export declare function loadMemoryStoreView(store: MemoryStoreDescriptor, quiet?: boolean): MemoryStoreView;
|
|
123
222
|
/** All project-scoped docs visible from an explicit node workspace/profile — the
|
|
124
223
|
* project-only slice of a `MemoryTarget` view, used where only workspace docs
|
|
125
224
|
* are wanted (a workspace-open render). For a full-precedence target-addressed
|
|
@@ -128,31 +227,22 @@ export declare function listProjectMemoryDocs(startDir?: string, profileId?: str
|
|
|
128
227
|
/** All memory docs across the resolved sources, in precedence order: each
|
|
129
228
|
* ancestor project `.crouter/` from nearest to farthest, then the selected
|
|
130
229
|
* profile's memory (if any), then user, then builtin. Within each source,
|
|
131
|
-
* native docs are emitted before enabled-plugin docs,
|
|
132
|
-
* caller's first-wins dedup
|
|
230
|
+
* native docs are emitted before enabled-plugin docs, and equal-canonical
|
|
231
|
+
* candidates stay in source order, so a caller's first-wins dedup yields the
|
|
232
|
+
* address winners. */
|
|
133
233
|
export declare function listAllMemoryDocs(scope?: MemoryScope, quiet?: boolean, includeDescendants?: boolean): MemoryDoc[];
|
|
134
|
-
/** Resolve a document NAME against a `.history` tree, which mirrors the doc
|
|
135
|
-
* tree segment for segment with `.jsonl` in place of `.md`. Reuses the doc
|
|
136
|
-
* resolution rules so a log outlives its doc under the same name the doc had:
|
|
137
|
-
* numeric prefixes stay prefix-blind (`00-topic.md` logged at
|
|
138
|
-
* `.history/00-topic.jsonl` still answers to `topic`). Returns null when
|
|
139
|
-
* nothing resolves. */
|
|
140
|
-
export declare function resolveHistoryLogPath(historyDir: string, segments: string[]): string | null;
|
|
141
234
|
export interface MemoryDocSnapshot {
|
|
142
235
|
/** Every document in default scope precedence order, loaded once. */
|
|
143
236
|
docs: readonly MemoryDoc[];
|
|
144
237
|
/** Resolve names against that source snapshot; failures are omitted so
|
|
145
238
|
* callers can retain their own per-document error behavior. */
|
|
146
239
|
resolve(names: readonly string[]): Map<string, MemoryDoc>;
|
|
147
|
-
/** Frozen pre-cut resolution used only by the surfaces migration: return the
|
|
148
|
-
* explicit INDEX spelling when a bare directory/plugin ref and that spelling
|
|
149
|
-
* resolve to the same file in this target corpus. */
|
|
150
|
-
legacyDirectoryIndex(name: string): string | null;
|
|
151
240
|
}
|
|
152
241
|
export declare function createMemoryDocSnapshot(target?: MemoryTarget): MemoryDocSnapshot;
|
|
153
|
-
/** Resolve several
|
|
242
|
+
/** Resolve several canonical names over one memory-source snapshot. Failed
|
|
154
243
|
* names are omitted so callers can preserve their per-document error behavior. */
|
|
155
244
|
export declare function resolveMemoryDocs(names: readonly string[]): Map<string, MemoryDoc>;
|
|
245
|
+
/** The address winner for an exact canonical name in the ambient target. */
|
|
156
246
|
export declare function resolveMemoryDoc(rawName: string, opts?: MemoryResolutionOpts): MemoryDoc;
|
|
157
247
|
/** Resolve a memory document as ANOTHER node would see it — the same precedence
|
|
158
248
|
* chain (node-local > project stack > profile > user > builtin), read from the
|
|
@@ -160,3 +250,16 @@ export declare function resolveMemoryDoc(rawName: string, opts?: MemoryResolutio
|
|
|
160
250
|
* resolves a `[[name]]` link through: the daemon's own cwd and env name no
|
|
161
251
|
* node, and the same name can be a different document for two nodes. */
|
|
162
252
|
export declare function resolveMemoryDocForTarget(rawName: string, target: MemoryTarget, opts?: MemoryResolutionOpts): MemoryDoc;
|
|
253
|
+
/** Every physical candidate for an exact canonical name in the ambient target,
|
|
254
|
+
* in source order — what path-aware inventory, diagnostics, and automatic
|
|
255
|
+
* event eligibility consume instead of the winner alone. */
|
|
256
|
+
export declare function resolveMemoryCandidates(rawName: string, opts?: MemoryResolutionOpts): MemoryCandidateSet;
|
|
257
|
+
export declare function resolveMemoryCandidatesForTarget(rawName: string, target: MemoryTarget, opts?: MemoryResolutionOpts): MemoryCandidateSet;
|
|
258
|
+
/** The address winner for an exact canonical name inside ONE project store —
|
|
259
|
+
* the `--dir` selector's resolution. The query is still the full canonical
|
|
260
|
+
* name, including that store's namespace. */
|
|
261
|
+
export declare function resolveMemoryDocInStore(rawName: string, store: MemoryStoreDescriptor, opts?: MemoryCandidateOpts): MemoryDoc;
|
|
262
|
+
/** Resolve PHYSICAL path segments against a `.history` tree, which mirrors the
|
|
263
|
+
* doc tree segment for segment with `.jsonl` in place of `.md`. A log outlives
|
|
264
|
+
* its document, so this lookup cannot go through document resolution. */
|
|
265
|
+
export declare function resolveHistoryLogPath(historyDir: string, segments: string[]): string | null;
|