@saasontools/strauss-kb 0.1.18 → 0.1.20
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/ARCHITECTURE.md +5 -5
- package/README.md +11 -4
- package/dist/{chunk-ROGVYSMV.js → chunk-EXZQZJU2.js} +2 -2
- package/dist/{chunk-GSOTMWZZ.js → chunk-QQLPJO4R.js} +3196 -1273
- package/dist/chunk-QQLPJO4R.js.map +1 -0
- package/dist/{chunk-IOIUS26S.js → chunk-XDH6J6CH.js} +2 -2
- package/dist/cli-main.cjs +2841 -954
- package/dist/cli-main.cjs.map +1 -1
- package/dist/cli-main.js +2 -2
- package/dist/index.cjs +2272 -417
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +510 -101
- package/dist/index.d.ts +510 -101
- package/dist/index.js +40 -83
- package/dist/index.js.map +1 -1
- package/dist/mcp-main.cjs +2837 -950
- package/dist/mcp-main.cjs.map +1 -1
- package/dist/mcp-main.js +2 -2
- package/package.json +1 -1
- package/dist/chunk-GSOTMWZZ.js.map +0 -1
- /package/dist/{chunk-ROGVYSMV.js.map → chunk-EXZQZJU2.js.map} +0 -0
- /package/dist/{chunk-IOIUS26S.js.map → chunk-XDH6J6CH.js.map} +0 -0
package/dist/index.d.cts
CHANGED
|
@@ -62,9 +62,25 @@ declare const kbVerifiedEventSchema: z.ZodObject<{
|
|
|
62
62
|
* independent of each other, so every anchor written before they existed stays
|
|
63
63
|
* valid.
|
|
64
64
|
*/
|
|
65
|
+
/**
|
|
66
|
+
* An explicit line range, 1-based and inclusive. Author-owned: a resolver
|
|
67
|
+
* hashes it but never moves it.
|
|
68
|
+
*/
|
|
69
|
+
declare const kbAnchorSpanSchema: z.ZodObject<{
|
|
70
|
+
start: z.ZodNumber;
|
|
71
|
+
end: z.ZodNumber;
|
|
72
|
+
}, z.core.$strict>;
|
|
65
73
|
declare const kbAnchorSchema: z.ZodObject<{
|
|
66
74
|
file: z.ZodString;
|
|
67
75
|
symbol: z.ZodOptional<z.ZodString>;
|
|
76
|
+
span: z.ZodOptional<z.ZodObject<{
|
|
77
|
+
start: z.ZodNumber;
|
|
78
|
+
end: z.ZodNumber;
|
|
79
|
+
}, z.core.$strict>>;
|
|
80
|
+
side: z.ZodOptional<z.ZodEnum<{
|
|
81
|
+
old: "old";
|
|
82
|
+
new: "new";
|
|
83
|
+
}>>;
|
|
68
84
|
repo: z.ZodOptional<z.ZodString>;
|
|
69
85
|
ref: z.ZodOptional<z.ZodString>;
|
|
70
86
|
hash: z.ZodOptional<z.ZodString>;
|
|
@@ -75,6 +91,40 @@ declare const kbAnchorSchema: z.ZodObject<{
|
|
|
75
91
|
resolved_at: z.ZodOptional<z.ZodString>;
|
|
76
92
|
lines: z.ZodOptional<z.ZodNumber>;
|
|
77
93
|
resolver: z.ZodOptional<z.ZodEnum<{
|
|
94
|
+
span: "span";
|
|
95
|
+
"tree-sitter": "tree-sitter";
|
|
96
|
+
regex: "regex";
|
|
97
|
+
}>>;
|
|
98
|
+
}, z.core.$strict>;
|
|
99
|
+
/**
|
|
100
|
+
* The anchor rules a resolver cannot settle for itself.
|
|
101
|
+
*
|
|
102
|
+
* Write-side only, like `kbVerifiedEventSchema`: the frontmatter keeps parsing
|
|
103
|
+
* with `kbAnchorSchema`, so a hand-edited defect is a `kb_validate` finding
|
|
104
|
+
* rather than a record that silently vanishes from `list()`.
|
|
105
|
+
*/
|
|
106
|
+
declare const kbAnchorWriteSchema: z.ZodObject<{
|
|
107
|
+
file: z.ZodString;
|
|
108
|
+
symbol: z.ZodOptional<z.ZodString>;
|
|
109
|
+
span: z.ZodOptional<z.ZodObject<{
|
|
110
|
+
start: z.ZodNumber;
|
|
111
|
+
end: z.ZodNumber;
|
|
112
|
+
}, z.core.$strict>>;
|
|
113
|
+
side: z.ZodOptional<z.ZodEnum<{
|
|
114
|
+
old: "old";
|
|
115
|
+
new: "new";
|
|
116
|
+
}>>;
|
|
117
|
+
repo: z.ZodOptional<z.ZodString>;
|
|
118
|
+
ref: z.ZodOptional<z.ZodString>;
|
|
119
|
+
hash: z.ZodOptional<z.ZodString>;
|
|
120
|
+
hash_kind: z.ZodOptional<z.ZodEnum<{
|
|
121
|
+
raw: "raw";
|
|
122
|
+
ast: "ast";
|
|
123
|
+
}>>;
|
|
124
|
+
resolved_at: z.ZodOptional<z.ZodString>;
|
|
125
|
+
lines: z.ZodOptional<z.ZodNumber>;
|
|
126
|
+
resolver: z.ZodOptional<z.ZodEnum<{
|
|
127
|
+
span: "span";
|
|
78
128
|
"tree-sitter": "tree-sitter";
|
|
79
129
|
regex: "regex";
|
|
80
130
|
}>>;
|
|
@@ -143,6 +193,14 @@ declare const kbRecordFrontmatterSchema: z.ZodObject<{
|
|
|
143
193
|
strauss_anchors: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
144
194
|
file: z.ZodString;
|
|
145
195
|
symbol: z.ZodOptional<z.ZodString>;
|
|
196
|
+
span: z.ZodOptional<z.ZodObject<{
|
|
197
|
+
start: z.ZodNumber;
|
|
198
|
+
end: z.ZodNumber;
|
|
199
|
+
}, z.core.$strict>>;
|
|
200
|
+
side: z.ZodOptional<z.ZodEnum<{
|
|
201
|
+
old: "old";
|
|
202
|
+
new: "new";
|
|
203
|
+
}>>;
|
|
146
204
|
repo: z.ZodOptional<z.ZodString>;
|
|
147
205
|
ref: z.ZodOptional<z.ZodString>;
|
|
148
206
|
hash: z.ZodOptional<z.ZodString>;
|
|
@@ -153,6 +211,7 @@ declare const kbRecordFrontmatterSchema: z.ZodObject<{
|
|
|
153
211
|
resolved_at: z.ZodOptional<z.ZodString>;
|
|
154
212
|
lines: z.ZodOptional<z.ZodNumber>;
|
|
155
213
|
resolver: z.ZodOptional<z.ZodEnum<{
|
|
214
|
+
span: "span";
|
|
156
215
|
"tree-sitter": "tree-sitter";
|
|
157
216
|
regex: "regex";
|
|
158
217
|
}>>;
|
|
@@ -193,6 +252,7 @@ declare const kbRecordFrontmatterSchema: z.ZodObject<{
|
|
|
193
252
|
type KbSource = z.infer<typeof kbSourceSchema>;
|
|
194
253
|
type KbActorStamp = z.infer<typeof kbActorStampSchema>;
|
|
195
254
|
type KbVerifiedEvent = z.infer<typeof kbVerifiedEventSchema>;
|
|
255
|
+
type KbAnchorSpan = z.infer<typeof kbAnchorSpanSchema>;
|
|
196
256
|
type KbAnchor = z.infer<typeof kbAnchorSchema>;
|
|
197
257
|
type KbLink = z.infer<typeof kbLinkSchema>;
|
|
198
258
|
type KbRecordFrontmatter = z.infer<typeof kbRecordFrontmatterSchema>;
|
|
@@ -203,9 +263,6 @@ type KbRecord = {
|
|
|
203
263
|
body: string;
|
|
204
264
|
};
|
|
205
265
|
|
|
206
|
-
/** Where bare mirrors live. Overridable so a test never writes to `$HOME`. */
|
|
207
|
-
declare function repoCacheDir(override?: string): string;
|
|
208
|
-
|
|
209
266
|
/**
|
|
210
267
|
* The vocabulary anchor resolution is reported in.
|
|
211
268
|
*
|
|
@@ -219,10 +276,10 @@ type ResolvedSymbol = {
|
|
|
219
276
|
endLine: number;
|
|
220
277
|
};
|
|
221
278
|
/** Which resolver produced a span. Stamped on the anchor. */
|
|
222
|
-
type AnchorResolverName = "tree-sitter" | "regex";
|
|
279
|
+
type AnchorResolverName = "tree-sitter" | "regex" | "span";
|
|
223
280
|
/**
|
|
224
281
|
* A resolver's verdict. `abstain` ("not my language") and `symbol-not-found`
|
|
225
|
-
* ("nothing I recognize declares this")
|
|
282
|
+
* ("nothing I recognize declares this") pass the symbol down the chain;
|
|
226
283
|
* `symbol-ambiguous` and `resolver-unavailable` end it, because neither may be
|
|
227
284
|
* answered by a looser resolver guessing.
|
|
228
285
|
*/
|
|
@@ -235,12 +292,17 @@ type ResolverAttempt = {
|
|
|
235
292
|
} | {
|
|
236
293
|
kind: "abstain";
|
|
237
294
|
};
|
|
295
|
+
/** What the chain already knows when it calls a resolver. */
|
|
296
|
+
type ResolverAttemptOptions = {
|
|
297
|
+
/** A resolver that parsed this file already reported `symbol-not-found`. */
|
|
298
|
+
afterParsedMiss?: boolean;
|
|
299
|
+
};
|
|
238
300
|
interface AnchorResolver {
|
|
239
301
|
name: string;
|
|
240
302
|
/** Loads whatever these files need, before any `resolve` call. Optional. */
|
|
241
303
|
prepare?(files: readonly string[]): Promise<void>;
|
|
242
304
|
/** The richer verdict the chain uses; defaults to `resolve`. */
|
|
243
|
-
attempt?(source: string, symbol: string, file?: string): ResolverAttempt;
|
|
305
|
+
attempt?(source: string, symbol: string, file?: string, options?: ResolverAttemptOptions): ResolverAttempt;
|
|
244
306
|
resolve(source: string, symbol: string, file?: string): ResolvedSymbol | null;
|
|
245
307
|
/**
|
|
246
308
|
* The span's normalised token stream — comments dropped, runs of whitespace
|
|
@@ -267,6 +329,12 @@ type AnchorResolution = {
|
|
|
267
329
|
type AnchorUnresolvedReason = "file-missing" | "symbol-not-found"
|
|
268
330
|
/** More than one definition carries the name, and guessing is not allowed. */
|
|
269
331
|
| "symbol-ambiguous"
|
|
332
|
+
/** The anchor's `span` runs past the end of the file it names. */
|
|
333
|
+
| "span-out-of-range"
|
|
334
|
+
/** `side: "old"` with no usable `ref`, or no such path at the rev. */
|
|
335
|
+
| "ref-unreadable"
|
|
336
|
+
/** The `ref` is not in this clone — a shallow checkout, not deleted code. */
|
|
337
|
+
| "ref-unavailable"
|
|
270
338
|
/** The extension has a grammar, but it would not load. Never a throw. */
|
|
271
339
|
| "resolver-unavailable" | "outside-repo" | "file-too-large" | "file-unreadable"
|
|
272
340
|
/** The remote could not be fetched, or `--offline` found nothing cached. */
|
|
@@ -313,6 +381,8 @@ type KbDriftMovedTo = {
|
|
|
313
381
|
type KbAnchorDriftEntry = {
|
|
314
382
|
file: string;
|
|
315
383
|
symbol?: string;
|
|
384
|
+
/** Set only for `side: "old"`: read at `ref`, never from the working tree. */
|
|
385
|
+
side?: "old";
|
|
316
386
|
state: "match" | "drifted" | "unresolved";
|
|
317
387
|
storedHash: string;
|
|
318
388
|
currentHash?: string;
|
|
@@ -345,6 +415,34 @@ type AnchorRead = {
|
|
|
345
415
|
};
|
|
346
416
|
type AnchorFileReader = (file: string) => Promise<AnchorRead>;
|
|
347
417
|
|
|
418
|
+
/**
|
|
419
|
+
* The committed file an old-side anchor names, at its own `ref` and nowhere
|
|
420
|
+
* else. No history fallback: `side: "old"` asserts one exact tree, so guessing
|
|
421
|
+
* a nearby commit would answer a question the anchor did not ask.
|
|
422
|
+
*
|
|
423
|
+
* A rev this clone does not carry is `ref-unavailable` — unchecked, not
|
|
424
|
+
* `gone`: a shallow checkout is no evidence the code went away.
|
|
425
|
+
*/
|
|
426
|
+
declare function readFileAtRef(repoRoot: string, anchor: {
|
|
427
|
+
file: string;
|
|
428
|
+
ref?: string;
|
|
429
|
+
}): Promise<AnchorRead>;
|
|
430
|
+
/** Where a recovered file came from, so a packet can say how far back it looked. */
|
|
431
|
+
type OldSourceOrigin =
|
|
432
|
+
/** `git cat-file blob <anchor.ref>:<file>` — the rev the record named. */
|
|
433
|
+
{
|
|
434
|
+
kind: "ref";
|
|
435
|
+
ref: string;
|
|
436
|
+
}
|
|
437
|
+
/** The last commit touching the path before `resolved_at`. */
|
|
438
|
+
| {
|
|
439
|
+
kind: "history";
|
|
440
|
+
ref: string;
|
|
441
|
+
};
|
|
442
|
+
|
|
443
|
+
/** Where bare mirrors live. Overridable so a test never writes to `$HOME`. */
|
|
444
|
+
declare function repoCacheDir(override?: string): string;
|
|
445
|
+
|
|
348
446
|
/**
|
|
349
447
|
* A foreign anchor's file at one rev. `ref` absent means the remote's default
|
|
350
448
|
* branch — the "current" side of a ref-pinned comparison.
|
|
@@ -388,6 +486,8 @@ type AnchorDriftOptions = {
|
|
|
388
486
|
concurrency?: number;
|
|
389
487
|
/** Test seam: replaces the disk reader. */
|
|
390
488
|
reader?: AnchorFileReader;
|
|
489
|
+
/** Test seam: replaces the committed-side git read. */
|
|
490
|
+
readAtRef?: typeof readFileAtRef;
|
|
391
491
|
/** Remote resolution of foreign anchors; `offline` keeps a run off the wire. */
|
|
392
492
|
remote?: RemoteOptions;
|
|
393
493
|
/** Test seam: replaces the remote blob reader. */
|
|
@@ -518,9 +618,9 @@ declare function resolveAnchor(source: string, anchor: KbAnchor, resolver?: Anch
|
|
|
518
618
|
* when the anchor names no symbol.
|
|
519
619
|
*
|
|
520
620
|
* `symbol-not-found` falls through (a tags query defines functions and types,
|
|
521
|
-
* not constants or fields)
|
|
522
|
-
*
|
|
523
|
-
*
|
|
621
|
+
* not constants or fields), but a resolver that parsed the file and missed
|
|
622
|
+
* narrows what follows to definition-shaped candidates: never a call site or a
|
|
623
|
+
* bare mention. `symbol-ambiguous` and `resolver-unavailable` end the chain.
|
|
524
624
|
*/
|
|
525
625
|
declare function resolveAnchorSpan(source: string, anchor: KbAnchor, resolvers?: readonly AnchorResolver[]): AnchorResolution;
|
|
526
626
|
/** Loads every chained resolver's per-language assets, once. */
|
|
@@ -743,6 +843,22 @@ type KbPackResult = {
|
|
|
743
843
|
*/
|
|
744
844
|
declare function pack(bundle: KbRecord[], rootId: string, options?: KbPackOptions): KbPackResult;
|
|
745
845
|
|
|
846
|
+
/**
|
|
847
|
+
* Selection by frontmatter `tags`. Matching is exact and no vocabulary is
|
|
848
|
+
* enforced — a tag is whatever a writer put there.
|
|
849
|
+
*/
|
|
850
|
+
type KbTagFilter = {
|
|
851
|
+
/** AND: a record matches only when it carries every one of these. */
|
|
852
|
+
tags?: string[];
|
|
853
|
+
/** A record carrying any one of these is dropped, even if `tags` matched. */
|
|
854
|
+
excludeTags?: string[];
|
|
855
|
+
};
|
|
856
|
+
/**
|
|
857
|
+
* Whether one record survives the filter. An empty filter keeps everything,
|
|
858
|
+
* so every caller can pass one unconditionally.
|
|
859
|
+
*/
|
|
860
|
+
declare function matchesTags(record: KbRecord, filter: KbTagFilter): boolean;
|
|
861
|
+
|
|
746
862
|
/** One record as the catalog names it — no body, no description, one line. */
|
|
747
863
|
type KbCatalogEntry = {
|
|
748
864
|
conceptId: string;
|
|
@@ -807,7 +923,7 @@ type KbCatalogResult = {
|
|
|
807
923
|
declare function catalog(bundle: KbRecord[], options?: {
|
|
808
924
|
type?: string;
|
|
809
925
|
now?: Date;
|
|
810
|
-
}): KbCatalogResult;
|
|
926
|
+
} & KbTagFilter): KbCatalogResult;
|
|
811
927
|
/**
|
|
812
928
|
* One entry, as one line.
|
|
813
929
|
*
|
|
@@ -952,6 +1068,8 @@ type KbLogReadResult = {
|
|
|
952
1068
|
line: number;
|
|
953
1069
|
text: string;
|
|
954
1070
|
}[];
|
|
1071
|
+
/** Whether the file still carried merge conflict markers. */
|
|
1072
|
+
conflicted: boolean;
|
|
955
1073
|
};
|
|
956
1074
|
declare function parseLog(raw: string): KbLogReadResult;
|
|
957
1075
|
|
|
@@ -1038,6 +1156,13 @@ type KbWriteInput = {
|
|
|
1038
1156
|
/** Replace an existing record rather than failing on the collision. */
|
|
1039
1157
|
overwrite?: boolean;
|
|
1040
1158
|
};
|
|
1159
|
+
/** What a record had to still be for `deleteRecord` to remove it. */
|
|
1160
|
+
type KbDeleteExpectation = {
|
|
1161
|
+
tag: string;
|
|
1162
|
+
statuses: readonly KbRecordStatus[];
|
|
1163
|
+
};
|
|
1164
|
+
/** Whether the delete landed, or the record left that scope first. */
|
|
1165
|
+
type KbDeleteOutcome = "deleted" | "changed-since-listing";
|
|
1041
1166
|
type KbWriteResult = KbRecord & {
|
|
1042
1167
|
/** Whether this write also marked prior records superseded. */
|
|
1043
1168
|
action: "created" | "superseded-prior";
|
|
@@ -1071,13 +1196,18 @@ declare class KbStore {
|
|
|
1071
1196
|
/** One record by concept id, or null when it does not exist. */
|
|
1072
1197
|
read(bundlePath: string, conceptId: string): Promise<KbRecord | null>;
|
|
1073
1198
|
/**
|
|
1074
|
-
* Every record in the bundle, optionally narrowed to one type
|
|
1199
|
+
* Every record in the bundle, optionally narrowed to one type and to the
|
|
1200
|
+
* records carrying every tag in `filter.tags`. Selection only — `excludeTags`
|
|
1201
|
+
* is not taken here, because `query`, `catalog` and `load` read through this
|
|
1202
|
+
* and must adjudicate over the whole base.
|
|
1075
1203
|
*
|
|
1076
1204
|
* A file that fails to parse is skipped and logged rather than thrown: one
|
|
1077
1205
|
* malformed record — hand-edited, or written by a producer we don't know —
|
|
1078
1206
|
* must not make the whole bundle unreadable.
|
|
1079
1207
|
*/
|
|
1080
|
-
list(bundlePath: string, type?: string
|
|
1208
|
+
list(bundlePath: string, type?: string, filter?: {
|
|
1209
|
+
tags?: string[];
|
|
1210
|
+
}): Promise<KbRecord[]>;
|
|
1081
1211
|
/**
|
|
1082
1212
|
* Moves a record's status, preserving everything else.
|
|
1083
1213
|
*
|
|
@@ -1095,6 +1225,9 @@ declare class KbStore {
|
|
|
1095
1225
|
* Wholesale rather than merged: the caller just resolved the anchors it is
|
|
1096
1226
|
* writing, so it holds the complete current set, and a merge would keep
|
|
1097
1227
|
* stale entries the resolution pass deliberately dropped.
|
|
1228
|
+
*
|
|
1229
|
+
* Through the write schema: this is a write, and a defect a hand-edit put in
|
|
1230
|
+
* the frontmatter must not be published back out under an actor stamp.
|
|
1098
1231
|
*/
|
|
1099
1232
|
updateAnchors(bundlePath: string, conceptId: string, anchors: KbAnchor[], actor?: string): Promise<KbRecord>;
|
|
1100
1233
|
/**
|
|
@@ -1119,6 +1252,15 @@ declare class KbStore {
|
|
|
1119
1252
|
supersede(bundlePath: string, conceptId: string, replacementId: string, actor?: string): Promise<KbRecord>;
|
|
1120
1253
|
/** Resolves an open question, stamping who answered and when. */
|
|
1121
1254
|
answer(bundlePath: string, conceptId: string, answer: string, actor?: string, at?: string): Promise<KbRecord>;
|
|
1255
|
+
/**
|
|
1256
|
+
* Removes one record, logged as `sweep`. The only path in this store that
|
|
1257
|
+
* deletes — see the specification for the scope that makes it safe.
|
|
1258
|
+
*
|
|
1259
|
+
* `expected` is re-read and re-checked immediately before the unlink, the
|
|
1260
|
+
* compare-and-swap `mutate` makes: a record retagged or moved out of a
|
|
1261
|
+
* terminal status since the caller listed it is reported, not removed.
|
|
1262
|
+
*/
|
|
1263
|
+
deleteRecord(bundlePath: string, conceptId: string, expected: KbDeleteExpectation, actor?: string): Promise<KbDeleteOutcome>;
|
|
1122
1264
|
/**
|
|
1123
1265
|
* Records matching a text query, each carrying its standing.
|
|
1124
1266
|
*
|
|
@@ -1135,7 +1277,7 @@ declare class KbStore {
|
|
|
1135
1277
|
type?: string;
|
|
1136
1278
|
includeNonCurrent?: boolean;
|
|
1137
1279
|
repoRoot?: string;
|
|
1138
|
-
}): Promise<KbAdjudicated[]>;
|
|
1280
|
+
} & KbTagFilter): Promise<KbAdjudicated[]>;
|
|
1139
1281
|
private rank;
|
|
1140
1282
|
/**
|
|
1141
1283
|
* Anchor drift over the records about to be handed back. Like the search
|
|
@@ -1197,6 +1339,8 @@ declare class KbStore {
|
|
|
1197
1339
|
type?: string;
|
|
1198
1340
|
all?: boolean;
|
|
1199
1341
|
repoRoot?: string;
|
|
1342
|
+
/** Records carrying any of these are left out. See `kb-tags.ts`. */
|
|
1343
|
+
excludeTags?: string[];
|
|
1200
1344
|
}): Promise<KbLoadResult>;
|
|
1201
1345
|
/**
|
|
1202
1346
|
* `load`'s digest without `load`'s bodies — the same records, adjudicated
|
|
@@ -1216,7 +1360,7 @@ declare class KbStore {
|
|
|
1216
1360
|
catalog(bundlePath: string, options?: {
|
|
1217
1361
|
type?: string;
|
|
1218
1362
|
now?: Date;
|
|
1219
|
-
}): Promise<KbCatalogResult>;
|
|
1363
|
+
} & KbTagFilter): Promise<KbCatalogResult>;
|
|
1220
1364
|
/** A bounded neighbourhood around one record. See `pack.ts`. */
|
|
1221
1365
|
pack(bundlePath: string, rootId: string, options?: KbPackOptions): Promise<KbPackResult>;
|
|
1222
1366
|
/** What breaks if this record changes. See `kb-links/impact.ts`. */
|
|
@@ -1231,14 +1375,29 @@ declare class KbStore {
|
|
|
1231
1375
|
* and the next reader through here settles it.
|
|
1232
1376
|
*/
|
|
1233
1377
|
readIndex(bundlePath: string): Promise<string>;
|
|
1378
|
+
/**
|
|
1379
|
+
* Drops the derived search index, so the next search rebuilds it.
|
|
1380
|
+
*
|
|
1381
|
+
* `searchBase` re-indexes when a record is newer than the index, which no
|
|
1382
|
+
* deletion makes true — a swept record would stay findable until some other
|
|
1383
|
+
* record was written.
|
|
1384
|
+
*/
|
|
1385
|
+
dropSearchIndex(bundlePath: string): Promise<void>;
|
|
1234
1386
|
/**
|
|
1235
1387
|
* The log, with unparseable lines reported rather than repaired.
|
|
1236
1388
|
*
|
|
1237
1389
|
* The log is the bundle's only artifact that cannot be reconstructed — the
|
|
1238
1390
|
* records rebuild the index, and the code outlives both, but nothing else
|
|
1239
1391
|
* knows which agent touched what. So a bad line is surfaced and left alone.
|
|
1392
|
+
* Conflict markers are read past rather than reported per line.
|
|
1240
1393
|
*/
|
|
1241
1394
|
readLog(bundlePath: string): Promise<ReturnType<typeof parseLog>>;
|
|
1395
|
+
/**
|
|
1396
|
+
* Appends one log entry for a move the store cannot see from one base.
|
|
1397
|
+
* Promotion writes into a target base and has to be legible from the source
|
|
1398
|
+
* base too, where nothing was written.
|
|
1399
|
+
*/
|
|
1400
|
+
note(bundlePath: string, entry: Omit<KbLogEntry, "at">): Promise<void>;
|
|
1242
1401
|
/**
|
|
1243
1402
|
* `markSuperseded`, tolerant of the two ways it legitimately doesn't land:
|
|
1244
1403
|
* a missing target (a broken link, legal per compose.ts) or a CAS conflict
|
|
@@ -1273,7 +1432,8 @@ declare class KbStore {
|
|
|
1273
1432
|
/**
|
|
1274
1433
|
* Declares union merge for the log, so two worktrees writing the same
|
|
1275
1434
|
* bundle interleave their `log.jsonl` lines on merge rather than one
|
|
1276
|
-
* side's appends silently losing to git's ordinary line-level merge
|
|
1435
|
+
* side's appends silently losing to git's ordinary line-level merge — and
|
|
1436
|
+
* marks every store-owned file generated, so GitHub collapses it in a diff.
|
|
1277
1437
|
*
|
|
1278
1438
|
* Called from `record` — every path that appends a log line, not just
|
|
1279
1439
|
* `write` — so a bundle only ever mutated through `setStatus`/`verify`/
|
|
@@ -1286,10 +1446,9 @@ declare class KbStore {
|
|
|
1286
1446
|
* race and created the file between the `readFile` below and this call,
|
|
1287
1447
|
* `wx` fails instead of truncating what that writer just wrote, and the
|
|
1288
1448
|
* failure is swallowed by the catch below same as any other best-effort
|
|
1289
|
-
* miss. A file that exists
|
|
1290
|
-
*
|
|
1291
|
-
*
|
|
1292
|
-
* entirely (see `hasMergeDeclaration`).
|
|
1449
|
+
* miss. A file that exists gets only the lines it lacks appended, never a
|
|
1450
|
+
* wholesale rewrite; an attribute it already sets — this one's value or a
|
|
1451
|
+
* user's own — is left alone (see `missingGitattributesLines`).
|
|
1293
1452
|
*
|
|
1294
1453
|
* `readFile` failing is `existing === null` only for `ENOENT` — genuinely
|
|
1295
1454
|
* missing. Any other error (a permission problem, a transient `EMFILE`,
|
|
@@ -1300,12 +1459,12 @@ declare class KbStore {
|
|
|
1300
1459
|
* therefore left untouched and reported as a failure like any other.
|
|
1301
1460
|
*
|
|
1302
1461
|
* Two processes racing the append branch — both read a file without the
|
|
1303
|
-
*
|
|
1304
|
-
* `O_APPEND`, so the result is two copies of the same
|
|
1305
|
-
* torn write, and
|
|
1306
|
-
*
|
|
1307
|
-
*
|
|
1308
|
-
*
|
|
1462
|
+
* lines, both append them — is possible and left unguarded: `appendFile` is
|
|
1463
|
+
* `O_APPEND`, so the result is two copies of the same lines rather than a
|
|
1464
|
+
* torn write, and the next call sees a duplicate declaration as "already
|
|
1465
|
+
* declared". A cheap-to-detect, harmless-to-leave residue, not a reason to
|
|
1466
|
+
* add a cross-process lock (see `ARCHITECTURE.md`'s rejection of one for
|
|
1467
|
+
* the same trade on records).
|
|
1309
1468
|
*
|
|
1310
1469
|
* Best-effort, like the log append it precedes: failing to write this
|
|
1311
1470
|
* file must not fail the mutation it guards.
|
|
@@ -1341,9 +1500,15 @@ declare enum Fault {
|
|
|
1341
1500
|
/** Machine-readable discriminant, stable across message rewording. */
|
|
1342
1501
|
declare enum ErrorTypes {
|
|
1343
1502
|
KbRecordAlreadyExists = "KbRecordAlreadyExists",
|
|
1503
|
+
KbClassifyInput = "KbClassifyInput",
|
|
1344
1504
|
KbInvalidConceptId = "KbInvalidConceptId",
|
|
1505
|
+
KbMatchInput = "KbMatchInput",
|
|
1345
1506
|
KbMissingFlagValue = "KbMissingFlagValue",
|
|
1346
1507
|
KbPackBudgetExceeded = "KbPackBudgetExceeded",
|
|
1508
|
+
KbPromoteCollision = "KbPromoteCollision",
|
|
1509
|
+
KbPromoteSelf = "KbPromoteSelf",
|
|
1510
|
+
KbPromoteStanding = "KbPromoteStanding",
|
|
1511
|
+
KbPromoteStopped = "KbPromoteStopped",
|
|
1347
1512
|
KbRecordNotFound = "KbRecordNotFound",
|
|
1348
1513
|
KbSelfVerification = "KbSelfVerification",
|
|
1349
1514
|
KbStampBaselineUnreadable = "KbStampBaselineUnreadable",
|
|
@@ -1437,6 +1602,35 @@ declare class KbMissingFlagValueError extends BaseError {
|
|
|
1437
1602
|
readonly flag: string;
|
|
1438
1603
|
constructor(flag: string);
|
|
1439
1604
|
}
|
|
1605
|
+
/** `classify` invoked with no diff it could read, or one it could not parse. */
|
|
1606
|
+
declare class KbClassifyInputError extends BaseError {
|
|
1607
|
+
readonly reason: string;
|
|
1608
|
+
constructor(reason: string);
|
|
1609
|
+
}
|
|
1610
|
+
/** The target base already holds one of the records. Refused for the whole run. */
|
|
1611
|
+
declare class KbPromoteCollisionError extends BaseError {
|
|
1612
|
+
readonly conceptId: string;
|
|
1613
|
+
readonly to: string;
|
|
1614
|
+
constructor(conceptId: string, to: string);
|
|
1615
|
+
}
|
|
1616
|
+
/** Promotion carries a record's standing, so a withdrawn one may not be copied. */
|
|
1617
|
+
declare class KbPromoteStandingError extends BaseError {
|
|
1618
|
+
readonly conceptId: string;
|
|
1619
|
+
readonly standing: string;
|
|
1620
|
+
constructor(conceptId: string, standing: string);
|
|
1621
|
+
}
|
|
1622
|
+
/** Source and target are the same base: the run would rewrite its own records. */
|
|
1623
|
+
declare class KbPromoteSelfError extends BaseError {
|
|
1624
|
+
readonly to: string;
|
|
1625
|
+
constructor(to: string);
|
|
1626
|
+
}
|
|
1627
|
+
/** A write failed after earlier ones landed; `landed` is what the target now holds. */
|
|
1628
|
+
declare class KbPromoteStoppedError extends BaseError {
|
|
1629
|
+
readonly conceptId: string;
|
|
1630
|
+
readonly landed: string[];
|
|
1631
|
+
readonly reason: string;
|
|
1632
|
+
constructor(conceptId: string, landed: string[], reason: string);
|
|
1633
|
+
}
|
|
1440
1634
|
declare class KbInvalidConceptIdError extends BaseError {
|
|
1441
1635
|
constructor(message: string, details: Record<string, string>);
|
|
1442
1636
|
}
|
|
@@ -1612,6 +1806,14 @@ declare const composeInputSchema: z.ZodObject<{
|
|
|
1612
1806
|
anchors: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
1613
1807
|
file: z.ZodString;
|
|
1614
1808
|
symbol: z.ZodOptional<z.ZodString>;
|
|
1809
|
+
span: z.ZodOptional<z.ZodObject<{
|
|
1810
|
+
start: z.ZodNumber;
|
|
1811
|
+
end: z.ZodNumber;
|
|
1812
|
+
}, z.core.$strict>>;
|
|
1813
|
+
side: z.ZodOptional<z.ZodEnum<{
|
|
1814
|
+
old: "old";
|
|
1815
|
+
new: "new";
|
|
1816
|
+
}>>;
|
|
1615
1817
|
repo: z.ZodOptional<z.ZodString>;
|
|
1616
1818
|
ref: z.ZodOptional<z.ZodString>;
|
|
1617
1819
|
hash: z.ZodOptional<z.ZodString>;
|
|
@@ -1622,6 +1824,7 @@ declare const composeInputSchema: z.ZodObject<{
|
|
|
1622
1824
|
resolved_at: z.ZodOptional<z.ZodString>;
|
|
1623
1825
|
lines: z.ZodOptional<z.ZodNumber>;
|
|
1624
1826
|
resolver: z.ZodOptional<z.ZodEnum<{
|
|
1827
|
+
span: "span";
|
|
1625
1828
|
"tree-sitter": "tree-sitter";
|
|
1626
1829
|
regex: "regex";
|
|
1627
1830
|
}>>;
|
|
@@ -1761,9 +1964,15 @@ declare const pinsManifestSchema: z.ZodObject<{
|
|
|
1761
1964
|
}, z.core.$loose>;
|
|
1762
1965
|
type KbPin = z.infer<typeof pinSchema>;
|
|
1763
1966
|
type KbPinsManifest = z.infer<typeof pinsManifestSchema>;
|
|
1967
|
+
/** One profile's `context` settings, from the manifest or the built-ins. */
|
|
1764
1968
|
type KbContextBudgets = {
|
|
1765
1969
|
budgetTokens?: number;
|
|
1766
1970
|
fullUnderTokens?: number;
|
|
1971
|
+
/**
|
|
1972
|
+
* Frontmatter tags whose records this profile leaves out of the block —
|
|
1973
|
+
* `review`, say, kept out of session-start without unpinning the base.
|
|
1974
|
+
*/
|
|
1975
|
+
excludeTags?: string[];
|
|
1767
1976
|
};
|
|
1768
1977
|
/** A pin as the merged view hands it back: entry + where it came from. */
|
|
1769
1978
|
type KbMergedPin = KbPin & {
|
|
@@ -1903,6 +2112,12 @@ type KbContextOptions = {
|
|
|
1903
2112
|
* name.
|
|
1904
2113
|
*/
|
|
1905
2114
|
profile?: string;
|
|
2115
|
+
/**
|
|
2116
|
+
* Frontmatter tags whose records stay out of the block. Resolved like the
|
|
2117
|
+
* budgets, and a profile setting rather than a pin's: it says what this
|
|
2118
|
+
* context birth wants, so a base stays pinned and stays readable by tool.
|
|
2119
|
+
*/
|
|
2120
|
+
excludeTags?: string[];
|
|
1906
2121
|
/**
|
|
1907
2122
|
* Where budget pressure is reported outside the block itself: a full pin
|
|
1908
2123
|
* that had to degrade to an index, a block that refused. The block already
|
|
@@ -1986,14 +2201,28 @@ declare function kbJsonSchemas(): Record<string, unknown>;
|
|
|
1986
2201
|
* those, not the base.
|
|
1987
2202
|
*/
|
|
1988
2203
|
type DiffHunk = {
|
|
1989
|
-
/** 1-based, inclusive, in the
|
|
2204
|
+
/** 1-based, inclusive, in the numbering of this hunk's `side`. */
|
|
1990
2205
|
startLine: number;
|
|
1991
2206
|
endLine: number;
|
|
2207
|
+
/**
|
|
2208
|
+
* Which half of the change these lines number; absent means `new`. An
|
|
2209
|
+
* old-side anchor lands here on the caller's word that its `ref` is this
|
|
2210
|
+
* diff's base rev — nothing compares the two.
|
|
2211
|
+
*/
|
|
2212
|
+
side?: "old" | "new";
|
|
2213
|
+
/**
|
|
2214
|
+
* This hunk's own changed lines, markers stripped, where a parser kept them.
|
|
2215
|
+
* Nothing here reads them; a caller classifying content does.
|
|
2216
|
+
*/
|
|
2217
|
+
lines?: string[];
|
|
1992
2218
|
};
|
|
1993
2219
|
type DiffFile = {
|
|
1994
2220
|
/** Repo-relative, matching how anchors are written. */
|
|
1995
2221
|
filePath: string;
|
|
1996
2222
|
hunks: DiffHunk[];
|
|
2223
|
+
/** Where `git diff -M` says this path came from, and how alike the two are. */
|
|
2224
|
+
renamedFrom?: string;
|
|
2225
|
+
similarity?: number;
|
|
1997
2226
|
};
|
|
1998
2227
|
/**
|
|
1999
2228
|
* A symbol resolved to lines. Supplied by whatever the caller uses to index
|
|
@@ -2004,6 +2233,8 @@ type SymbolRange = {
|
|
|
2004
2233
|
symbol: string;
|
|
2005
2234
|
startLine: number;
|
|
2006
2235
|
endLine: number;
|
|
2236
|
+
/** Which side these lines number; absent means `new`, as on a hunk. */
|
|
2237
|
+
side?: "old" | "new";
|
|
2007
2238
|
};
|
|
2008
2239
|
type DiffMatch = {
|
|
2009
2240
|
filePath: string;
|
|
@@ -2024,6 +2255,157 @@ type MatchOptions = {
|
|
|
2024
2255
|
now?: Date;
|
|
2025
2256
|
};
|
|
2026
2257
|
declare function matchToDiff(files: DiffFile[], records: KbRecord[], options?: MatchOptions): DiffMatch[];
|
|
2258
|
+
/** The anchor alone, for a caller that already knows the hunk matched. */
|
|
2259
|
+
declare function anchorOnHunk(record: KbRecord, filePath: string, hunk: DiffHunk, symbolRanges?: readonly SymbolRange[] | SymbolRangeIndex): KbAnchor | undefined;
|
|
2260
|
+
/** Built once by a caller placing many records on many hunks of one diff. */
|
|
2261
|
+
type SymbolRangeIndex = ReadonlyMap<string, SymbolRange[]>;
|
|
2262
|
+
declare function symbolRangeIndex(ranges: readonly SymbolRange[]): SymbolRangeIndex;
|
|
2263
|
+
|
|
2264
|
+
/**
|
|
2265
|
+
* Every operation a knowledge base exposes, defined once.
|
|
2266
|
+
*
|
|
2267
|
+
* The CLI and the MCP server are both projections of this table. Kept apart
|
|
2268
|
+
* they drift within a day — fourteen commands against six tools — which is the
|
|
2269
|
+
* same failure as a schema restated in prose beside the code that enforces it,
|
|
2270
|
+
* one level up. A command added to the table appears in both surfaces or in
|
|
2271
|
+
* neither, and a test asserts exactly that.
|
|
2272
|
+
*
|
|
2273
|
+
* The two differ only in how arguments arrive: MCP passes an object matching
|
|
2274
|
+
* `input`, while the CLI has to turn positional argv into the same object.
|
|
2275
|
+
* `fromArgv` is that adapter and is the only per-surface code a command needs.
|
|
2276
|
+
*
|
|
2277
|
+
* One file per command in this folder; `index.ts` assembles the table.
|
|
2278
|
+
*/
|
|
2279
|
+
type KbCommandContext = {
|
|
2280
|
+
store: KbStore;
|
|
2281
|
+
actor: string;
|
|
2282
|
+
now: () => string;
|
|
2283
|
+
};
|
|
2284
|
+
type KbCommand<Shape extends z.ZodRawShape = z.ZodRawShape> = {
|
|
2285
|
+
/** CLI verb. */
|
|
2286
|
+
name: string;
|
|
2287
|
+
/**
|
|
2288
|
+
* MCP tool name. Absent only for CLI-only plumbing (`sync-instructions`),
|
|
2289
|
+
* which exists to edit files for hooks and instruction blocks rather than to
|
|
2290
|
+
* give an agent a capability — the capability, "get the pinned context
|
|
2291
|
+
* block", is `kb_context`.
|
|
2292
|
+
*/
|
|
2293
|
+
tool?: string;
|
|
2294
|
+
/** Argument spelling for CLI usage output. */
|
|
2295
|
+
usage: string;
|
|
2296
|
+
/** Shown to an agent choosing a tool, so it carries the judgment too. */
|
|
2297
|
+
description: string;
|
|
2298
|
+
input: z.ZodObject<Shape>;
|
|
2299
|
+
/**
|
|
2300
|
+
* Positional argv → the same object MCP receives. `bundleExplicit` says
|
|
2301
|
+
* whether `--bundle` was actually passed, for the one command whose meaning
|
|
2302
|
+
* turns on it: `stamp` with no bundle stamps every pinned base.
|
|
2303
|
+
*/
|
|
2304
|
+
fromArgv(argv: string[], bundlePath: string, stdin: () => Promise<string>, bundleExplicit?: boolean): Promise<unknown> | unknown;
|
|
2305
|
+
run(ctx: KbCommandContext, input: z.infer<z.ZodObject<Shape>>): Promise<unknown>;
|
|
2306
|
+
/**
|
|
2307
|
+
* A human-readable form of the result, for the CLI. Where it exists the CLI
|
|
2308
|
+
* prints it and `--json` asks for the machine shape instead; MCP always gets
|
|
2309
|
+
* the machine shape, since a tool result is parsed rather than read.
|
|
2310
|
+
*
|
|
2311
|
+
* Separate from `run` rather than rendered inside it — as `pack` does, whose
|
|
2312
|
+
* result *is* a document — because a command whose result is a report needs
|
|
2313
|
+
* both forms: the table for a person, and the object for `failsWhen` and for
|
|
2314
|
+
* anything downstream.
|
|
2315
|
+
*/
|
|
2316
|
+
render?(result: unknown): string;
|
|
2317
|
+
/**
|
|
2318
|
+
* Turns a result into a non-zero exit for the CLI. A check that reports a
|
|
2319
|
+
* problem has succeeded as a command and failed as a check, and a shell
|
|
2320
|
+
* caller can only see the difference through the exit code.
|
|
2321
|
+
*
|
|
2322
|
+
* The input comes too, so a command can make the exit conditional on a flag
|
|
2323
|
+
* the caller passed rather than on the result alone.
|
|
2324
|
+
*/
|
|
2325
|
+
failsWhen?(result: unknown, input: z.infer<z.ZodObject<Shape>>): boolean;
|
|
2326
|
+
};
|
|
2327
|
+
|
|
2328
|
+
/** One record on a hunk: enough to decide whether to read it, and no body. */
|
|
2329
|
+
type KbMatchRecord = {
|
|
2330
|
+
conceptId: string;
|
|
2331
|
+
type: string;
|
|
2332
|
+
title: string | null;
|
|
2333
|
+
/** Carried on every entry, so a hit is never handed over as a bare match. */
|
|
2334
|
+
standing: KbStanding;
|
|
2335
|
+
status: KbRecordStatus;
|
|
2336
|
+
/** Where the supersession chain ends. Empty while the record still holds. */
|
|
2337
|
+
supersededBy: string[];
|
|
2338
|
+
materiality?: KbRecordFrontmatter["strauss_materiality"];
|
|
2339
|
+
confidence?: KbRecordFrontmatter["strauss_confidence"];
|
|
2340
|
+
tags?: string[];
|
|
2341
|
+
/** The anchor that put this record on this hunk. */
|
|
2342
|
+
anchor?: KbAnchor;
|
|
2343
|
+
};
|
|
2344
|
+
type KbMatch = {
|
|
2345
|
+
filePath: string;
|
|
2346
|
+
hunk: DiffHunk;
|
|
2347
|
+
/** `symbol` when every record here was placed by a resolved symbol range. */
|
|
2348
|
+
precision: "symbol" | "file";
|
|
2349
|
+
records: KbMatchRecord[];
|
|
2350
|
+
};
|
|
2351
|
+
|
|
2352
|
+
/**
|
|
2353
|
+
* What a reviewer can skim and what they must read, derived from the diff.
|
|
2354
|
+
*
|
|
2355
|
+
* A closed set: a consumer branches on these nine, and a tenth would arrive
|
|
2356
|
+
* unhandled. `source` is the residue — everything no rule claimed.
|
|
2357
|
+
*/
|
|
2358
|
+
declare const KB_CLASSES: readonly ["test", "config", "ci", "docs", "lockfile", "generated", "boilerplate", "rename", "source"];
|
|
2359
|
+
type KbClass = (typeof KB_CLASSES)[number];
|
|
2360
|
+
/** A diff file, plus the head lines a caller could read for it. */
|
|
2361
|
+
type KbClassifyFile = DiffFile & {
|
|
2362
|
+
/** The file's first lines at head. Absent falls back to the diff's own. */
|
|
2363
|
+
header?: string[];
|
|
2364
|
+
};
|
|
2365
|
+
type KbClassifyThresholds = {
|
|
2366
|
+
/** Share of a file's changed lines that must match a boilerplate shape. */
|
|
2367
|
+
boilerplate?: number;
|
|
2368
|
+
/** The `git diff -M` similarity a rename needs before it is called one. */
|
|
2369
|
+
rename?: number;
|
|
2370
|
+
};
|
|
2371
|
+
declare const DEFAULT_THRESHOLDS: Required<KbClassifyThresholds>;
|
|
2372
|
+
type KbClassifyOptions = {
|
|
2373
|
+
/** The base, for the `review:*` overrides. Adjudicated: only current wins. */
|
|
2374
|
+
records?: KbRecord[];
|
|
2375
|
+
/** Without these a symbol anchor covers its whole file rather than a hunk. */
|
|
2376
|
+
symbolRanges?: readonly SymbolRange[];
|
|
2377
|
+
now?: Date;
|
|
2378
|
+
thresholds?: KbClassifyThresholds;
|
|
2379
|
+
};
|
|
2380
|
+
/** The class and the name of the rule that produced it. */
|
|
2381
|
+
type KbVerdict = {
|
|
2382
|
+
class: KbClass;
|
|
2383
|
+
reason: string;
|
|
2384
|
+
};
|
|
2385
|
+
type KbClassifiedHunk = KbVerdict & {
|
|
2386
|
+
startLine: number;
|
|
2387
|
+
endLine: number;
|
|
2388
|
+
};
|
|
2389
|
+
type KbClassifiedFile = KbVerdict & {
|
|
2390
|
+
filePath: string;
|
|
2391
|
+
renamedFrom?: string;
|
|
2392
|
+
/** Present only where some hunk's class differs from the file's. */
|
|
2393
|
+
hunks?: KbClassifiedHunk[];
|
|
2394
|
+
};
|
|
2395
|
+
type KbClassifyResult = {
|
|
2396
|
+
files: KbClassifiedFile[];
|
|
2397
|
+
};
|
|
2398
|
+
|
|
2399
|
+
/**
|
|
2400
|
+
* What kind of change each file carries.
|
|
2401
|
+
*
|
|
2402
|
+
* Every input is in the diff, so nothing here is written down: a class the KB
|
|
2403
|
+
* stored would be a second copy of an answer the patch already gives, and the
|
|
2404
|
+
* two would disagree the first time a rule changed. The one thing a script
|
|
2405
|
+
* cannot derive — "this output is generated, read its input instead" — is a
|
|
2406
|
+
* record, and it wins over the heuristic.
|
|
2407
|
+
*/
|
|
2408
|
+
declare function classifyDiff(files: readonly KbClassifyFile[], options?: KbClassifyOptions): KbClassifiedFile[];
|
|
2027
2409
|
|
|
2028
2410
|
/**
|
|
2029
2411
|
* The edges between records in one bundle, defined once.
|
|
@@ -2161,6 +2543,14 @@ type KbAnchorResolverCounts = {
|
|
|
2161
2543
|
treeSitter: number;
|
|
2162
2544
|
/** Includes anchors stamped before resolvers were named. */
|
|
2163
2545
|
regex: number;
|
|
2546
|
+
/** Author-given line ranges, hashed exactly as written. */
|
|
2547
|
+
span: number;
|
|
2548
|
+
/**
|
|
2549
|
+
* Hashed anchors read at their `ref` rather than the working tree. Counted
|
|
2550
|
+
* beside the resolver buckets and outside `total`: `side` is not a resolver,
|
|
2551
|
+
* and one of these may name a whole file.
|
|
2552
|
+
*/
|
|
2553
|
+
oldSide: number;
|
|
2164
2554
|
};
|
|
2165
2555
|
type KbDoctorOptions = {
|
|
2166
2556
|
/** How far ahead `expiring` looks. */
|
|
@@ -2224,6 +2614,14 @@ declare const decisionInputSchema: z.ZodObject<{
|
|
|
2224
2614
|
anchors: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
2225
2615
|
file: z.ZodString;
|
|
2226
2616
|
symbol: z.ZodOptional<z.ZodString>;
|
|
2617
|
+
span: z.ZodOptional<z.ZodObject<{
|
|
2618
|
+
start: z.ZodNumber;
|
|
2619
|
+
end: z.ZodNumber;
|
|
2620
|
+
}, z.core.$strict>>;
|
|
2621
|
+
side: z.ZodOptional<z.ZodEnum<{
|
|
2622
|
+
old: "old";
|
|
2623
|
+
new: "new";
|
|
2624
|
+
}>>;
|
|
2227
2625
|
repo: z.ZodOptional<z.ZodString>;
|
|
2228
2626
|
ref: z.ZodOptional<z.ZodString>;
|
|
2229
2627
|
hash: z.ZodOptional<z.ZodString>;
|
|
@@ -2234,6 +2632,7 @@ declare const decisionInputSchema: z.ZodObject<{
|
|
|
2234
2632
|
resolved_at: z.ZodOptional<z.ZodString>;
|
|
2235
2633
|
lines: z.ZodOptional<z.ZodNumber>;
|
|
2236
2634
|
resolver: z.ZodOptional<z.ZodEnum<{
|
|
2635
|
+
span: "span";
|
|
2237
2636
|
"tree-sitter": "tree-sitter";
|
|
2238
2637
|
regex: "regex";
|
|
2239
2638
|
}>>;
|
|
@@ -2283,90 +2682,100 @@ declare function isNoDecisionRecord(record: KbRecord): boolean;
|
|
|
2283
2682
|
declare function selectDecisions(records: KbRecord[]): KbRecord[];
|
|
2284
2683
|
|
|
2285
2684
|
/**
|
|
2286
|
-
*
|
|
2287
|
-
*
|
|
2288
|
-
* The CLI and the MCP server are both projections of this table. Kept apart
|
|
2289
|
-
* they drift within a day — fourteen commands against six tools — which is the
|
|
2290
|
-
* same failure as a schema restated in prose beside the code that enforces it,
|
|
2291
|
-
* one level up. A command added to the table appears in both surfaces or in
|
|
2292
|
-
* neither, and a test asserts exactly that.
|
|
2293
|
-
*
|
|
2294
|
-
* The two differ only in how arguments arrive: MCP passes an object matching
|
|
2295
|
-
* `input`, while the CLI has to turn positional argv into the same object.
|
|
2296
|
-
* `fromArgv` is that adapter and is the only per-surface code a command needs.
|
|
2685
|
+
* The command table, assembled from one file per command.
|
|
2297
2686
|
*
|
|
2298
|
-
*
|
|
2687
|
+
* Order is the CLI usage listing's order: the write path, the read path,
|
|
2688
|
+
* base housekeeping, the format, and the workspace pin verbs.
|
|
2299
2689
|
*/
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2690
|
+
|
|
2691
|
+
declare const KB_COMMANDS: KbCommand[];
|
|
2692
|
+
declare const KB_COMMANDS_BY_NAME: Map<string, KbCommand>;
|
|
2693
|
+
|
|
2694
|
+
/**
|
|
2695
|
+
* Listing candidates and promoting share one input, and the two need different
|
|
2696
|
+
* arguments. The rule lives here rather than in `run` so both surfaces refuse
|
|
2697
|
+
* the same call: the CLI before it dispatches, MCP before the tool runs.
|
|
2698
|
+
*/
|
|
2699
|
+
declare const promoteInputSchema: z.ZodObject<{
|
|
2700
|
+
bundlePath: z.ZodString;
|
|
2701
|
+
conceptIds: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
2702
|
+
to: z.ZodOptional<z.ZodString>;
|
|
2703
|
+
source: z.ZodOptional<z.ZodString>;
|
|
2704
|
+
force: z.ZodOptional<z.ZodBoolean>;
|
|
2705
|
+
list: z.ZodOptional<z.ZodBoolean>;
|
|
2706
|
+
}, z.core.$strip>;
|
|
2707
|
+
/** A typed link the copy does not carry, because its target stayed behind. */
|
|
2708
|
+
type KbDroppedLink = {
|
|
2709
|
+
target: string;
|
|
2710
|
+
rel: string;
|
|
2304
2711
|
};
|
|
2305
|
-
type
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
* turns on it: `stamp` with no bundle stamps every pinned base.
|
|
2324
|
-
*/
|
|
2325
|
-
fromArgv(argv: string[], bundlePath: string, stdin: () => Promise<string>, bundleExplicit?: boolean): Promise<unknown> | unknown;
|
|
2326
|
-
run(ctx: KbCommandContext, input: z.infer<z.ZodObject<Shape>>): Promise<unknown>;
|
|
2327
|
-
/**
|
|
2328
|
-
* A human-readable form of the result, for the CLI. Where it exists the CLI
|
|
2329
|
-
* prints it and `--json` asks for the machine shape instead; MCP always gets
|
|
2330
|
-
* the machine shape, since a tool result is parsed rather than read.
|
|
2331
|
-
*
|
|
2332
|
-
* Separate from `run` rather than rendered inside it — as `pack` does, whose
|
|
2333
|
-
* result *is* a document — because a command whose result is a report needs
|
|
2334
|
-
* both forms: the table for a person, and the object for `failsWhen` and for
|
|
2335
|
-
* anything downstream.
|
|
2336
|
-
*/
|
|
2337
|
-
render?(result: unknown): string;
|
|
2338
|
-
/**
|
|
2339
|
-
* Turns a result into a non-zero exit for the CLI. A check that reports a
|
|
2340
|
-
* problem has succeeded as a command and failed as a check, and a shell
|
|
2341
|
-
* caller can only see the difference through the exit code.
|
|
2342
|
-
*
|
|
2343
|
-
* The input comes too, so a command can make the exit conditional on a flag
|
|
2344
|
-
* the caller passed rather than on the result alone.
|
|
2345
|
-
*/
|
|
2346
|
-
failsWhen?(result: unknown, input: z.infer<z.ZodObject<Shape>>): boolean;
|
|
2712
|
+
type KbPromotedRecord = {
|
|
2713
|
+
conceptId: string;
|
|
2714
|
+
droppedLinks: KbDroppedLink[];
|
|
2715
|
+
};
|
|
2716
|
+
type KbPromoteCandidate = {
|
|
2717
|
+
conceptId: string;
|
|
2718
|
+
type: string;
|
|
2719
|
+
title: string | null;
|
|
2720
|
+
/** The rule that made it a candidate, in the reader's terms. */
|
|
2721
|
+
why: string;
|
|
2722
|
+
};
|
|
2723
|
+
type KbPromoteResult = {
|
|
2724
|
+
mode: "list";
|
|
2725
|
+
candidates: KbPromoteCandidate[];
|
|
2726
|
+
} | {
|
|
2727
|
+
mode: "promote";
|
|
2728
|
+
to: string;
|
|
2729
|
+
promoted: KbPromotedRecord[];
|
|
2347
2730
|
};
|
|
2348
2731
|
|
|
2732
|
+
/** The source entry a promotion adds, replaced rather than repeated on re-promote. */
|
|
2733
|
+
declare const PROMOTION_SOURCE_ID = "promoted";
|
|
2734
|
+
type KbCarriedRecord = {
|
|
2735
|
+
frontmatter: Omit<KbRecordFrontmatter, "type">;
|
|
2736
|
+
body: string;
|
|
2737
|
+
droppedLinks: KbDroppedLink[];
|
|
2738
|
+
};
|
|
2349
2739
|
/**
|
|
2350
|
-
*
|
|
2740
|
+
* One record as the target base should hold it.
|
|
2351
2741
|
*
|
|
2352
|
-
*
|
|
2353
|
-
*
|
|
2742
|
+
* Frontmatter is carried rather than recomposed: OKF requires a consumer to
|
|
2743
|
+
* preserve keys it does not recognise when round-tripping, and a record written
|
|
2744
|
+
* by another producer would lose them to a rebuild from known fields.
|
|
2354
2745
|
*/
|
|
2746
|
+
declare function carry(record: KbRecord, promoted: ReadonlySet<string>, source?: string): KbCarriedRecord;
|
|
2747
|
+
/**
|
|
2748
|
+
* `review` and the `review:<id>` family alike: the target base is not a review
|
|
2749
|
+
* base, so a tag saying which review wrote the record no longer selects
|
|
2750
|
+
* anything there.
|
|
2751
|
+
*/
|
|
2752
|
+
declare function isReviewTag(tag: string): boolean;
|
|
2355
2753
|
|
|
2356
|
-
|
|
2357
|
-
|
|
2754
|
+
/**
|
|
2755
|
+
* What in a review base is worth keeping once the change merges. Heuristics over
|
|
2756
|
+
* what a reviewer usually wants; a record they cut is still nameable by hand.
|
|
2757
|
+
* A withdrawn record is not among them — `promote` refuses those outright.
|
|
2758
|
+
*/
|
|
2759
|
+
declare function promoteCandidates(bundle: KbRecord[]): KbPromoteCandidate[];
|
|
2358
2760
|
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
/**
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
}
|
|
2366
|
-
/**
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2761
|
+
type KbExportedDecision = {
|
|
2762
|
+
conceptId: string;
|
|
2763
|
+
/** File name within the target directory, `NNNN-<slug>.md`. */
|
|
2764
|
+
file: string;
|
|
2765
|
+
/** The ADR's Status line, as adjudication settled it. */
|
|
2766
|
+
status: string;
|
|
2767
|
+
};
|
|
2768
|
+
/** A file this exporter did not write, holding the name a decision needs. */
|
|
2769
|
+
type KbExportForeignFile = {
|
|
2770
|
+
conceptId: string;
|
|
2771
|
+
file: string;
|
|
2772
|
+
};
|
|
2773
|
+
type KbExportResult = {
|
|
2774
|
+
to: string;
|
|
2775
|
+
format: "madr";
|
|
2776
|
+
exported: KbExportedDecision[];
|
|
2777
|
+
/** Decisions left unwritten because a foreign file already holds their name. */
|
|
2778
|
+
foreign: KbExportForeignFile[];
|
|
2370
2779
|
};
|
|
2371
2780
|
|
|
2372
2781
|
type MovedSearch = {
|
|
@@ -2671,4 +3080,4 @@ declare function parseMarkdownWithFrontmatter<S extends z.ZodType>(text: string,
|
|
|
2671
3080
|
frontmatter: ReturnType<S["safeParse"]>;
|
|
2672
3081
|
};
|
|
2673
3082
|
|
|
2674
|
-
export { type AnchorResolution, type AnchorResolver, type AnchorResolverName, BaseError, CONTEXT_BEGIN, CONTEXT_END, CONTEXT_PROFILES, type ClassifiedAnchor, type ComposeInput, type ComposeLink, type ComposedRecord, DECISION_TYPE, DEFAULT_AGING_DAYS, DEFAULT_EXPIRING_DAYS, DEFAULT_LOAD_BUDGET, DEFAULT_PACK_HOPS, DEFAULT_PACK_MAX_NODES, DEFAULT_TYPED_LINK_RELS, DEFAULT_UNVERIFIED_DAYS, type DecisionInput, type DiffFile, type DiffHunk, type DiffMatch, type ErrorDetails, type ErrorProps, ErrorTypes, Fault, type Grammar, type GrammarManifest, type GrammarOptions, INDEX_FILE, KB_CAUSAL_LINK_RELS, KB_COMMANDS, KB_COMMANDS_BY_NAME, KB_CONCEPT_ID_PATTERN, KB_CONFIDENCES, KB_DIR, KB_DOCTOR_CHECKS, KB_EDGE_KINDS, KB_LINK_RELS, KB_MATERIALITIES, KB_RECORD_STATUSES, KB_RECORD_TYPES, KB_SLUG_PATTERN, type KbActorStamp, type KbAdjudicated, type KbAnchor, type KbAnchorDriftEntry, type KbBacklink, type KbBacklinksResult, KbBaseFrozenError, type KbCatalogEntry, type KbCatalogResult, type KbCommand, type KbCommandContext, type KbContextBudgets, type KbContextOptions, type KbContextResult, type KbDoctorCheck, type KbDoctorFinding, type KbDoctorGroup, type KbDoctorOptions, type KbDoctorReport, type KbDoctorThresholds, type KbEdgeKind, type KbImpactOptions, type KbImpactResult, type KbImpactedRecord, type KbInboundEdge, KbInvalidConceptIdError, type KbLink, type KbLinkEdge, type KbLinkRel, type KbLinkRelSpec, type KbLoadResult, type KbLogEntry, type KbLogReadResult, type KbLogger, type KbMergedPin, type KbMergedPins, KbMissingFlagValueError, type KbNeighbour, KbPackBudgetExceededError, type KbPackOptions, type KbPackResult, type KbPackedRecord, type KbPin, type KbPinLayer, type KbPinOptions, type KbPinResult, type KbPinStatus, KbPinsMalformedError, type KbPinsManifest, type KbReassessAnchor, type KbReassessDefault, type KbReassessDiff, type KbReassessPacket, type KbRecord, KbRecordAlreadyExistsError, type KbRecordFrontmatter, KbRecordNotFoundError, type KbRecordStatus, type KbRecordType, type KbRecordTypeSpec, type KbSearchLogger, KbSelfVerificationError, type KbSource, type KbStanding, KbStore, type KbSupersededStub, type KbSyncResult, type KbTraceEdge, type KbTraceOptions, type KbTraceStep, KbUnknownLinkRelError, type KbValidationProblem, type KbValidationSeverity, type KbVerifiedEvent, type KbWarning, KbWriteConflictError, type KbWriteInput, LINK_RELS, LOG_FILE, type MatchOptions, NO_DECISION_SLUG, PINS_FILE, PINS_LOCAL_FILE, PIN_LAYERS, type QmdModule, RECORD_TYPES, type RemoteAnchorState, type RemoteOptions, type RemoteRead, type ResolvedSymbol, type ResolverAttempt, SEARCH_INDEX_FILE, type SearchHit, type SearchOptions, type SymbolRange, TRACE_EDGES, TreeSitterResolver, adjudicate, anchorFilePath, assertBaseNotFrozen, backlinks, buildContext, catalog, classifyDrift, composeDecisionRecord, composeInputSchema, composeLinkSchema, composeNoDecisionRecord, composeRecord, contextProfileBudgets, createKbMcpServer, decisionInputSchema, defaultAnchorResolvers, detectAnchorDrift, doctor, edgeNeighbours, ensureGrammar, grammarHints, grammarManifest, grammarsCacheRoot, hashAnchorText, impact, inboundIndex, indexIsStale, isCanonicalRepoUrl, isKbLinkRel, isKbRecordType, isNoDecisionRecord, kbActorStampSchema, kbAnchorSchema, kbConceptIdSchema, kbJsonSchemas, kbLinkSchema, kbLogEntrySchema, kbRecordFrontmatterSchema, kbSourceSchema, kbVerifiedEventSchema, languageForFile, listPins, loadQmd, matchToDiff, mergedContextBudgets, neighbours, pack, parseLog, parseMarkdownWithFrontmatter, pinBase, prepareResolvers, readMergedPins, readPinsLayer, readRemoteAnchors, reassessPacket, regexResolver, renderCatalogLine, renderIndex, renderIndexLine, renderLogEntry, repoCacheDir, resolveAnchor, resolveAnchorSpan, resolveHeads, resolveHits, resolvePinPath, runKbCli, runKbMcpServer, searchBase, selectDecisions, splitMarkdownFrontmatter, stringifyMarkdownWithFrontmatter, syncInstructions, toHookJson, trace, treeSitterLanguages, unifiedDiff, unpinBase, validateBundle };
|
|
3083
|
+
export { type AnchorResolution, type AnchorResolver, type AnchorResolverName, BaseError, CONTEXT_BEGIN, CONTEXT_END, CONTEXT_PROFILES, type ClassifiedAnchor, type ComposeInput, type ComposeLink, type ComposedRecord, DECISION_TYPE, DEFAULT_AGING_DAYS, DEFAULT_EXPIRING_DAYS, DEFAULT_LOAD_BUDGET, DEFAULT_PACK_HOPS, DEFAULT_PACK_MAX_NODES, DEFAULT_THRESHOLDS, DEFAULT_TYPED_LINK_RELS, DEFAULT_UNVERIFIED_DAYS, type DecisionInput, type DiffFile, type DiffHunk, type DiffMatch, type ErrorDetails, type ErrorProps, ErrorTypes, Fault, type Grammar, type GrammarManifest, type GrammarOptions, INDEX_FILE, KB_CAUSAL_LINK_RELS, KB_CLASSES, KB_COMMANDS, KB_COMMANDS_BY_NAME, KB_CONCEPT_ID_PATTERN, KB_CONFIDENCES, KB_DIR, KB_DOCTOR_CHECKS, KB_EDGE_KINDS, KB_LINK_RELS, KB_MATERIALITIES, KB_RECORD_STATUSES, KB_RECORD_TYPES, KB_SLUG_PATTERN, type KbActorStamp, type KbAdjudicated, type KbAnchor, type KbAnchorDriftEntry, type KbAnchorSpan, type KbBacklink, type KbBacklinksResult, KbBaseFrozenError, type KbCatalogEntry, type KbCatalogResult, type KbClass, type KbClassifiedFile, type KbClassifiedHunk, type KbClassifyFile, KbClassifyInputError, type KbClassifyOptions, type KbClassifyResult, type KbClassifyThresholds, type KbCommand, type KbCommandContext, type KbContextBudgets, type KbContextOptions, type KbContextResult, type KbDoctorCheck, type KbDoctorFinding, type KbDoctorGroup, type KbDoctorOptions, type KbDoctorReport, type KbDoctorThresholds, type KbDroppedLink, type KbEdgeKind, type KbExportForeignFile, type KbExportResult, type KbExportedDecision, type KbImpactOptions, type KbImpactResult, type KbImpactedRecord, type KbInboundEdge, KbInvalidConceptIdError, type KbLink, type KbLinkEdge, type KbLinkRel, type KbLinkRelSpec, type KbLoadResult, type KbLogEntry, type KbLogReadResult, type KbLogger, type KbMatch, type KbMatchRecord, type KbMergedPin, type KbMergedPins, KbMissingFlagValueError, type KbNeighbour, KbPackBudgetExceededError, type KbPackOptions, type KbPackResult, type KbPackedRecord, type KbPin, type KbPinLayer, type KbPinOptions, type KbPinResult, type KbPinStatus, KbPinsMalformedError, type KbPinsManifest, type KbPromoteCandidate, KbPromoteCollisionError, type KbPromoteResult, KbPromoteSelfError, KbPromoteStandingError, KbPromoteStoppedError, type KbPromotedRecord, type KbReassessAnchor, type KbReassessDefault, type KbReassessDiff, type KbReassessPacket, type KbRecord, KbRecordAlreadyExistsError, type KbRecordFrontmatter, KbRecordNotFoundError, type KbRecordStatus, type KbRecordType, type KbRecordTypeSpec, type KbSearchLogger, KbSelfVerificationError, type KbSource, type KbStanding, KbStore, type KbSupersededStub, type KbSyncResult, type KbTagFilter, type KbTraceEdge, type KbTraceOptions, type KbTraceStep, KbUnknownLinkRelError, type KbValidationProblem, type KbValidationSeverity, type KbVerdict, type KbVerifiedEvent, type KbWarning, KbWriteConflictError, type KbWriteInput, LINK_RELS, LOG_FILE, type MatchOptions, NO_DECISION_SLUG, PINS_FILE, PINS_LOCAL_FILE, PIN_LAYERS, PROMOTION_SOURCE_ID, type QmdModule, RECORD_TYPES, type RemoteAnchorState, type RemoteOptions, type RemoteRead, type ResolvedSymbol, type ResolverAttempt, type ResolverAttemptOptions, SEARCH_INDEX_FILE, type SearchHit, type SearchOptions, type SymbolRange, type SymbolRangeIndex, TRACE_EDGES, TreeSitterResolver, adjudicate, anchorFilePath, anchorOnHunk, assertBaseNotFrozen, backlinks, buildContext, carry, catalog, classifyDiff, classifyDrift, composeDecisionRecord, composeInputSchema, composeLinkSchema, composeNoDecisionRecord, composeRecord, contextProfileBudgets, createKbMcpServer, decisionInputSchema, defaultAnchorResolvers, detectAnchorDrift, doctor, edgeNeighbours, ensureGrammar, grammarHints, grammarManifest, grammarsCacheRoot, hashAnchorText, impact, inboundIndex, indexIsStale, isCanonicalRepoUrl, isKbLinkRel, isKbRecordType, isNoDecisionRecord, isReviewTag, kbActorStampSchema, kbAnchorSchema, kbAnchorSpanSchema, kbAnchorWriteSchema, kbConceptIdSchema, kbJsonSchemas, kbLinkSchema, kbLogEntrySchema, kbRecordFrontmatterSchema, kbSourceSchema, kbVerifiedEventSchema, languageForFile, listPins, loadQmd, matchToDiff, matchesTags, mergedContextBudgets, neighbours, pack, parseLog, parseMarkdownWithFrontmatter, pinBase, prepareResolvers, promoteCandidates, promoteInputSchema, readMergedPins, readPinsLayer, readRemoteAnchors, reassessPacket, regexResolver, renderCatalogLine, renderIndex, renderIndexLine, renderLogEntry, repoCacheDir, resolveAnchor, resolveAnchorSpan, resolveHeads, resolveHits, resolvePinPath, runKbCli, runKbMcpServer, searchBase, selectDecisions, splitMarkdownFrontmatter, stringifyMarkdownWithFrontmatter, symbolRangeIndex, syncInstructions, toHookJson, trace, treeSitterLanguages, unifiedDiff, unpinBase, validateBundle };
|