@north-light/crouter 0.3.208 → 0.3.210
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 +3 -1
- package/dist/api/client.js +4 -0
- package/dist/api/dto/broker-ops.d.ts +2 -12
- package/dist/api/dto/nodes.d.ts +16 -0
- package/dist/api/routes.d.ts +1 -0
- package/dist/api/routes.js +1 -0
- package/dist/builtin-memory/00-runtime-base.md +3 -2
- package/dist/builtin-memory/01-spine/00-has-manager.md +3 -2
- package/dist/builtin-memory/01-spine/01-no-manager.md +3 -2
- package/dist/builtin-memory/02-lifecycle/00-terminal.md +3 -2
- package/dist/builtin-memory/02-lifecycle/01-resident.md +3 -2
- package/dist/builtin-memory/04-base-worker.md +3 -2
- package/dist/builtin-memory/04-orchestration-kernel.md +3 -2
- package/dist/builtin-memory/05-kinds/advisor/00-base.md +3 -2
- package/dist/builtin-memory/05-kinds/advisor/01-orchestrator.md +3 -2
- package/dist/builtin-memory/05-kinds/design/00-base.md +3 -2
- package/dist/builtin-memory/05-kinds/design/01-orchestrator.md +3 -2
- package/dist/builtin-memory/05-kinds/developer/00-base.md +3 -2
- package/dist/builtin-memory/05-kinds/developer/01-orchestrator.md +3 -2
- package/dist/builtin-memory/05-kinds/explore/00-base.md +3 -2
- package/dist/builtin-memory/05-kinds/explore/01-orchestrator.md +3 -2
- package/dist/builtin-memory/05-kinds/general/00-base.md +3 -2
- package/dist/builtin-memory/05-kinds/general/01-orchestrator.md +3 -2
- package/dist/builtin-memory/05-kinds/plan/00-base.md +3 -2
- package/dist/builtin-memory/05-kinds/plan/01-orchestrator.md +3 -2
- package/dist/builtin-memory/05-kinds/plan/reviewers/00-base.md +3 -2
- package/dist/builtin-memory/05-kinds/plan/reviewers/architecture-fit.md +3 -2
- package/dist/builtin-memory/05-kinds/plan/reviewers/code-smells.md +3 -2
- package/dist/builtin-memory/05-kinds/plan/reviewers/pattern-consistency.md +3 -2
- package/dist/builtin-memory/05-kinds/plan/reviewers/requirements-coverage.md +3 -2
- package/dist/builtin-memory/05-kinds/plan/reviewers/security.md +3 -2
- package/dist/builtin-memory/05-kinds/review/00-base.md +3 -2
- package/dist/builtin-memory/05-kinds/review/01-orchestrator.md +3 -2
- package/dist/builtin-memory/05-kinds/review/companion/00-base.md +3 -2
- package/dist/builtin-memory/05-kinds/spec/00-base.md +3 -2
- package/dist/builtin-memory/05-kinds/spec/01-orchestrator.md +3 -2
- package/dist/builtin-memory/05-kinds/spec/requirements.md +3 -2
- package/dist/builtin-memory/advisor/council.md +0 -2
- package/dist/builtin-memory/design.md +3 -2
- package/dist/builtin-memory/development.md +3 -2
- package/dist/builtin-memory/insights/capture.md +1 -3
- package/dist/builtin-memory/insights/init.md +1 -3
- package/dist/builtin-memory/insights/listen.md +3 -2
- package/dist/builtin-memory/internal/INDEX.md +5 -4
- package/dist/builtin-memory/internal/agent-shaping.md +5 -4
- package/dist/builtin-memory/internal/examples/INDEX.md +3 -2
- package/dist/builtin-memory/internal/examples/imessage-assistant.md +3 -2
- package/dist/builtin-memory/internal/marketplaces.md +3 -2
- package/dist/builtin-memory/internal/memory-loading.md +31 -20
- package/dist/builtin-memory/internal/nodes-and-canvas.md +3 -2
- package/dist/builtin-memory/internal/plugins.md +7 -6
- package/dist/builtin-memory/internal/storage-tiers.md +3 -2
- package/dist/builtin-memory/plan/roadmap.md +3 -2
- package/dist/builtin-memory/spec/guide.md +0 -2
- package/dist/builtin-memory/spec/requirements.md +0 -2
- package/dist/builtin-memory/spec/roadmap.md +3 -2
- package/dist/builtin-memory/testing.md +1 -3
- package/dist/builtin-memory/wedged-child-on-runaway-bash.md +3 -2
- package/dist/builtin-pi-packages/pi-crtr-extensions/README.md +1 -1
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/frontmatter-rules/index.ts +3 -3
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/memory-slash-commands.ts +1 -4
- package/dist/clients/attach/viewer.js +366 -366
- package/dist/commands/memory/delete.js +3 -18
- package/dist/commands/memory/edit.js +23 -30
- package/dist/commands/memory/history.js +1 -1
- package/dist/commands/memory/lint.d.ts +7 -8
- package/dist/commands/memory/lint.js +178 -132
- package/dist/commands/memory/list.d.ts +0 -1
- package/dist/commands/memory/list.js +2 -12
- package/dist/commands/memory/move.d.ts +1 -0
- package/dist/commands/memory/move.js +195 -0
- package/dist/commands/memory/read.js +135 -141
- package/dist/commands/memory/shared.d.ts +18 -17
- package/dist/commands/memory/shared.js +93 -39
- package/dist/commands/memory/write.js +23 -33
- package/dist/commands/memory.js +5 -4
- package/dist/commands/pkg/browse/catalog.js +2 -4
- package/dist/commands/pkg/browse/doc-view.js +17 -11
- package/dist/commands/pkg/browse/model.d.ts +7 -9
- package/dist/commands/sys/migrate.d.ts +1 -0
- package/dist/commands/sys/migrate.js +106 -0
- package/dist/commands/sys/sync-deps.js +5 -10
- package/dist/commands/sys/sync-project-guidance.js +36 -16
- package/dist/commands/sys/sync-skills.js +8 -4
- package/dist/commands/sys.js +3 -2
- package/dist/core/__tests__/inline-memory-refs.test.js +8 -5
- package/dist/core/__tests__/memory-resolver-precedence.test.js +5 -4
- package/dist/core/__tests__/nested-store-discovery.test.js +1 -3
- package/dist/core/__tests__/on-read-crouter-home-fence.test.js +3 -3
- package/dist/core/__tests__/on-read-dedup-resume.test.js +12 -12
- package/dist/core/__tests__/on-read-nested-store.test.js +23 -20
- package/dist/core/canvas/db.d.ts +3 -1
- package/dist/core/canvas/db.js +12 -2
- package/dist/core/memory/history.d.ts +4 -1
- package/dist/core/memory/history.js +1 -0
- package/dist/core/memory/inline-ref-inventory.d.ts +5 -4
- package/dist/core/memory/inline-ref-inventory.js +23 -19
- package/dist/core/memory-resolver.d.ts +4 -4
- package/dist/core/memory-resolver.js +16 -43
- package/dist/core/runtime/bearings.d.ts +4 -3
- package/dist/core/runtime/bearings.js +4 -4
- package/dist/core/runtime/broker-extension-render.d.ts +3 -2
- package/dist/core/runtime/broker-extension-render.js +3 -3
- package/dist/core/runtime/memory.js +2 -3
- package/dist/core/substrate/index.d.ts +7 -4
- package/dist/core/substrate/index.js +6 -4
- package/dist/core/substrate/injected-store.d.ts +24 -12
- package/dist/core/substrate/injected-store.js +80 -33
- package/dist/core/substrate/listings.d.ts +21 -0
- package/dist/core/substrate/listings.js +88 -0
- package/dist/core/substrate/on-read-node.d.ts +5 -5
- package/dist/core/substrate/on-read-node.js +4 -5
- package/dist/core/substrate/on-read.d.ts +25 -4
- package/dist/core/substrate/on-read.js +81 -102
- package/dist/core/substrate/render-node.d.ts +5 -2
- package/dist/core/substrate/render-node.js +5 -3
- package/dist/core/substrate/render.d.ts +9 -8
- package/dist/core/substrate/render.js +104 -96
- package/dist/core/substrate/schema.d.ts +34 -18
- package/dist/core/substrate/schema.js +75 -32
- package/dist/core/substrate/surface-match.d.ts +32 -0
- package/dist/core/substrate/surface-match.js +179 -0
- package/dist/daemon/api/handlers/nodes.js +9 -0
- package/dist/migrations/001-surfaces-frontmatter.d.ts +2 -0
- package/dist/migrations/001-surfaces-frontmatter.js +276 -0
- package/dist/migrations/convergent.d.ts +31 -0
- package/dist/migrations/convergent.js +71 -0
- package/dist/migrations/registry.d.ts +2 -0
- package/dist/migrations/registry.js +19 -0
- package/dist/migrations/types.d.ts +40 -0
- package/dist/migrations/types.js +11 -0
- package/dist/pi-extensions/canvas-context-intro.d.ts +2 -1
- package/dist/pi-extensions/canvas-doc-substrate.d.ts +2 -1
- package/dist/pi-extensions/canvas-doc-substrate.js +57 -34
- package/package.json +1 -1
- package/runtime.lock.json +2 -2
- package/dist/core/substrate/ceiling.d.ts +0 -17
- package/dist/core/substrate/ceiling.js +0 -67
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { CONTEXT_INTRO_CUSTOM_TYPE } from '../shared/generated-context.js';
|
|
2
|
+
import { type InjectedDocs } from '../core/substrate/injected-store.js';
|
|
2
3
|
/** The `customType` stamped on the injected session message. Used both to write
|
|
3
4
|
* the entry and to detect it on resume (the idempotency guard). Defined beside
|
|
4
5
|
* the block builder in `core/runtime/bearings.ts` because the warm-pool claim's
|
|
@@ -68,7 +69,7 @@ interface PiLike {
|
|
|
68
69
|
}
|
|
69
70
|
/** Build the full bearings baseline for a conversation without inherited
|
|
70
71
|
* crouter context. Exported for testing. */
|
|
71
|
-
export declare function buildContextIntro(nodeId: string, seen?:
|
|
72
|
+
export declare function buildContextIntro(nodeId: string, seen?: InjectedDocs): Promise<string>;
|
|
72
73
|
/** Build the compact node-scoped update for a fork whose copied branch already
|
|
73
74
|
* carries a full crouter baseline. Exported for testing. */
|
|
74
75
|
export declare function buildForkContextIntro(nodeId: string): Promise<string>;
|
|
@@ -17,7 +17,8 @@ interface ToolResultEventLike {
|
|
|
17
17
|
toolName: string;
|
|
18
18
|
isError?: boolean;
|
|
19
19
|
/** The tool's resolved input. For `read` it carries the file path under
|
|
20
|
-
* `path` (or the legacy `file_path`)
|
|
20
|
+
* `path` (or the legacy `file_path`); for `bash`, the command string under
|
|
21
|
+
* `command`. Typed loosely; narrowed at use. */
|
|
21
22
|
input?: unknown;
|
|
22
23
|
content: ContentBlockLike[];
|
|
23
24
|
}
|
|
@@ -15,12 +15,14 @@
|
|
|
15
15
|
// a capability. Falls back to appending when the anchor is absent. (The `<memory kind="knowledge">`
|
|
16
16
|
// catalog rides the bearings message instead — see core/substrate/render.ts.)
|
|
17
17
|
//
|
|
18
|
-
// 2. tool_result (gated on `read`) — the
|
|
19
|
-
// `read`, evaluates
|
|
20
|
-
// across the resolved corpus and any project stores
|
|
21
|
-
//
|
|
22
|
-
//
|
|
23
|
-
//
|
|
18
|
+
// 2. tool_result (gated on `read` and `bash`) — the EVENT half. For each
|
|
19
|
+
// non-error `read`, evaluates the read file against every doc's `read`
|
|
20
|
+
// surfaces entries across the resolved corpus and any project stores
|
|
21
|
+
// enclosing the read file; for each non-error `bash`, evaluates the
|
|
22
|
+
// executed command string against every doc's `command` entries. Matches
|
|
23
|
+
// render at their matched rung in `<auto-loaded-context>` before the
|
|
24
|
+
// tool output. A transcript-scoped (realpath → rung) map deduplicates
|
|
25
|
+
// repeated deliveries and resumed broker processes.
|
|
24
26
|
//
|
|
25
27
|
// Both handler bodies are wrapped in try/catch and degrade to INERT on error —
|
|
26
28
|
// a substrate bug must never brick node boot or break a `read`, only quietly
|
|
@@ -34,9 +36,9 @@ import { homedir } from 'node:os';
|
|
|
34
36
|
import { join, resolve } from 'node:path';
|
|
35
37
|
import { brokerExtensionState } from '../core/runtime/broker/daemon-ops.js';
|
|
36
38
|
import { renderPreferencesFromState } from '../core/runtime/broker-extension-render.js';
|
|
37
|
-
import { renderOnReadDocsForSubject } from '../core/substrate/on-read.js';
|
|
39
|
+
import { renderOnCommandDocsForSubject, renderOnReadDocsForSubject } from '../core/substrate/on-read.js';
|
|
38
40
|
import { clearSessionCache } from '../core/substrate/session-cache.js';
|
|
39
|
-
import { loadInjectedDocs, saveInjectedDocs, sharedInjectedDocs } from '../core/substrate/injected-store.js';
|
|
41
|
+
import { loadInjectedDocs, mergeInjectedDocs, saveInjectedDocs, sharedInjectedDocs } from '../core/substrate/injected-store.js';
|
|
40
42
|
import { autoLoadedContextInner, mergeAutoLoadedContext } from './envelope-merge.js';
|
|
41
43
|
// ---------------------------------------------------------------------------
|
|
42
44
|
// Extension
|
|
@@ -86,7 +88,13 @@ export function registerCanvasDocSubstrate(pi) {
|
|
|
86
88
|
pi.on('before_agent_start', async (event) => {
|
|
87
89
|
try {
|
|
88
90
|
const state = await brokerExtensionState(nodeId);
|
|
89
|
-
|
|
91
|
+
// Merge the on-disk set first so this save never clobbers an
|
|
92
|
+
// out-of-process delivery (the daemon's warm-spare bearings push), then
|
|
93
|
+
// seed each rendered preference at its boot rung. Boot renders every
|
|
94
|
+
// agent run and never skips; re-seeding at the same rung is idempotent.
|
|
95
|
+
mergeInjectedDocs(injectedDocs, loadInjectedDocs(nodeId));
|
|
96
|
+
const block = renderPreferencesFromState(state, injectedDocs);
|
|
97
|
+
saveInjectedDocs(nodeId, injectedDocs);
|
|
90
98
|
if (block === '')
|
|
91
99
|
return; // nothing eligible — leave the prompt untouched
|
|
92
100
|
const idx = event.systemPrompt.indexOf(TOOLS_ANCHOR);
|
|
@@ -101,43 +109,58 @@ export function registerCanvasDocSubstrate(pi) {
|
|
|
101
109
|
return; // inert on error — never brick node boot
|
|
102
110
|
}
|
|
103
111
|
});
|
|
104
|
-
// 2.
|
|
112
|
+
// 2. EVENT half — augment a non-error `read` with docs matched by the read
|
|
113
|
+
// file, and a non-error `bash` with docs matched by the command string.
|
|
105
114
|
pi.on('tool_result', async (event, ctx) => {
|
|
106
115
|
try {
|
|
107
|
-
if (event.
|
|
116
|
+
if (event.isError === true)
|
|
108
117
|
return;
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
118
|
+
let injected;
|
|
119
|
+
if (event.toolName === 'read') {
|
|
120
|
+
const input = event.input;
|
|
121
|
+
const rawPath = input?.path ?? input?.file_path;
|
|
122
|
+
if (rawPath === undefined || rawPath === '')
|
|
123
|
+
return;
|
|
124
|
+
// Resolve to an absolute path (renderOnReadDocsForSubject realpaths it).
|
|
125
|
+
// pi's read tool expands a leading `~`, but event.input keeps the raw
|
|
126
|
+
// form, so expand it ourselves before resolving against the session cwd.
|
|
127
|
+
const cwd = typeof ctx?.cwd === 'string' && ctx.cwd !== '' ? ctx.cwd : process.cwd();
|
|
128
|
+
const expanded = rawPath.startsWith('~') ? join(homedir(), rawPath.slice(1)) : rawPath;
|
|
129
|
+
const absFile = resolve(cwd, expanded);
|
|
130
|
+
const state = await brokerExtensionState(nodeId);
|
|
131
|
+
// Merge the on-disk set: an out-of-process delivery (the daemon's
|
|
132
|
+
// warm-spare claim pushes bearings — including workspace-open docs —
|
|
133
|
+
// into the live session and persists what it delivered) must dedup here
|
|
134
|
+
// too. Cheap: one tiny JSON read per tool result.
|
|
135
|
+
mergeInjectedDocs(injectedDocs, loadInjectedDocs(nodeId));
|
|
136
|
+
injected = renderOnReadDocsForSubject(state.subject, absFile, injectedDocs);
|
|
137
|
+
}
|
|
138
|
+
else if (event.toolName === 'bash') {
|
|
139
|
+
const input = event.input;
|
|
140
|
+
const command = input?.command;
|
|
141
|
+
if (typeof command !== 'string' || command.trim() === '')
|
|
142
|
+
return;
|
|
143
|
+
const state = await brokerExtensionState(nodeId);
|
|
144
|
+
mergeInjectedDocs(injectedDocs, loadInjectedDocs(nodeId));
|
|
145
|
+
injected = renderOnCommandDocsForSubject(state.subject, command, injectedDocs);
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
112
148
|
return;
|
|
113
|
-
|
|
114
|
-
// pi's read tool expands a leading `~`, but event.input keeps the raw
|
|
115
|
-
// form, so expand it ourselves before resolving against the session cwd.
|
|
116
|
-
const cwd = typeof ctx?.cwd === 'string' && ctx.cwd !== '' ? ctx.cwd : process.cwd();
|
|
117
|
-
const expanded = rawPath.startsWith('~') ? join(homedir(), rawPath.slice(1)) : rawPath;
|
|
118
|
-
const absFile = resolve(cwd, expanded);
|
|
119
|
-
const state = await brokerExtensionState(nodeId);
|
|
120
|
-
// Merge the on-disk set: an out-of-process delivery (the daemon's
|
|
121
|
-
// warm-spare claim pushes bearings — including workspace-open docs —
|
|
122
|
-
// into the live session and persists what it delivered) must dedup here
|
|
123
|
-
// too. Cheap: one tiny JSON read per `read`.
|
|
124
|
-
for (const real of loadInjectedDocs(nodeId))
|
|
125
|
-
injectedDocs.add(real);
|
|
126
|
-
const injected = renderOnReadDocsForSubject(state.subject, absFile, injectedDocs);
|
|
149
|
+
}
|
|
127
150
|
if (injected === '')
|
|
128
|
-
return; // nothing surfaced — pass the
|
|
129
|
-
// A doc surfaced →
|
|
130
|
-
//
|
|
151
|
+
return; // nothing surfaced — pass the result through unchanged
|
|
152
|
+
// A doc surfaced → the render grew injectedDocs; persist the set so the
|
|
153
|
+
// dedup survives a later dormancy → revive(resume).
|
|
131
154
|
saveInjectedDocs(nodeId, injectedDocs);
|
|
132
|
-
// Fold into any existing auto-loaded-context block from sibling
|
|
133
|
-
// otherwise prepend one quiet block ahead of the
|
|
155
|
+
// Fold into any existing auto-loaded-context block from sibling hooks;
|
|
156
|
+
// otherwise prepend one quiet block ahead of the tool output.
|
|
134
157
|
const inner = autoLoadedContextInner(injected);
|
|
135
158
|
if (inner === null)
|
|
136
159
|
return;
|
|
137
160
|
return { content: mergeAutoLoadedContext([inner], event.content) };
|
|
138
161
|
}
|
|
139
162
|
catch {
|
|
140
|
-
return; // inert on error — a bug must degrade a
|
|
163
|
+
return; // inert on error — a bug must degrade a tool result, never break it
|
|
141
164
|
}
|
|
142
165
|
});
|
|
143
166
|
}
|
package/package.json
CHANGED
package/runtime.lock.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@north-light/crouter",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.210",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@north-light/crouter",
|
|
9
|
-
"version": "0.3.
|
|
9
|
+
"version": "0.3.210",
|
|
10
10
|
"hasInstallScript": true,
|
|
11
11
|
"license": "MIT",
|
|
12
12
|
"dependencies": {
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { type Rung, type SubstrateDoc } from './schema.js';
|
|
2
|
-
/** The reserved basename (no extension) that marks a directory's index doc. */
|
|
3
|
-
export declare const INDEX_NAME = "INDEX";
|
|
4
|
-
/** Does this path-derived name denote a directory INDEX (`taste/INDEX`, or a
|
|
5
|
-
* top-level `INDEX`)? */
|
|
6
|
-
export declare function isIndexName(name: string): boolean;
|
|
7
|
-
/** The directory an INDEX doc represents: `taste/INDEX` → `taste`, `INDEX` → ''. */
|
|
8
|
-
export declare function indexDirOf(name: string): string;
|
|
9
|
-
/** Returns the display path corresponding to a canonical logical identifier. */
|
|
10
|
-
export declare function displayName(name: string): string;
|
|
11
|
-
/** Build the dir → governing-INDEX map. Precedence is first-occurrence-wins, so
|
|
12
|
-
* callers MUST pass docs precedence-ordered (project > user > builtin) — the
|
|
13
|
-
* highest-precedence INDEX governs a dir, mirroring the memory resolver. */
|
|
14
|
-
export declare function buildCeilingIndex(docs: SubstrateDoc[]): Map<string, SubstrateDoc>;
|
|
15
|
-
/** A doc's effective system-prompt rung after applying every ancestor INDEX
|
|
16
|
-
* ceiling. A `none` ancestor hides the whole subtree from the boot catalog. */
|
|
17
|
-
export declare function effectiveSystemPromptRung(doc: SubstrateDoc, ceil: Map<string, SubstrateDoc>): Rung;
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
// ceiling.ts — canonical INDEX identifiers and the boot-catalog subtree ceiling.
|
|
2
|
-
//
|
|
3
|
-
// A directory INDEX has the canonical logical identifier `<directory>/INDEX`
|
|
4
|
-
// (`INDEX` at the root). Its system-prompt rung caps every document in that
|
|
5
|
-
// subtree while the boot catalog renders:
|
|
6
|
-
//
|
|
7
|
-
// effective rung of a descendant = min(own rung, every ancestor INDEX's rung)
|
|
8
|
-
//
|
|
9
|
-
// A `preview` INDEX therefore lets its descendants surface at most at preview;
|
|
10
|
-
// a `none` INDEX hides the subtree. File context does not use this ceiling:
|
|
11
|
-
// every workspace/file match is an explicit `applies-to` route and renders at
|
|
12
|
-
// the matched document's own file-read rung.
|
|
13
|
-
import { rungRank } from './schema.js';
|
|
14
|
-
/** The reserved basename (no extension) that marks a directory's index doc. */
|
|
15
|
-
export const INDEX_NAME = 'INDEX';
|
|
16
|
-
/** Does this path-derived name denote a directory INDEX (`taste/INDEX`, or a
|
|
17
|
-
* top-level `INDEX`)? */
|
|
18
|
-
export function isIndexName(name) {
|
|
19
|
-
return name === INDEX_NAME || name.endsWith('/' + INDEX_NAME);
|
|
20
|
-
}
|
|
21
|
-
/** The directory an INDEX doc represents: `taste/INDEX` → `taste`, `INDEX` → ''. */
|
|
22
|
-
export function indexDirOf(name) {
|
|
23
|
-
return name === INDEX_NAME ? '' : name.slice(0, name.length - INDEX_NAME.length - 1);
|
|
24
|
-
}
|
|
25
|
-
/** Returns the display path corresponding to a canonical logical identifier. */
|
|
26
|
-
export function displayName(name) {
|
|
27
|
-
return isIndexName(name) ? indexDirOf(name) : name;
|
|
28
|
-
}
|
|
29
|
-
/** Build the dir → governing-INDEX map. Precedence is first-occurrence-wins, so
|
|
30
|
-
* callers MUST pass docs precedence-ordered (project > user > builtin) — the
|
|
31
|
-
* highest-precedence INDEX governs a dir, mirroring the memory resolver. */
|
|
32
|
-
export function buildCeilingIndex(docs) {
|
|
33
|
-
const m = new Map();
|
|
34
|
-
for (const d of docs) {
|
|
35
|
-
if (!isIndexName(d.name))
|
|
36
|
-
continue;
|
|
37
|
-
const dir = indexDirOf(d.name);
|
|
38
|
-
if (!m.has(dir))
|
|
39
|
-
m.set(dir, d);
|
|
40
|
-
}
|
|
41
|
-
return m;
|
|
42
|
-
}
|
|
43
|
-
function minRung(a, b) {
|
|
44
|
-
return rungRank(a) <= rungRank(b) ? a : b;
|
|
45
|
-
}
|
|
46
|
-
/** Ancestor directory names of a doc, nearest-last: `a/b/c` → [`a/b`, `a`];
|
|
47
|
-
* `a` → []. An INDEX doc's OWN dir is included (a self-cap is a no-op), so a
|
|
48
|
-
* nested INDEX still inherits its parents' ceilings. */
|
|
49
|
-
function ancestorDirs(name) {
|
|
50
|
-
const parts = name.split('/');
|
|
51
|
-
parts.pop(); // drop the leaf
|
|
52
|
-
const out = [];
|
|
53
|
-
for (let i = parts.length; i > 0; i--)
|
|
54
|
-
out.push(parts.slice(0, i).join('/'));
|
|
55
|
-
return out;
|
|
56
|
-
}
|
|
57
|
-
/** A doc's effective system-prompt rung after applying every ancestor INDEX
|
|
58
|
-
* ceiling. A `none` ancestor hides the whole subtree from the boot catalog. */
|
|
59
|
-
export function effectiveSystemPromptRung(doc, ceil) {
|
|
60
|
-
let rung = doc.systemPromptVisibility;
|
|
61
|
-
for (const dir of ancestorDirs(doc.name)) {
|
|
62
|
-
const idx = ceil.get(dir);
|
|
63
|
-
if (idx)
|
|
64
|
-
rung = minRung(rung, idx.systemPromptVisibility);
|
|
65
|
-
}
|
|
66
|
-
return rung;
|
|
67
|
-
}
|