@saasontools/strauss-kb 0.1.19 → 0.1.21

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/index.d.ts CHANGED
@@ -62,9 +62,58 @@ 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
+ }>>;
84
+ repo: z.ZodOptional<z.ZodString>;
85
+ ref: z.ZodOptional<z.ZodString>;
86
+ hash: z.ZodOptional<z.ZodString>;
87
+ hash_kind: z.ZodOptional<z.ZodEnum<{
88
+ raw: "raw";
89
+ ast: "ast";
90
+ }>>;
91
+ resolved_at: z.ZodOptional<z.ZodString>;
92
+ lines: z.ZodOptional<z.ZodNumber>;
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
+ }>>;
68
117
  repo: z.ZodOptional<z.ZodString>;
69
118
  ref: z.ZodOptional<z.ZodString>;
70
119
  hash: z.ZodOptional<z.ZodString>;
@@ -75,6 +124,7 @@ declare const kbAnchorSchema: z.ZodObject<{
75
124
  resolved_at: z.ZodOptional<z.ZodString>;
76
125
  lines: z.ZodOptional<z.ZodNumber>;
77
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") both pass the symbol down the chain;
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) and the anchor records the resolver that answered.
522
- * `symbol-ambiguous` and `resolver-unavailable` end the chain: one would be
523
- * settled by guessing, the other would trade a precise span for a guessed one.
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. */
@@ -968,6 +1068,8 @@ type KbLogReadResult = {
968
1068
  line: number;
969
1069
  text: string;
970
1070
  }[];
1071
+ /** Whether the file still carried merge conflict markers. */
1072
+ conflicted: boolean;
971
1073
  };
972
1074
  declare function parseLog(raw: string): KbLogReadResult;
973
1075
 
@@ -1054,6 +1156,13 @@ type KbWriteInput = {
1054
1156
  /** Replace an existing record rather than failing on the collision. */
1055
1157
  overwrite?: boolean;
1056
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";
1057
1166
  type KbWriteResult = KbRecord & {
1058
1167
  /** Whether this write also marked prior records superseded. */
1059
1168
  action: "created" | "superseded-prior";
@@ -1116,6 +1225,9 @@ declare class KbStore {
1116
1225
  * Wholesale rather than merged: the caller just resolved the anchors it is
1117
1226
  * writing, so it holds the complete current set, and a merge would keep
1118
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.
1119
1231
  */
1120
1232
  updateAnchors(bundlePath: string, conceptId: string, anchors: KbAnchor[], actor?: string): Promise<KbRecord>;
1121
1233
  /**
@@ -1140,6 +1252,15 @@ declare class KbStore {
1140
1252
  supersede(bundlePath: string, conceptId: string, replacementId: string, actor?: string): Promise<KbRecord>;
1141
1253
  /** Resolves an open question, stamping who answered and when. */
1142
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>;
1143
1264
  /**
1144
1265
  * Records matching a text query, each carrying its standing.
1145
1266
  *
@@ -1254,14 +1375,29 @@ declare class KbStore {
1254
1375
  * and the next reader through here settles it.
1255
1376
  */
1256
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>;
1257
1386
  /**
1258
1387
  * The log, with unparseable lines reported rather than repaired.
1259
1388
  *
1260
1389
  * The log is the bundle's only artifact that cannot be reconstructed — the
1261
1390
  * records rebuild the index, and the code outlives both, but nothing else
1262
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.
1263
1393
  */
1264
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>;
1265
1401
  /**
1266
1402
  * `markSuperseded`, tolerant of the two ways it legitimately doesn't land:
1267
1403
  * a missing target (a broken link, legal per compose.ts) or a CAS conflict
@@ -1296,7 +1432,8 @@ declare class KbStore {
1296
1432
  /**
1297
1433
  * Declares union merge for the log, so two worktrees writing the same
1298
1434
  * bundle interleave their `log.jsonl` lines on merge rather than one
1299
- * 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.
1300
1437
  *
1301
1438
  * Called from `record` — every path that appends a log line, not just
1302
1439
  * `write` — so a bundle only ever mutated through `setStatus`/`verify`/
@@ -1309,10 +1446,9 @@ declare class KbStore {
1309
1446
  * race and created the file between the `readFile` below and this call,
1310
1447
  * `wx` fails instead of truncating what that writer just wrote, and the
1311
1448
  * failure is swallowed by the catch below same as any other best-effort
1312
- * miss. A file that exists but declares no merge strategy for the log
1313
- * gets the line appended, never a wholesale rewrite; one that already
1314
- * declares any merge strategy — this one or a user's own — is left alone
1315
- * 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`).
1316
1452
  *
1317
1453
  * `readFile` failing is `existing === null` only for `ENOENT` — genuinely
1318
1454
  * missing. Any other error (a permission problem, a transient `EMFILE`,
@@ -1323,12 +1459,12 @@ declare class KbStore {
1323
1459
  * therefore left untouched and reported as a failure like any other.
1324
1460
  *
1325
1461
  * Two processes racing the append branch — both read a file without the
1326
- * line, both append it — is possible and left unguarded: `appendFile` is
1327
- * `O_APPEND`, so the result is two copies of the same line rather than a
1328
- * torn write, and `hasMergeDeclaration` sees a duplicate declaration as
1329
- * "already declared" on the next call. A cheap-to-detect, harmless-to-
1330
- * leave residue, not a reason to add a cross-process lock (see
1331
- * `ARCHITECTURE.md`'s rejection of one for the same trade on records).
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).
1332
1468
  *
1333
1469
  * Best-effort, like the log append it precedes: failing to write this
1334
1470
  * file must not fail the mutation it guards.
@@ -1364,9 +1500,17 @@ declare enum Fault {
1364
1500
  /** Machine-readable discriminant, stable across message rewording. */
1365
1501
  declare enum ErrorTypes {
1366
1502
  KbRecordAlreadyExists = "KbRecordAlreadyExists",
1503
+ KbClassifyInput = "KbClassifyInput",
1504
+ KbFlagConflict = "KbFlagConflict",
1505
+ KbInvalidActor = "KbInvalidActor",
1367
1506
  KbInvalidConceptId = "KbInvalidConceptId",
1507
+ KbMatchInput = "KbMatchInput",
1368
1508
  KbMissingFlagValue = "KbMissingFlagValue",
1369
1509
  KbPackBudgetExceeded = "KbPackBudgetExceeded",
1510
+ KbPromoteCollision = "KbPromoteCollision",
1511
+ KbPromoteSelf = "KbPromoteSelf",
1512
+ KbPromoteStanding = "KbPromoteStanding",
1513
+ KbPromoteStopped = "KbPromoteStopped",
1370
1514
  KbRecordNotFound = "KbRecordNotFound",
1371
1515
  KbSelfVerification = "KbSelfVerification",
1372
1516
  KbStampBaselineUnreadable = "KbStampBaselineUnreadable",
@@ -1460,6 +1604,35 @@ declare class KbMissingFlagValueError extends BaseError {
1460
1604
  readonly flag: string;
1461
1605
  constructor(flag: string);
1462
1606
  }
1607
+ /** `classify` invoked with no diff it could read, or one it could not parse. */
1608
+ declare class KbClassifyInputError extends BaseError {
1609
+ readonly reason: string;
1610
+ constructor(reason: string);
1611
+ }
1612
+ /** The target base already holds one of the records. Refused for the whole run. */
1613
+ declare class KbPromoteCollisionError extends BaseError {
1614
+ readonly conceptId: string;
1615
+ readonly to: string;
1616
+ constructor(conceptId: string, to: string);
1617
+ }
1618
+ /** Promotion carries a record's standing, so a withdrawn one may not be copied. */
1619
+ declare class KbPromoteStandingError extends BaseError {
1620
+ readonly conceptId: string;
1621
+ readonly standing: string;
1622
+ constructor(conceptId: string, standing: string);
1623
+ }
1624
+ /** Source and target are the same base: the run would rewrite its own records. */
1625
+ declare class KbPromoteSelfError extends BaseError {
1626
+ readonly to: string;
1627
+ constructor(to: string);
1628
+ }
1629
+ /** A write failed after earlier ones landed; `landed` is what the target now holds. */
1630
+ declare class KbPromoteStoppedError extends BaseError {
1631
+ readonly conceptId: string;
1632
+ readonly landed: string[];
1633
+ readonly reason: string;
1634
+ constructor(conceptId: string, landed: string[], reason: string);
1635
+ }
1463
1636
  declare class KbInvalidConceptIdError extends BaseError {
1464
1637
  constructor(message: string, details: Record<string, string>);
1465
1638
  }
@@ -1635,6 +1808,14 @@ declare const composeInputSchema: z.ZodObject<{
1635
1808
  anchors: z.ZodOptional<z.ZodArray<z.ZodObject<{
1636
1809
  file: z.ZodString;
1637
1810
  symbol: z.ZodOptional<z.ZodString>;
1811
+ span: z.ZodOptional<z.ZodObject<{
1812
+ start: z.ZodNumber;
1813
+ end: z.ZodNumber;
1814
+ }, z.core.$strict>>;
1815
+ side: z.ZodOptional<z.ZodEnum<{
1816
+ old: "old";
1817
+ new: "new";
1818
+ }>>;
1638
1819
  repo: z.ZodOptional<z.ZodString>;
1639
1820
  ref: z.ZodOptional<z.ZodString>;
1640
1821
  hash: z.ZodOptional<z.ZodString>;
@@ -1645,6 +1826,7 @@ declare const composeInputSchema: z.ZodObject<{
1645
1826
  resolved_at: z.ZodOptional<z.ZodString>;
1646
1827
  lines: z.ZodOptional<z.ZodNumber>;
1647
1828
  resolver: z.ZodOptional<z.ZodEnum<{
1829
+ span: "span";
1648
1830
  "tree-sitter": "tree-sitter";
1649
1831
  regex: "regex";
1650
1832
  }>>;
@@ -2021,14 +2203,28 @@ declare function kbJsonSchemas(): Record<string, unknown>;
2021
2203
  * those, not the base.
2022
2204
  */
2023
2205
  type DiffHunk = {
2024
- /** 1-based, inclusive, in the file's post-change line numbering. */
2206
+ /** 1-based, inclusive, in the numbering of this hunk's `side`. */
2025
2207
  startLine: number;
2026
2208
  endLine: number;
2209
+ /**
2210
+ * Which half of the change these lines number; absent means `new`. An
2211
+ * old-side anchor lands here on the caller's word that its `ref` is this
2212
+ * diff's base rev — nothing compares the two.
2213
+ */
2214
+ side?: "old" | "new";
2215
+ /**
2216
+ * This hunk's own changed lines, markers stripped, where a parser kept them.
2217
+ * Nothing here reads them; a caller classifying content does.
2218
+ */
2219
+ lines?: string[];
2027
2220
  };
2028
2221
  type DiffFile = {
2029
2222
  /** Repo-relative, matching how anchors are written. */
2030
2223
  filePath: string;
2031
2224
  hunks: DiffHunk[];
2225
+ /** Where `git diff -M` says this path came from, and how alike the two are. */
2226
+ renamedFrom?: string;
2227
+ similarity?: number;
2032
2228
  };
2033
2229
  /**
2034
2230
  * A symbol resolved to lines. Supplied by whatever the caller uses to index
@@ -2039,6 +2235,8 @@ type SymbolRange = {
2039
2235
  symbol: string;
2040
2236
  startLine: number;
2041
2237
  endLine: number;
2238
+ /** Which side these lines number; absent means `new`, as on a hunk. */
2239
+ side?: "old" | "new";
2042
2240
  };
2043
2241
  type DiffMatch = {
2044
2242
  filePath: string;
@@ -2059,6 +2257,157 @@ type MatchOptions = {
2059
2257
  now?: Date;
2060
2258
  };
2061
2259
  declare function matchToDiff(files: DiffFile[], records: KbRecord[], options?: MatchOptions): DiffMatch[];
2260
+ /** The anchor alone, for a caller that already knows the hunk matched. */
2261
+ declare function anchorOnHunk(record: KbRecord, filePath: string, hunk: DiffHunk, symbolRanges?: readonly SymbolRange[] | SymbolRangeIndex): KbAnchor | undefined;
2262
+ /** Built once by a caller placing many records on many hunks of one diff. */
2263
+ type SymbolRangeIndex = ReadonlyMap<string, SymbolRange[]>;
2264
+ declare function symbolRangeIndex(ranges: readonly SymbolRange[]): SymbolRangeIndex;
2265
+
2266
+ /**
2267
+ * Every operation a knowledge base exposes, defined once.
2268
+ *
2269
+ * The CLI and the MCP server are both projections of this table. Kept apart
2270
+ * they drift within a day — fourteen commands against six tools — which is the
2271
+ * same failure as a schema restated in prose beside the code that enforces it,
2272
+ * one level up. A command added to the table appears in both surfaces or in
2273
+ * neither, and a test asserts exactly that.
2274
+ *
2275
+ * The two differ only in how arguments arrive: MCP passes an object matching
2276
+ * `input`, while the CLI has to turn positional argv into the same object.
2277
+ * `fromArgv` is that adapter and is the only per-surface code a command needs.
2278
+ *
2279
+ * One file per command in this folder; `index.ts` assembles the table.
2280
+ */
2281
+ type KbCommandContext = {
2282
+ store: KbStore;
2283
+ actor: string;
2284
+ now: () => string;
2285
+ };
2286
+ type KbCommand<Shape extends z.ZodRawShape = z.ZodRawShape> = {
2287
+ /** CLI verb. */
2288
+ name: string;
2289
+ /**
2290
+ * MCP tool name. Absent only for CLI-only plumbing (`sync-instructions`),
2291
+ * which exists to edit files for hooks and instruction blocks rather than to
2292
+ * give an agent a capability — the capability, "get the pinned context
2293
+ * block", is `kb_context`.
2294
+ */
2295
+ tool?: string;
2296
+ /** Argument spelling for CLI usage output. */
2297
+ usage: string;
2298
+ /** Shown to an agent choosing a tool, so it carries the judgment too. */
2299
+ description: string;
2300
+ input: z.ZodObject<Shape>;
2301
+ /**
2302
+ * Positional argv → the same object MCP receives. `bundleExplicit` says
2303
+ * whether `--bundle` was actually passed, for the one command whose meaning
2304
+ * turns on it: `stamp` with no bundle stamps every pinned base.
2305
+ */
2306
+ fromArgv(argv: string[], bundlePath: string, stdin: () => Promise<string>, bundleExplicit?: boolean): Promise<unknown> | unknown;
2307
+ run(ctx: KbCommandContext, input: z.infer<z.ZodObject<Shape>>): Promise<unknown>;
2308
+ /**
2309
+ * A human-readable form of the result, for the CLI. Where it exists the CLI
2310
+ * prints it and `--json` asks for the machine shape instead; MCP always gets
2311
+ * the machine shape, since a tool result is parsed rather than read.
2312
+ *
2313
+ * Separate from `run` rather than rendered inside it — as `pack` does, whose
2314
+ * result *is* a document — because a command whose result is a report needs
2315
+ * both forms: the table for a person, and the object for `failsWhen` and for
2316
+ * anything downstream.
2317
+ */
2318
+ render?(result: unknown): string;
2319
+ /**
2320
+ * Turns a result into a non-zero exit for the CLI. A check that reports a
2321
+ * problem has succeeded as a command and failed as a check, and a shell
2322
+ * caller can only see the difference through the exit code.
2323
+ *
2324
+ * The input comes too, so a command can make the exit conditional on a flag
2325
+ * the caller passed rather than on the result alone.
2326
+ */
2327
+ failsWhen?(result: unknown, input: z.infer<z.ZodObject<Shape>>): boolean;
2328
+ };
2329
+
2330
+ /** One record on a hunk: enough to decide whether to read it, and no body. */
2331
+ type KbMatchRecord = {
2332
+ conceptId: string;
2333
+ type: string;
2334
+ title: string | null;
2335
+ /** Carried on every entry, so a hit is never handed over as a bare match. */
2336
+ standing: KbStanding;
2337
+ status: KbRecordStatus;
2338
+ /** Where the supersession chain ends. Empty while the record still holds. */
2339
+ supersededBy: string[];
2340
+ materiality?: KbRecordFrontmatter["strauss_materiality"];
2341
+ confidence?: KbRecordFrontmatter["strauss_confidence"];
2342
+ tags?: string[];
2343
+ /** The anchor that put this record on this hunk. */
2344
+ anchor?: KbAnchor;
2345
+ };
2346
+ type KbMatch = {
2347
+ filePath: string;
2348
+ hunk: DiffHunk;
2349
+ /** `symbol` when every record here was placed by a resolved symbol range. */
2350
+ precision: "symbol" | "file";
2351
+ records: KbMatchRecord[];
2352
+ };
2353
+
2354
+ /**
2355
+ * What a reviewer can skim and what they must read, derived from the diff.
2356
+ *
2357
+ * A closed set: a consumer branches on these nine, and a tenth would arrive
2358
+ * unhandled. `source` is the residue — everything no rule claimed.
2359
+ */
2360
+ declare const KB_CLASSES: readonly ["test", "config", "ci", "docs", "lockfile", "generated", "boilerplate", "rename", "source"];
2361
+ type KbClass = (typeof KB_CLASSES)[number];
2362
+ /** A diff file, plus the head lines a caller could read for it. */
2363
+ type KbClassifyFile = DiffFile & {
2364
+ /** The file's first lines at head. Absent falls back to the diff's own. */
2365
+ header?: string[];
2366
+ };
2367
+ type KbClassifyThresholds = {
2368
+ /** Share of a file's changed lines that must match a boilerplate shape. */
2369
+ boilerplate?: number;
2370
+ /** The `git diff -M` similarity a rename needs before it is called one. */
2371
+ rename?: number;
2372
+ };
2373
+ declare const DEFAULT_THRESHOLDS: Required<KbClassifyThresholds>;
2374
+ type KbClassifyOptions = {
2375
+ /** The base, for the `review:*` overrides. Adjudicated: only current wins. */
2376
+ records?: KbRecord[];
2377
+ /** Without these a symbol anchor covers its whole file rather than a hunk. */
2378
+ symbolRanges?: readonly SymbolRange[];
2379
+ now?: Date;
2380
+ thresholds?: KbClassifyThresholds;
2381
+ };
2382
+ /** The class and the name of the rule that produced it. */
2383
+ type KbVerdict = {
2384
+ class: KbClass;
2385
+ reason: string;
2386
+ };
2387
+ type KbClassifiedHunk = KbVerdict & {
2388
+ startLine: number;
2389
+ endLine: number;
2390
+ };
2391
+ type KbClassifiedFile = KbVerdict & {
2392
+ filePath: string;
2393
+ renamedFrom?: string;
2394
+ /** Present only where some hunk's class differs from the file's. */
2395
+ hunks?: KbClassifiedHunk[];
2396
+ };
2397
+ type KbClassifyResult = {
2398
+ files: KbClassifiedFile[];
2399
+ };
2400
+
2401
+ /**
2402
+ * What kind of change each file carries.
2403
+ *
2404
+ * Every input is in the diff, so nothing here is written down: a class the KB
2405
+ * stored would be a second copy of an answer the patch already gives, and the
2406
+ * two would disagree the first time a rule changed. The one thing a script
2407
+ * cannot derive — "this output is generated, read its input instead" — is a
2408
+ * record, and it wins over the heuristic.
2409
+ */
2410
+ declare function classifyDiff(files: readonly KbClassifyFile[], options?: KbClassifyOptions): KbClassifiedFile[];
2062
2411
 
2063
2412
  /**
2064
2413
  * The edges between records in one bundle, defined once.
@@ -2196,6 +2545,14 @@ type KbAnchorResolverCounts = {
2196
2545
  treeSitter: number;
2197
2546
  /** Includes anchors stamped before resolvers were named. */
2198
2547
  regex: number;
2548
+ /** Author-given line ranges, hashed exactly as written. */
2549
+ span: number;
2550
+ /**
2551
+ * Hashed anchors read at their `ref` rather than the working tree. Counted
2552
+ * beside the resolver buckets and outside `total`: `side` is not a resolver,
2553
+ * and one of these may name a whole file.
2554
+ */
2555
+ oldSide: number;
2199
2556
  };
2200
2557
  type KbDoctorOptions = {
2201
2558
  /** How far ahead `expiring` looks. */
@@ -2259,6 +2616,14 @@ declare const decisionInputSchema: z.ZodObject<{
2259
2616
  anchors: z.ZodOptional<z.ZodArray<z.ZodObject<{
2260
2617
  file: z.ZodString;
2261
2618
  symbol: z.ZodOptional<z.ZodString>;
2619
+ span: z.ZodOptional<z.ZodObject<{
2620
+ start: z.ZodNumber;
2621
+ end: z.ZodNumber;
2622
+ }, z.core.$strict>>;
2623
+ side: z.ZodOptional<z.ZodEnum<{
2624
+ old: "old";
2625
+ new: "new";
2626
+ }>>;
2262
2627
  repo: z.ZodOptional<z.ZodString>;
2263
2628
  ref: z.ZodOptional<z.ZodString>;
2264
2629
  hash: z.ZodOptional<z.ZodString>;
@@ -2269,6 +2634,7 @@ declare const decisionInputSchema: z.ZodObject<{
2269
2634
  resolved_at: z.ZodOptional<z.ZodString>;
2270
2635
  lines: z.ZodOptional<z.ZodNumber>;
2271
2636
  resolver: z.ZodOptional<z.ZodEnum<{
2637
+ span: "span";
2272
2638
  "tree-sitter": "tree-sitter";
2273
2639
  regex: "regex";
2274
2640
  }>>;
@@ -2318,90 +2684,100 @@ declare function isNoDecisionRecord(record: KbRecord): boolean;
2318
2684
  declare function selectDecisions(records: KbRecord[]): KbRecord[];
2319
2685
 
2320
2686
  /**
2321
- * Every operation a knowledge base exposes, defined once.
2322
- *
2323
- * The CLI and the MCP server are both projections of this table. Kept apart
2324
- * they drift within a day — fourteen commands against six tools — which is the
2325
- * same failure as a schema restated in prose beside the code that enforces it,
2326
- * one level up. A command added to the table appears in both surfaces or in
2327
- * neither, and a test asserts exactly that.
2328
- *
2329
- * The two differ only in how arguments arrive: MCP passes an object matching
2330
- * `input`, while the CLI has to turn positional argv into the same object.
2331
- * `fromArgv` is that adapter and is the only per-surface code a command needs.
2687
+ * The command table, assembled from one file per command.
2332
2688
  *
2333
- * One file per command in this folder; `index.ts` assembles the table.
2689
+ * Order is the CLI usage listing's order: the write path, the read path,
2690
+ * base housekeeping, the format, and the workspace pin verbs.
2334
2691
  */
2335
- type KbCommandContext = {
2336
- store: KbStore;
2337
- actor: string;
2338
- now: () => string;
2692
+
2693
+ declare const KB_COMMANDS: KbCommand[];
2694
+ declare const KB_COMMANDS_BY_NAME: Map<string, KbCommand>;
2695
+
2696
+ /**
2697
+ * Listing candidates and promoting share one input, and the two need different
2698
+ * arguments. The rule lives here rather than in `run` so both surfaces refuse
2699
+ * the same call: the CLI before it dispatches, MCP before the tool runs.
2700
+ */
2701
+ declare const promoteInputSchema: z.ZodObject<{
2702
+ bundlePath: z.ZodString;
2703
+ conceptIds: z.ZodOptional<z.ZodArray<z.ZodString>>;
2704
+ to: z.ZodOptional<z.ZodString>;
2705
+ source: z.ZodOptional<z.ZodString>;
2706
+ force: z.ZodOptional<z.ZodBoolean>;
2707
+ list: z.ZodOptional<z.ZodBoolean>;
2708
+ }, z.core.$strip>;
2709
+ /** A typed link the copy does not carry, because its target stayed behind. */
2710
+ type KbDroppedLink = {
2711
+ target: string;
2712
+ rel: string;
2339
2713
  };
2340
- type KbCommand<Shape extends z.ZodRawShape = z.ZodRawShape> = {
2341
- /** CLI verb. */
2342
- name: string;
2343
- /**
2344
- * MCP tool name. Absent only for CLI-only plumbing (`sync-instructions`),
2345
- * which exists to edit files for hooks and instruction blocks rather than to
2346
- * give an agent a capability — the capability, "get the pinned context
2347
- * block", is `kb_context`.
2348
- */
2349
- tool?: string;
2350
- /** Argument spelling for CLI usage output. */
2351
- usage: string;
2352
- /** Shown to an agent choosing a tool, so it carries the judgment too. */
2353
- description: string;
2354
- input: z.ZodObject<Shape>;
2355
- /**
2356
- * Positional argv → the same object MCP receives. `bundleExplicit` says
2357
- * whether `--bundle` was actually passed, for the one command whose meaning
2358
- * turns on it: `stamp` with no bundle stamps every pinned base.
2359
- */
2360
- fromArgv(argv: string[], bundlePath: string, stdin: () => Promise<string>, bundleExplicit?: boolean): Promise<unknown> | unknown;
2361
- run(ctx: KbCommandContext, input: z.infer<z.ZodObject<Shape>>): Promise<unknown>;
2362
- /**
2363
- * A human-readable form of the result, for the CLI. Where it exists the CLI
2364
- * prints it and `--json` asks for the machine shape instead; MCP always gets
2365
- * the machine shape, since a tool result is parsed rather than read.
2366
- *
2367
- * Separate from `run` rather than rendered inside it — as `pack` does, whose
2368
- * result *is* a document — because a command whose result is a report needs
2369
- * both forms: the table for a person, and the object for `failsWhen` and for
2370
- * anything downstream.
2371
- */
2372
- render?(result: unknown): string;
2373
- /**
2374
- * Turns a result into a non-zero exit for the CLI. A check that reports a
2375
- * problem has succeeded as a command and failed as a check, and a shell
2376
- * caller can only see the difference through the exit code.
2377
- *
2378
- * The input comes too, so a command can make the exit conditional on a flag
2379
- * the caller passed rather than on the result alone.
2380
- */
2381
- failsWhen?(result: unknown, input: z.infer<z.ZodObject<Shape>>): boolean;
2714
+ type KbPromotedRecord = {
2715
+ conceptId: string;
2716
+ droppedLinks: KbDroppedLink[];
2717
+ };
2718
+ type KbPromoteCandidate = {
2719
+ conceptId: string;
2720
+ type: string;
2721
+ title: string | null;
2722
+ /** The rule that made it a candidate, in the reader's terms. */
2723
+ why: string;
2724
+ };
2725
+ type KbPromoteResult = {
2726
+ mode: "list";
2727
+ candidates: KbPromoteCandidate[];
2728
+ } | {
2729
+ mode: "promote";
2730
+ to: string;
2731
+ promoted: KbPromotedRecord[];
2382
2732
  };
2383
2733
 
2734
+ /** The source entry a promotion adds, replaced rather than repeated on re-promote. */
2735
+ declare const PROMOTION_SOURCE_ID = "promoted";
2736
+ type KbCarriedRecord = {
2737
+ frontmatter: Omit<KbRecordFrontmatter, "type">;
2738
+ body: string;
2739
+ droppedLinks: KbDroppedLink[];
2740
+ };
2384
2741
  /**
2385
- * The command table, assembled from one file per command.
2742
+ * One record as the target base should hold it.
2386
2743
  *
2387
- * Order is the CLI usage listing's order: the write path, the read path,
2388
- * base housekeeping, the format, and the workspace pin verbs.
2744
+ * Frontmatter is carried rather than recomposed: OKF requires a consumer to
2745
+ * preserve keys it does not recognise when round-tripping, and a record written
2746
+ * by another producer would lose them to a rebuild from known fields.
2747
+ */
2748
+ declare function carry(record: KbRecord, promoted: ReadonlySet<string>, source?: string): KbCarriedRecord;
2749
+ /**
2750
+ * `review` and the `review:<id>` family alike: the target base is not a review
2751
+ * base, so a tag saying which review wrote the record no longer selects
2752
+ * anything there.
2389
2753
  */
2754
+ declare function isReviewTag(tag: string): boolean;
2390
2755
 
2391
- declare const KB_COMMANDS: KbCommand[];
2392
- declare const KB_COMMANDS_BY_NAME: Map<string, KbCommand>;
2756
+ /**
2757
+ * What in a review base is worth keeping once the change merges. Heuristics over
2758
+ * what a reviewer usually wants; a record they cut is still nameable by hand.
2759
+ * A withdrawn record is not among them — `promote` refuses those outright.
2760
+ */
2761
+ declare function promoteCandidates(bundle: KbRecord[]): KbPromoteCandidate[];
2393
2762
 
2394
- /** Where a recovered file came from, so a packet can say how far back it looked. */
2395
- type OldSourceOrigin =
2396
- /** `git show <anchor.ref>:<file>` the rev the record itself named. */
2397
- {
2398
- kind: "ref";
2399
- ref: string;
2400
- }
2401
- /** The last commit touching the path before `resolved_at`. */
2402
- | {
2403
- kind: "history";
2404
- ref: string;
2763
+ type KbExportedDecision = {
2764
+ conceptId: string;
2765
+ /** File name within the target directory, `NNNN-<slug>.md`. */
2766
+ file: string;
2767
+ /** The ADR's Status line, as adjudication settled it. */
2768
+ status: string;
2769
+ };
2770
+ /** A file this exporter did not write, holding the name a decision needs. */
2771
+ type KbExportForeignFile = {
2772
+ conceptId: string;
2773
+ file: string;
2774
+ };
2775
+ type KbExportResult = {
2776
+ to: string;
2777
+ format: "madr";
2778
+ exported: KbExportedDecision[];
2779
+ /** Decisions left unwritten because a foreign file already holds their name. */
2780
+ foreign: KbExportForeignFile[];
2405
2781
  };
2406
2782
 
2407
2783
  type MovedSearch = {
@@ -2706,4 +3082,4 @@ declare function parseMarkdownWithFrontmatter<S extends z.ZodType>(text: string,
2706
3082
  frontmatter: ReturnType<S["safeParse"]>;
2707
3083
  };
2708
3084
 
2709
- 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 KbTagFilter, 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, matchesTags, 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 };
3085
+ 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 };