@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/dist/index.d.ts 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") 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. */
@@ -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): Promise<KbRecord[]>;
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 but declares no merge strategy for the log
1290
- * gets the line appended, never a wholesale rewrite; one that already
1291
- * declares any merge strategy — this one or a user's own — is left alone
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
- * line, both append it — is possible and left unguarded: `appendFile` is
1304
- * `O_APPEND`, so the result is two copies of the same line rather than a
1305
- * torn write, and `hasMergeDeclaration` sees a duplicate declaration as
1306
- * "already declared" on the next call. A cheap-to-detect, harmless-to-
1307
- * leave residue, not a reason to add a cross-process lock (see
1308
- * `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).
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 file's post-change line numbering. */
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
- * Every operation a knowledge base exposes, defined once.
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
- * One file per command in this folder; `index.ts` assembles the table.
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
- type KbCommandContext = {
2301
- store: KbStore;
2302
- actor: string;
2303
- now: () => string;
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 KbCommand<Shape extends z.ZodRawShape = z.ZodRawShape> = {
2306
- /** CLI verb. */
2307
- name: string;
2308
- /**
2309
- * MCP tool name. Absent only for CLI-only plumbing (`sync-instructions`),
2310
- * which exists to edit files for hooks and instruction blocks rather than to
2311
- * give an agent a capability — the capability, "get the pinned context
2312
- * block", is `kb_context`.
2313
- */
2314
- tool?: string;
2315
- /** Argument spelling for CLI usage output. */
2316
- usage: string;
2317
- /** Shown to an agent choosing a tool, so it carries the judgment too. */
2318
- description: string;
2319
- input: z.ZodObject<Shape>;
2320
- /**
2321
- * Positional argv → the same object MCP receives. `bundleExplicit` says
2322
- * whether `--bundle` was actually passed, for the one command whose meaning
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
- * The command table, assembled from one file per command.
2740
+ * One record as the target base should hold it.
2351
2741
  *
2352
- * Order is the CLI usage listing's order: the write path, the read path,
2353
- * base housekeeping, the format, and the workspace pin verbs.
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
- declare const KB_COMMANDS: KbCommand[];
2357
- declare const KB_COMMANDS_BY_NAME: Map<string, KbCommand>;
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
- /** Where a recovered file came from, so a packet can say how far back it looked. */
2360
- type OldSourceOrigin =
2361
- /** `git show <anchor.ref>:<file>` the rev the record itself named. */
2362
- {
2363
- kind: "ref";
2364
- ref: string;
2365
- }
2366
- /** The last commit touching the path before `resolved_at`. */
2367
- | {
2368
- kind: "history";
2369
- ref: string;
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 };