@north-light/crouter 0.3.222 → 0.3.224
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/builtin-memory/internal/memory-loading.md +4 -4
- package/dist/clients/attach/viewer.js +391 -391
- package/dist/clients/inbox/page-adapter.js +2 -1
- package/dist/clients/inbox/tui/panel.js +23 -4
- package/dist/clients/inbox/tui/render.js +6 -0
- package/dist/clients/inbox/tui/types.d.ts +8 -0
- package/dist/commands/memory/shared.d.ts +2 -2
- package/dist/commands/memory/shared.js +11 -6
- package/dist/commands/pkg/browse/doc-view.js +2 -0
- package/dist/core/__tests__/preview-mirror-cap.test.d.ts +1 -0
- package/dist/core/__tests__/preview-mirror-cap.test.js +37 -0
- package/dist/core/__tests__/profile-project-memory-delivery.test.js +69 -2
- package/dist/core/io.d.ts +9 -0
- package/dist/core/io.js +13 -1
- package/dist/core/substrate/frontmatter-validation.d.ts +2 -5
- package/dist/core/substrate/frontmatter-validation.js +8 -4
- package/dist/core/substrate/gate.d.ts +4 -1
- package/dist/core/substrate/gate.js +5 -0
- package/dist/core/substrate/on-read.js +4 -4
- package/dist/core/substrate/render.js +13 -18
- package/dist/core/substrate/schema.d.ts +12 -7
- package/dist/core/substrate/schema.js +10 -6
- package/dist/core/substrate/surface-match.d.ts +8 -7
- package/dist/core/substrate/surface-match.js +15 -14
- package/package.json +1 -1
- package/runtime.lock.json +2 -2
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type ProfileProjectMemory } from '../../api/dto/profiles.js';
|
|
2
2
|
import type { MemoryDoc, MemoryScope } from '../memory-resolver.js';
|
|
3
|
+
import type { NodeConfigSubject } from './subject-fields.js';
|
|
3
4
|
export declare const KINDS: readonly ["knowledge", "preference"];
|
|
4
5
|
export type DocKind = (typeof KINDS)[number];
|
|
5
6
|
/** Is `v` one of the two valid document kinds? */
|
|
@@ -34,10 +35,10 @@ export type SurfaceEvent = (typeof SURFACE_EVENTS)[number];
|
|
|
34
35
|
export declare const SURFACE_RUNGS: readonly ["name", "preview", "content"];
|
|
35
36
|
export type SurfaceRung = (typeof SURFACE_RUNGS)[number];
|
|
36
37
|
/** One routing entry: when event `on` exposes a subject that fits `match`
|
|
37
|
-
* (and `matchFrontmatter`, `read` only)
|
|
38
|
-
* Constraints within one entry AND together
|
|
39
|
-
* fit; a `match` list is satisfied by any one
|
|
40
|
-
* event OR together. */
|
|
38
|
+
* (and `matchFrontmatter`, `read` only) and its optional node-config `gate`,
|
|
39
|
+
* the doc delivers at rung `at`. Constraints within one entry AND together
|
|
40
|
+
* (each present constraint must fit; a `match` list is satisfied by any one
|
|
41
|
+
* glob); multiple entries per event OR together. */
|
|
41
42
|
export interface SurfaceEntry {
|
|
42
43
|
on: SurfaceEvent;
|
|
43
44
|
/** Globs vs the event's subject namespace. Required on read/memory-read/
|
|
@@ -47,11 +48,15 @@ export interface SurfaceEntry {
|
|
|
47
48
|
/** Predicate over the read file's own YAML frontmatter — `read` event only.
|
|
48
49
|
* Frontmatter key `match-frontmatter`. */
|
|
49
50
|
matchFrontmatter?: GatePredicate;
|
|
51
|
+
/** Optional predicate over the current node config. Frontmatter key `gate`.
|
|
52
|
+
* The document-level gate remains the hard eligibility check. */
|
|
53
|
+
gate?: GatePredicate;
|
|
50
54
|
at: SurfaceRung;
|
|
51
55
|
}
|
|
52
|
-
/** A doc's boot rung
|
|
53
|
-
* it carries
|
|
54
|
-
|
|
56
|
+
/** A doc's boot rung for `subject`: the highest `at` over participating
|
|
57
|
+
* `boot` entries, `none` when it carries none. The boot render's per-doc
|
|
58
|
+
* selection input. */
|
|
59
|
+
export declare function bootRung(doc: Pick<SubstrateSchema, 'surfaces'>, subject: NodeConfigSubject): Rung;
|
|
55
60
|
/** A gate predicate tree, evaluated by predicate.ts (`evalCondition`) against
|
|
56
61
|
* the node-config subject. Typed loosely on purpose — the matcher engine owns
|
|
57
62
|
* validation; structurally it is a field→matcher map with optional
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
// never throw): invalid `surfaces` entries are dropped rather than crashing a
|
|
9
9
|
// render, and `crtr memory lint` owns strict authoring-time enforcement.
|
|
10
10
|
import { PROFILE_PROJECT_MEMORY_VALUES } from '../../api/dto/profiles.js';
|
|
11
|
+
import { surfaceEntryGatePasses } from './gate.js';
|
|
11
12
|
// ---------------------------------------------------------------------------
|
|
12
13
|
// Kinds — the two semantic kinds (design §3): `knowledge` (consult — procedural
|
|
13
14
|
// playbooks + factual references merged) vs `preference` (behave — standing
|
|
@@ -95,12 +96,13 @@ export const SURFACE_EVENTS = ['boot', 'workspace-open', 'read', 'memory-read',
|
|
|
95
96
|
* absence of an entry. (`Rung`'s `none` survives only as the internal
|
|
96
97
|
* ranking floor, e.g. `bootRung` of a doc with no boot entry.) */
|
|
97
98
|
export const SURFACE_RUNGS = ['name', 'preview', 'content'];
|
|
98
|
-
/** A doc's boot rung
|
|
99
|
-
* it carries
|
|
100
|
-
|
|
99
|
+
/** A doc's boot rung for `subject`: the highest `at` over participating
|
|
100
|
+
* `boot` entries, `none` when it carries none. The boot render's per-doc
|
|
101
|
+
* selection input. */
|
|
102
|
+
export function bootRung(doc, subject) {
|
|
101
103
|
let r = 'none';
|
|
102
104
|
for (const e of doc.surfaces) {
|
|
103
|
-
if (e.on !== 'boot')
|
|
105
|
+
if (e.on !== 'boot' || !surfaceEntryGatePasses(e, subject))
|
|
104
106
|
continue;
|
|
105
107
|
if (rungRank(e.at) > rungRank(r))
|
|
106
108
|
r = e.at;
|
|
@@ -194,8 +196,8 @@ function parseGate(v) {
|
|
|
194
196
|
* dropped (bad `on`, bad `at`, a read/memory-read/command entry left with
|
|
195
197
|
* neither `match` nor — read only — `match-frontmatter`). `match-frontmatter`
|
|
196
198
|
* on a non-read event is dropped from the entry, which survives iff it still
|
|
197
|
-
* carries a `match
|
|
198
|
-
* over many docs and must never throw. */
|
|
199
|
+
* carries a `match`; an invalid entry `gate` is dropped. Lint owns strict
|
|
200
|
+
* enforcement; the runtime parser maps over many docs and must never throw. */
|
|
199
201
|
function parseSurfaces(v) {
|
|
200
202
|
if (!Array.isArray(v))
|
|
201
203
|
return [];
|
|
@@ -212,6 +214,7 @@ function parseSurfaces(v) {
|
|
|
212
214
|
continue;
|
|
213
215
|
const match = parseMatchGlobs(rec['match']);
|
|
214
216
|
const matchFrontmatter = on === 'read' ? parseGate(rec['match-frontmatter']) : undefined;
|
|
217
|
+
const gate = parseGate(rec['gate']);
|
|
215
218
|
if ((on === 'read' || on === 'memory-read' || on === 'command') &&
|
|
216
219
|
match === undefined &&
|
|
217
220
|
matchFrontmatter === undefined) {
|
|
@@ -222,6 +225,7 @@ function parseSurfaces(v) {
|
|
|
222
225
|
at: at,
|
|
223
226
|
...(match !== undefined ? { match } : {}),
|
|
224
227
|
...(matchFrontmatter !== undefined ? { matchFrontmatter } : {}),
|
|
228
|
+
...(gate !== undefined ? { gate } : {}),
|
|
225
229
|
});
|
|
226
230
|
}
|
|
227
231
|
return out;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type Rung, type SubstrateDoc, type SurfaceEntry } from './schema.js';
|
|
2
|
+
import type { NodeConfigSubject } from './subject-fields.js';
|
|
2
3
|
/** The project directory owning a doc's store: the path segment stack above
|
|
3
4
|
* the doc's `.crouter` dir. `null` when the doc's path carries no `.crouter`
|
|
4
5
|
* segment (builtin docs). */
|
|
@@ -13,20 +14,20 @@ export declare function underOwningRoot(doc: Pick<SubstrateDoc, 'path'>, absFile
|
|
|
13
14
|
* realpathed. `readFrontmatter` is the read file's own parsed YAML (empty
|
|
14
15
|
* for non-markdown files); an empty record never satisfies
|
|
15
16
|
* `matchFrontmatter`. */
|
|
16
|
-
export declare function matchesReadEntry(entry: SurfaceEntry, doc: Pick<SubstrateDoc, 'path' | 'scope'>, absReadFile: string, readFrontmatter: Record<string, unknown>): boolean;
|
|
17
|
+
export declare function matchesReadEntry(entry: SurfaceEntry, doc: Pick<SubstrateDoc, 'path' | 'scope'>, subject: NodeConfigSubject, absReadFile: string, readFrontmatter: Record<string, unknown>): boolean;
|
|
17
18
|
/** Does a `memory-read` entry on the doc named `carrierName` fit a resolved
|
|
18
19
|
* read of a doc known by `targetNames`? */
|
|
19
|
-
export declare function matchesMemoryReadEntry(entry: SurfaceEntry, carrierName: string, targetNames: string[]): boolean;
|
|
20
|
+
export declare function matchesMemoryReadEntry(entry: SurfaceEntry, carrierName: string, subject: NodeConfigSubject | null, targetNames: string[]): boolean;
|
|
20
21
|
/** Does a `command` entry fit the executed command string? */
|
|
21
|
-
export declare function matchesCommandEntry(entry: SurfaceEntry, command: string): boolean;
|
|
22
|
+
export declare function matchesCommandEntry(entry: SurfaceEntry, subject: NodeConfigSubject, command: string): boolean;
|
|
22
23
|
/** The doc's delivery rung for a read of `absReadFile` (already realpathed). */
|
|
23
|
-
export declare function readDeliveryRung(doc: Pick<SubstrateDoc, 'surfaces' | 'path' | 'scope'>, absReadFile: string, readFrontmatter: Record<string, unknown>): Rung;
|
|
24
|
+
export declare function readDeliveryRung(doc: Pick<SubstrateDoc, 'surfaces' | 'path' | 'scope'>, subject: NodeConfigSubject, absReadFile: string, readFrontmatter: Record<string, unknown>): Rung;
|
|
24
25
|
/** The doc's workspace-open rung. Presence of an entry is the match; callers
|
|
25
26
|
* scope the corpus to project stores mounted by the subject's cwd/profile. */
|
|
26
|
-
export declare function workspaceOpenRung(doc: Pick<SubstrateDoc, 'surfaces'
|
|
27
|
+
export declare function workspaceOpenRung(doc: Pick<SubstrateDoc, 'surfaces'>, subject: NodeConfigSubject): Rung;
|
|
27
28
|
/** The doc's delivery rung for a `crtr memory read` that resolved a doc
|
|
28
29
|
* known by `targetNames` (canonical name, plus the mount-stripped name for
|
|
29
30
|
* plugin-mounted docs). The doc's own `name` anchors `./` globs. */
|
|
30
|
-
export declare function memoryReadDeliveryRung(doc: Pick<SubstrateDoc, 'surfaces' | 'name'>, targetNames: string[]): Rung;
|
|
31
|
+
export declare function memoryReadDeliveryRung(doc: Pick<SubstrateDoc, 'surfaces' | 'name'>, subject: NodeConfigSubject | null, targetNames: string[]): Rung;
|
|
31
32
|
/** The doc's delivery rung for an executed command string. */
|
|
32
|
-
export declare function commandDeliveryRung(doc: Pick<SubstrateDoc, 'surfaces'>, command: string): Rung;
|
|
33
|
+
export declare function commandDeliveryRung(doc: Pick<SubstrateDoc, 'surfaces'>, subject: NodeConfigSubject, command: string): Rung;
|
|
@@ -13,6 +13,7 @@ import { basename, isAbsolute, matchesGlob, relative, sep } from 'node:path';
|
|
|
13
13
|
import { CRTR_DIR_NAME } from '../../types.js';
|
|
14
14
|
import { realpathOrSelf } from '../fs-utils.js';
|
|
15
15
|
import { evalCondition } from '../predicate.js';
|
|
16
|
+
import { surfaceEntryGatePasses } from './gate.js';
|
|
16
17
|
import { rungRank } from './schema.js';
|
|
17
18
|
/** The project directory owning a doc's store: the path segment stack above
|
|
18
19
|
* the doc's `.crouter` dir. `null` when the doc's path carries no `.crouter`
|
|
@@ -62,8 +63,8 @@ function readGlobMatches(glob, doc, absReadFile) {
|
|
|
62
63
|
* realpathed. `readFrontmatter` is the read file's own parsed YAML (empty
|
|
63
64
|
* for non-markdown files); an empty record never satisfies
|
|
64
65
|
* `matchFrontmatter`. */
|
|
65
|
-
export function matchesReadEntry(entry, doc, absReadFile, readFrontmatter) {
|
|
66
|
-
if (entry.on !== 'read')
|
|
66
|
+
export function matchesReadEntry(entry, doc, subject, absReadFile, readFrontmatter) {
|
|
67
|
+
if (entry.on !== 'read' || !surfaceEntryGatePasses(entry, subject))
|
|
67
68
|
return false;
|
|
68
69
|
if (entry.match !== undefined && !entry.match.some((g) => readGlobMatches(g, doc, absReadFile))) {
|
|
69
70
|
return false;
|
|
@@ -97,8 +98,8 @@ function memoryReadGlobMatches(glob, carrierName, targetNames) {
|
|
|
97
98
|
}
|
|
98
99
|
/** Does a `memory-read` entry on the doc named `carrierName` fit a resolved
|
|
99
100
|
* read of a doc known by `targetNames`? */
|
|
100
|
-
export function matchesMemoryReadEntry(entry, carrierName, targetNames) {
|
|
101
|
-
if (entry.on !== 'memory-read' || entry.match === undefined)
|
|
101
|
+
export function matchesMemoryReadEntry(entry, carrierName, subject, targetNames) {
|
|
102
|
+
if (entry.on !== 'memory-read' || entry.match === undefined || !surfaceEntryGatePasses(entry, subject))
|
|
102
103
|
return false;
|
|
103
104
|
return entry.match.some((g) => memoryReadGlobMatches(g, carrierName, targetNames));
|
|
104
105
|
}
|
|
@@ -119,8 +120,8 @@ function commandGlobMatches(glob, command) {
|
|
|
119
120
|
}
|
|
120
121
|
}
|
|
121
122
|
/** Does a `command` entry fit the executed command string? */
|
|
122
|
-
export function matchesCommandEntry(entry, command) {
|
|
123
|
-
if (entry.on !== 'command' || entry.match === undefined)
|
|
123
|
+
export function matchesCommandEntry(entry, subject, command) {
|
|
124
|
+
if (entry.on !== 'command' || entry.match === undefined || !surfaceEntryGatePasses(entry, subject))
|
|
124
125
|
return false;
|
|
125
126
|
return entry.match.some((g) => commandGlobMatches(g, command));
|
|
126
127
|
}
|
|
@@ -131,10 +132,10 @@ export function matchesCommandEntry(entry, command) {
|
|
|
131
132
|
// floor, never an authored rung).
|
|
132
133
|
// ---------------------------------------------------------------------------
|
|
133
134
|
/** The doc's delivery rung for a read of `absReadFile` (already realpathed). */
|
|
134
|
-
export function readDeliveryRung(doc, absReadFile, readFrontmatter) {
|
|
135
|
+
export function readDeliveryRung(doc, subject, absReadFile, readFrontmatter) {
|
|
135
136
|
let r = 'none';
|
|
136
137
|
for (const e of doc.surfaces) {
|
|
137
|
-
if (!matchesReadEntry(e, doc, absReadFile, readFrontmatter))
|
|
138
|
+
if (!matchesReadEntry(e, doc, subject, absReadFile, readFrontmatter))
|
|
138
139
|
continue;
|
|
139
140
|
if (rungRank(e.at) > rungRank(r))
|
|
140
141
|
r = e.at;
|
|
@@ -143,10 +144,10 @@ export function readDeliveryRung(doc, absReadFile, readFrontmatter) {
|
|
|
143
144
|
}
|
|
144
145
|
/** The doc's workspace-open rung. Presence of an entry is the match; callers
|
|
145
146
|
* scope the corpus to project stores mounted by the subject's cwd/profile. */
|
|
146
|
-
export function workspaceOpenRung(doc) {
|
|
147
|
+
export function workspaceOpenRung(doc, subject) {
|
|
147
148
|
let r = 'none';
|
|
148
149
|
for (const e of doc.surfaces) {
|
|
149
|
-
if (e.on !== 'workspace-open')
|
|
150
|
+
if (e.on !== 'workspace-open' || !surfaceEntryGatePasses(e, subject))
|
|
150
151
|
continue;
|
|
151
152
|
if (rungRank(e.at) > rungRank(r))
|
|
152
153
|
r = e.at;
|
|
@@ -156,10 +157,10 @@ export function workspaceOpenRung(doc) {
|
|
|
156
157
|
/** The doc's delivery rung for a `crtr memory read` that resolved a doc
|
|
157
158
|
* known by `targetNames` (canonical name, plus the mount-stripped name for
|
|
158
159
|
* plugin-mounted docs). The doc's own `name` anchors `./` globs. */
|
|
159
|
-
export function memoryReadDeliveryRung(doc, targetNames) {
|
|
160
|
+
export function memoryReadDeliveryRung(doc, subject, targetNames) {
|
|
160
161
|
let r = 'none';
|
|
161
162
|
for (const e of doc.surfaces) {
|
|
162
|
-
if (!matchesMemoryReadEntry(e, doc.name, targetNames))
|
|
163
|
+
if (!matchesMemoryReadEntry(e, doc.name, subject, targetNames))
|
|
163
164
|
continue;
|
|
164
165
|
if (rungRank(e.at) > rungRank(r))
|
|
165
166
|
r = e.at;
|
|
@@ -167,10 +168,10 @@ export function memoryReadDeliveryRung(doc, targetNames) {
|
|
|
167
168
|
return r;
|
|
168
169
|
}
|
|
169
170
|
/** The doc's delivery rung for an executed command string. */
|
|
170
|
-
export function commandDeliveryRung(doc, command) {
|
|
171
|
+
export function commandDeliveryRung(doc, subject, command) {
|
|
171
172
|
let r = 'none';
|
|
172
173
|
for (const e of doc.surfaces) {
|
|
173
|
-
if (!matchesCommandEntry(e, command))
|
|
174
|
+
if (!matchesCommandEntry(e, subject, command))
|
|
174
175
|
continue;
|
|
175
176
|
if (rungRank(e.at) > rungRank(r))
|
|
176
177
|
r = e.at;
|
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.224",
|
|
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.224",
|
|
10
10
|
"hasInstallScript": true,
|
|
11
11
|
"license": "MIT",
|
|
12
12
|
"dependencies": {
|