@saasontools/strauss-kb 0.1.9 → 0.1.10

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.cts CHANGED
@@ -311,6 +311,79 @@ type KbPackResult = {
311
311
  */
312
312
  declare function pack(bundle: KbRecord[], rootId: string, options?: KbPackOptions): KbPackResult;
313
313
 
314
+ /** One record as the catalog names it — no body, no description, one line. */
315
+ type KbCatalogEntry = {
316
+ conceptId: string;
317
+ type: string;
318
+ title: string | null;
319
+ standing: KbStanding;
320
+ /** Where the supersession chain ends. Empty when broken, cyclic, or n/a. */
321
+ supersededBy: string[];
322
+ /** `stale_after` is in the past. The one freshness signal a line can carry. */
323
+ stale: boolean;
324
+ };
325
+ type KbCatalogResult = {
326
+ entries: KbCatalogEntry[];
327
+ /** Every record the catalog names, filter applied. */
328
+ recordCount: number;
329
+ /**
330
+ * How many records hold each standing. Sums to `recordCount` — every record
331
+ * has exactly one standing, so the reader can see that nothing went missing.
332
+ */
333
+ standings: Record<KbStanding, number>;
334
+ /** Shorthand for `standings.current` — records that simply hold. */
335
+ currentCount: number;
336
+ /** Shorthand for `standings.superseded`. */
337
+ supersededCount: number;
338
+ /**
339
+ * Records whose `stale_after` has passed. A flag over the standings rather
340
+ * than one of them — a current record can be stale — so this deliberately
341
+ * does not participate in the sum.
342
+ */
343
+ staleCount: number;
344
+ };
345
+ /**
346
+ * The tier-one listing: every record named, nothing spelled out.
347
+ *
348
+ * `load` hands over bodies and `pack` hands over a neighbourhood; both have to
349
+ * decide what the reader can afford. The catalog is the rung below either — one
350
+ * line per record at roughly thirty tokens, so a base far past `load`'s gate
351
+ * still fits in a single call. What it buys is the ability to choose: a reader
352
+ * that can see every id, type, title and standing knows which record to `pack`
353
+ * and knows when no record covers the question at all, which is the conclusion
354
+ * a truncated read can never support.
355
+ *
356
+ * Standing travels on the line for the same reason it travels with every other
357
+ * result here: a title is a claim, and a superseded claim reads exactly like a
358
+ * live one. A superseded entry names its replacement, so the line the reader
359
+ * should follow instead is already in front of them.
360
+ *
361
+ * Unbounded, alone among the read paths. `load` and `pack` refuse past a
362
+ * ceiling because a partial body set reads as a complete one; a catalog has no
363
+ * such failure — it is the rung a caller lands on *because* something else
364
+ * refused, and a second refusal there would leave nowhere to go. The cost is
365
+ * linear and cheap: roughly thirty tokens a record, so a thousand-record base
366
+ * is about 30k and five thousand about 150k. Past that the `type` filter
367
+ * narrows it, and no ceiling is needed to make that available.
368
+ *
369
+ * Deterministic given a fixed `now`: no timestamp is emitted, and the ordering
370
+ * is total down to the concept id, so two catalogs of an unchanged base within
371
+ * one `stale_after` window are byte-identical and diff to nothing. The default
372
+ * clock is the wall clock, so a line can still flip to stale as a date passes —
373
+ * pass `now` when byte-equality has to hold across that boundary.
374
+ */
375
+ declare function catalog(bundle: KbRecord[], options?: {
376
+ type?: string;
377
+ now?: Date;
378
+ }): KbCatalogResult;
379
+ /**
380
+ * One entry, as one line.
381
+ *
382
+ * ` · `-separated rather than a table: a table pays for column alignment on
383
+ * every row, and nothing downstream parses these.
384
+ */
385
+ declare function renderCatalogLine(entry: KbCatalogEntry): string;
386
+
314
387
  declare const LOG_FILE = "log.jsonl";
315
388
  declare const kbLogEntrySchema: z.ZodObject<{
316
389
  at: z.ZodISODateTime;
@@ -391,6 +464,8 @@ type KbLoadResult = {
391
464
  recordCount: number;
392
465
  approxTokens: number;
393
466
  budgetTokens: number;
467
+ /** The refusal in words, naming the budget and what to call next. */
468
+ message: string;
394
469
  };
395
470
  type KbWriteInput = {
396
471
  type: string;
@@ -509,9 +584,16 @@ declare class KbStore {
509
584
  * is indistinguishable from a complete one, so a caller would answer "that
510
585
  * was never decided" from a slice it did not know was a slice.
511
586
  *
512
- * That refusal is the default guardrail. `all` bypasses it outright and
513
- * always hands back the whole bundle: an explicit, never-accidental escape
514
- * hatch for an operator who has the budget to spend, not a wider default.
587
+ * A token budget decides that, measured over what is actually handed back.
588
+ * The refusal names the estimate and the budget, because a caller told only
589
+ * "too big" cannot tell whether to narrow the type filter, raise the budget,
590
+ * or stop loading the base whole altogether. Past the budget the answer is
591
+ * the catalog and then a pack, which is what the refusal says.
592
+ *
593
+ * That refusal is the default guardrail. `all` bypasses the budget outright
594
+ * and always hands back the whole bundle: an explicit, never-accidental
595
+ * escape hatch for an operator who has the budget to spend, not a wider
596
+ * default.
515
597
  */
516
598
  load(bundlePath: string, options?: {
517
599
  budgetTokens?: number;
@@ -520,6 +602,11 @@ declare class KbStore {
520
602
  }): Promise<KbLoadResult>;
521
603
  /** How a position was arrived at, as a timeline. See `trace.ts`. */
522
604
  trace(bundlePath: string, seedId: string, options?: KbTraceOptions): Promise<KbTraceStep[]>;
605
+ /** Every record named in one line each. See `catalog.ts`. */
606
+ catalog(bundlePath: string, options?: {
607
+ type?: string;
608
+ now?: Date;
609
+ }): Promise<KbCatalogResult>;
523
610
  /** A bounded neighbourhood around one record. See `pack.ts`. */
524
611
  pack(bundlePath: string, rootId: string, options?: KbPackOptions): Promise<KbPackResult>;
525
612
  /**
@@ -641,6 +728,7 @@ declare enum Fault {
641
728
  declare enum ErrorTypes {
642
729
  KbRecordAlreadyExists = "KbRecordAlreadyExists",
643
730
  KbInvalidConceptId = "KbInvalidConceptId",
731
+ KbMissingFlagValue = "KbMissingFlagValue",
644
732
  KbPackBudgetExceeded = "KbPackBudgetExceeded",
645
733
  KbRecordNotFound = "KbRecordNotFound",
646
734
  KbSelfVerification = "KbSelfVerification",
@@ -707,6 +795,18 @@ declare class KbPackBudgetExceededError extends BaseError {
707
795
  readonly excluded: string[];
708
796
  constructor(recordCount: number, approxTokens: number, budgetTokens: number, excluded: string[]);
709
797
  }
798
+ /**
799
+ * A flag that takes a value, given none.
800
+ *
801
+ * `strauss-kb load --budget` used to read the next argv entry, find
802
+ * nothing, and quietly fall back to the default — so a caller who meant to
803
+ * raise a ceiling got the ceiling they were trying to move, and a typo looked
804
+ * exactly like success. Refusing is the only way that stays visible.
805
+ */
806
+ declare class KbMissingFlagValueError extends BaseError {
807
+ readonly flag: string;
808
+ constructor(flag: string);
809
+ }
710
810
  declare class KbInvalidConceptIdError extends BaseError {
711
811
  constructor(message: string, details: Record<string, string>);
712
812
  }
@@ -1511,4 +1611,4 @@ declare function parseMarkdownWithFrontmatter<S extends z.ZodType>(text: string,
1511
1611
  frontmatter: ReturnType<S["safeParse"]>;
1512
1612
  };
1513
1613
 
1514
- export { BaseError, CONTEXT_BEGIN, CONTEXT_END, CONTEXT_PROFILES, type ComposeInput, type ComposedRecord, DECISION_TYPE, DEFAULT_AGING_DAYS, DEFAULT_EXPIRING_DAYS, DEFAULT_LOAD_BUDGET, DEFAULT_PACK_HOPS, DEFAULT_PACK_MAX_NODES, DEFAULT_UNVERIFIED_DAYS, type DecisionInput, type DiffFile, type DiffHunk, type DiffMatch, type ErrorDetails, type ErrorProps, ErrorTypes, Fault, INDEX_FILE, KB_COMMANDS, KB_COMMANDS_BY_NAME, KB_CONCEPT_ID_PATTERN, KB_CONFIDENCES, KB_DIR, KB_DOCTOR_CHECKS, KB_EDGE_KINDS, KB_MATERIALITIES, KB_RECORD_STATUSES, KB_RECORD_TYPES, KB_SLUG_PATTERN, type KbActorStamp, type KbAdjudicated, type KbAnchor, KbBaseFrozenError, type KbCommand, type KbCommandContext, type KbContextBudgets, type KbContextOptions, type KbContextResult, type KbDoctorCheck, type KbDoctorFinding, type KbDoctorGroup, type KbDoctorOptions, type KbDoctorReport, type KbDoctorThresholds, type KbEdgeKind, KbInvalidConceptIdError, type KbLoadResult, type KbLogEntry, type KbLogReadResult, type KbLogger, type KbMergedPin, type KbMergedPins, type KbNeighbour, KbPackBudgetExceededError, type KbPackOptions, type KbPackResult, type KbPackedRecord, type KbPin, type KbPinLayer, type KbPinOptions, type KbPinResult, type KbPinStatus, KbPinsMalformedError, type KbPinsManifest, 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, type KbValidationProblem, type KbVerifiedEvent, type KbWarning, KbWriteConflictError, type KbWriteInput, LOG_FILE, type MatchOptions, NO_DECISION_SLUG, PINS_FILE, PINS_LOCAL_FILE, PIN_LAYERS, type QmdModule, RECORD_TYPES, SEARCH_INDEX_FILE, type SearchHit, type SearchOptions, type SymbolRange, TRACE_EDGES, adjudicate, assertBaseNotFrozen, buildContext, composeDecisionRecord, composeInputSchema, composeNoDecisionRecord, composeRecord, contextProfileBudgets, createKbMcpServer, decisionInputSchema, doctor, edgeNeighbours, indexIsStale, isKbRecordType, isNoDecisionRecord, kbActorStampSchema, kbAnchorSchema, kbConceptIdSchema, kbJsonSchemas, kbLogEntrySchema, kbRecordFrontmatterSchema, kbSourceSchema, kbVerifiedEventSchema, listPins, loadQmd, matchToDiff, mergedContextBudgets, neighbours, pack, parseLog, parseMarkdownWithFrontmatter, pinBase, readMergedPins, readPinsLayer, renderIndex, renderIndexLine, renderLogEntry, resolveHeads, resolveHits, resolvePinPath, runKbCli, runKbMcpServer, searchBase, selectDecisions, splitMarkdownFrontmatter, stringifyMarkdownWithFrontmatter, syncInstructions, toHookJson, trace, unpinBase, validateBundle };
1614
+ export { BaseError, CONTEXT_BEGIN, CONTEXT_END, CONTEXT_PROFILES, type ComposeInput, type ComposedRecord, DECISION_TYPE, DEFAULT_AGING_DAYS, DEFAULT_EXPIRING_DAYS, DEFAULT_LOAD_BUDGET, DEFAULT_PACK_HOPS, DEFAULT_PACK_MAX_NODES, DEFAULT_UNVERIFIED_DAYS, type DecisionInput, type DiffFile, type DiffHunk, type DiffMatch, type ErrorDetails, type ErrorProps, ErrorTypes, Fault, INDEX_FILE, KB_COMMANDS, KB_COMMANDS_BY_NAME, KB_CONCEPT_ID_PATTERN, KB_CONFIDENCES, KB_DIR, KB_DOCTOR_CHECKS, KB_EDGE_KINDS, KB_MATERIALITIES, KB_RECORD_STATUSES, KB_RECORD_TYPES, KB_SLUG_PATTERN, type KbActorStamp, type KbAdjudicated, type KbAnchor, 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, KbInvalidConceptIdError, 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 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, type KbValidationProblem, type KbVerifiedEvent, type KbWarning, KbWriteConflictError, type KbWriteInput, LOG_FILE, type MatchOptions, NO_DECISION_SLUG, PINS_FILE, PINS_LOCAL_FILE, PIN_LAYERS, type QmdModule, RECORD_TYPES, SEARCH_INDEX_FILE, type SearchHit, type SearchOptions, type SymbolRange, TRACE_EDGES, adjudicate, assertBaseNotFrozen, buildContext, catalog, composeDecisionRecord, composeInputSchema, composeNoDecisionRecord, composeRecord, contextProfileBudgets, createKbMcpServer, decisionInputSchema, doctor, edgeNeighbours, indexIsStale, isKbRecordType, isNoDecisionRecord, kbActorStampSchema, kbAnchorSchema, kbConceptIdSchema, kbJsonSchemas, kbLogEntrySchema, kbRecordFrontmatterSchema, kbSourceSchema, kbVerifiedEventSchema, listPins, loadQmd, matchToDiff, mergedContextBudgets, neighbours, pack, parseLog, parseMarkdownWithFrontmatter, pinBase, readMergedPins, readPinsLayer, renderCatalogLine, renderIndex, renderIndexLine, renderLogEntry, resolveHeads, resolveHits, resolvePinPath, runKbCli, runKbMcpServer, searchBase, selectDecisions, splitMarkdownFrontmatter, stringifyMarkdownWithFrontmatter, syncInstructions, toHookJson, trace, unpinBase, validateBundle };
package/dist/index.d.ts CHANGED
@@ -311,6 +311,79 @@ type KbPackResult = {
311
311
  */
312
312
  declare function pack(bundle: KbRecord[], rootId: string, options?: KbPackOptions): KbPackResult;
313
313
 
314
+ /** One record as the catalog names it — no body, no description, one line. */
315
+ type KbCatalogEntry = {
316
+ conceptId: string;
317
+ type: string;
318
+ title: string | null;
319
+ standing: KbStanding;
320
+ /** Where the supersession chain ends. Empty when broken, cyclic, or n/a. */
321
+ supersededBy: string[];
322
+ /** `stale_after` is in the past. The one freshness signal a line can carry. */
323
+ stale: boolean;
324
+ };
325
+ type KbCatalogResult = {
326
+ entries: KbCatalogEntry[];
327
+ /** Every record the catalog names, filter applied. */
328
+ recordCount: number;
329
+ /**
330
+ * How many records hold each standing. Sums to `recordCount` — every record
331
+ * has exactly one standing, so the reader can see that nothing went missing.
332
+ */
333
+ standings: Record<KbStanding, number>;
334
+ /** Shorthand for `standings.current` — records that simply hold. */
335
+ currentCount: number;
336
+ /** Shorthand for `standings.superseded`. */
337
+ supersededCount: number;
338
+ /**
339
+ * Records whose `stale_after` has passed. A flag over the standings rather
340
+ * than one of them — a current record can be stale — so this deliberately
341
+ * does not participate in the sum.
342
+ */
343
+ staleCount: number;
344
+ };
345
+ /**
346
+ * The tier-one listing: every record named, nothing spelled out.
347
+ *
348
+ * `load` hands over bodies and `pack` hands over a neighbourhood; both have to
349
+ * decide what the reader can afford. The catalog is the rung below either — one
350
+ * line per record at roughly thirty tokens, so a base far past `load`'s gate
351
+ * still fits in a single call. What it buys is the ability to choose: a reader
352
+ * that can see every id, type, title and standing knows which record to `pack`
353
+ * and knows when no record covers the question at all, which is the conclusion
354
+ * a truncated read can never support.
355
+ *
356
+ * Standing travels on the line for the same reason it travels with every other
357
+ * result here: a title is a claim, and a superseded claim reads exactly like a
358
+ * live one. A superseded entry names its replacement, so the line the reader
359
+ * should follow instead is already in front of them.
360
+ *
361
+ * Unbounded, alone among the read paths. `load` and `pack` refuse past a
362
+ * ceiling because a partial body set reads as a complete one; a catalog has no
363
+ * such failure — it is the rung a caller lands on *because* something else
364
+ * refused, and a second refusal there would leave nowhere to go. The cost is
365
+ * linear and cheap: roughly thirty tokens a record, so a thousand-record base
366
+ * is about 30k and five thousand about 150k. Past that the `type` filter
367
+ * narrows it, and no ceiling is needed to make that available.
368
+ *
369
+ * Deterministic given a fixed `now`: no timestamp is emitted, and the ordering
370
+ * is total down to the concept id, so two catalogs of an unchanged base within
371
+ * one `stale_after` window are byte-identical and diff to nothing. The default
372
+ * clock is the wall clock, so a line can still flip to stale as a date passes —
373
+ * pass `now` when byte-equality has to hold across that boundary.
374
+ */
375
+ declare function catalog(bundle: KbRecord[], options?: {
376
+ type?: string;
377
+ now?: Date;
378
+ }): KbCatalogResult;
379
+ /**
380
+ * One entry, as one line.
381
+ *
382
+ * ` · `-separated rather than a table: a table pays for column alignment on
383
+ * every row, and nothing downstream parses these.
384
+ */
385
+ declare function renderCatalogLine(entry: KbCatalogEntry): string;
386
+
314
387
  declare const LOG_FILE = "log.jsonl";
315
388
  declare const kbLogEntrySchema: z.ZodObject<{
316
389
  at: z.ZodISODateTime;
@@ -391,6 +464,8 @@ type KbLoadResult = {
391
464
  recordCount: number;
392
465
  approxTokens: number;
393
466
  budgetTokens: number;
467
+ /** The refusal in words, naming the budget and what to call next. */
468
+ message: string;
394
469
  };
395
470
  type KbWriteInput = {
396
471
  type: string;
@@ -509,9 +584,16 @@ declare class KbStore {
509
584
  * is indistinguishable from a complete one, so a caller would answer "that
510
585
  * was never decided" from a slice it did not know was a slice.
511
586
  *
512
- * That refusal is the default guardrail. `all` bypasses it outright and
513
- * always hands back the whole bundle: an explicit, never-accidental escape
514
- * hatch for an operator who has the budget to spend, not a wider default.
587
+ * A token budget decides that, measured over what is actually handed back.
588
+ * The refusal names the estimate and the budget, because a caller told only
589
+ * "too big" cannot tell whether to narrow the type filter, raise the budget,
590
+ * or stop loading the base whole altogether. Past the budget the answer is
591
+ * the catalog and then a pack, which is what the refusal says.
592
+ *
593
+ * That refusal is the default guardrail. `all` bypasses the budget outright
594
+ * and always hands back the whole bundle: an explicit, never-accidental
595
+ * escape hatch for an operator who has the budget to spend, not a wider
596
+ * default.
515
597
  */
516
598
  load(bundlePath: string, options?: {
517
599
  budgetTokens?: number;
@@ -520,6 +602,11 @@ declare class KbStore {
520
602
  }): Promise<KbLoadResult>;
521
603
  /** How a position was arrived at, as a timeline. See `trace.ts`. */
522
604
  trace(bundlePath: string, seedId: string, options?: KbTraceOptions): Promise<KbTraceStep[]>;
605
+ /** Every record named in one line each. See `catalog.ts`. */
606
+ catalog(bundlePath: string, options?: {
607
+ type?: string;
608
+ now?: Date;
609
+ }): Promise<KbCatalogResult>;
523
610
  /** A bounded neighbourhood around one record. See `pack.ts`. */
524
611
  pack(bundlePath: string, rootId: string, options?: KbPackOptions): Promise<KbPackResult>;
525
612
  /**
@@ -641,6 +728,7 @@ declare enum Fault {
641
728
  declare enum ErrorTypes {
642
729
  KbRecordAlreadyExists = "KbRecordAlreadyExists",
643
730
  KbInvalidConceptId = "KbInvalidConceptId",
731
+ KbMissingFlagValue = "KbMissingFlagValue",
644
732
  KbPackBudgetExceeded = "KbPackBudgetExceeded",
645
733
  KbRecordNotFound = "KbRecordNotFound",
646
734
  KbSelfVerification = "KbSelfVerification",
@@ -707,6 +795,18 @@ declare class KbPackBudgetExceededError extends BaseError {
707
795
  readonly excluded: string[];
708
796
  constructor(recordCount: number, approxTokens: number, budgetTokens: number, excluded: string[]);
709
797
  }
798
+ /**
799
+ * A flag that takes a value, given none.
800
+ *
801
+ * `strauss-kb load --budget` used to read the next argv entry, find
802
+ * nothing, and quietly fall back to the default — so a caller who meant to
803
+ * raise a ceiling got the ceiling they were trying to move, and a typo looked
804
+ * exactly like success. Refusing is the only way that stays visible.
805
+ */
806
+ declare class KbMissingFlagValueError extends BaseError {
807
+ readonly flag: string;
808
+ constructor(flag: string);
809
+ }
710
810
  declare class KbInvalidConceptIdError extends BaseError {
711
811
  constructor(message: string, details: Record<string, string>);
712
812
  }
@@ -1511,4 +1611,4 @@ declare function parseMarkdownWithFrontmatter<S extends z.ZodType>(text: string,
1511
1611
  frontmatter: ReturnType<S["safeParse"]>;
1512
1612
  };
1513
1613
 
1514
- export { BaseError, CONTEXT_BEGIN, CONTEXT_END, CONTEXT_PROFILES, type ComposeInput, type ComposedRecord, DECISION_TYPE, DEFAULT_AGING_DAYS, DEFAULT_EXPIRING_DAYS, DEFAULT_LOAD_BUDGET, DEFAULT_PACK_HOPS, DEFAULT_PACK_MAX_NODES, DEFAULT_UNVERIFIED_DAYS, type DecisionInput, type DiffFile, type DiffHunk, type DiffMatch, type ErrorDetails, type ErrorProps, ErrorTypes, Fault, INDEX_FILE, KB_COMMANDS, KB_COMMANDS_BY_NAME, KB_CONCEPT_ID_PATTERN, KB_CONFIDENCES, KB_DIR, KB_DOCTOR_CHECKS, KB_EDGE_KINDS, KB_MATERIALITIES, KB_RECORD_STATUSES, KB_RECORD_TYPES, KB_SLUG_PATTERN, type KbActorStamp, type KbAdjudicated, type KbAnchor, KbBaseFrozenError, type KbCommand, type KbCommandContext, type KbContextBudgets, type KbContextOptions, type KbContextResult, type KbDoctorCheck, type KbDoctorFinding, type KbDoctorGroup, type KbDoctorOptions, type KbDoctorReport, type KbDoctorThresholds, type KbEdgeKind, KbInvalidConceptIdError, type KbLoadResult, type KbLogEntry, type KbLogReadResult, type KbLogger, type KbMergedPin, type KbMergedPins, type KbNeighbour, KbPackBudgetExceededError, type KbPackOptions, type KbPackResult, type KbPackedRecord, type KbPin, type KbPinLayer, type KbPinOptions, type KbPinResult, type KbPinStatus, KbPinsMalformedError, type KbPinsManifest, 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, type KbValidationProblem, type KbVerifiedEvent, type KbWarning, KbWriteConflictError, type KbWriteInput, LOG_FILE, type MatchOptions, NO_DECISION_SLUG, PINS_FILE, PINS_LOCAL_FILE, PIN_LAYERS, type QmdModule, RECORD_TYPES, SEARCH_INDEX_FILE, type SearchHit, type SearchOptions, type SymbolRange, TRACE_EDGES, adjudicate, assertBaseNotFrozen, buildContext, composeDecisionRecord, composeInputSchema, composeNoDecisionRecord, composeRecord, contextProfileBudgets, createKbMcpServer, decisionInputSchema, doctor, edgeNeighbours, indexIsStale, isKbRecordType, isNoDecisionRecord, kbActorStampSchema, kbAnchorSchema, kbConceptIdSchema, kbJsonSchemas, kbLogEntrySchema, kbRecordFrontmatterSchema, kbSourceSchema, kbVerifiedEventSchema, listPins, loadQmd, matchToDiff, mergedContextBudgets, neighbours, pack, parseLog, parseMarkdownWithFrontmatter, pinBase, readMergedPins, readPinsLayer, renderIndex, renderIndexLine, renderLogEntry, resolveHeads, resolveHits, resolvePinPath, runKbCli, runKbMcpServer, searchBase, selectDecisions, splitMarkdownFrontmatter, stringifyMarkdownWithFrontmatter, syncInstructions, toHookJson, trace, unpinBase, validateBundle };
1614
+ export { BaseError, CONTEXT_BEGIN, CONTEXT_END, CONTEXT_PROFILES, type ComposeInput, type ComposedRecord, DECISION_TYPE, DEFAULT_AGING_DAYS, DEFAULT_EXPIRING_DAYS, DEFAULT_LOAD_BUDGET, DEFAULT_PACK_HOPS, DEFAULT_PACK_MAX_NODES, DEFAULT_UNVERIFIED_DAYS, type DecisionInput, type DiffFile, type DiffHunk, type DiffMatch, type ErrorDetails, type ErrorProps, ErrorTypes, Fault, INDEX_FILE, KB_COMMANDS, KB_COMMANDS_BY_NAME, KB_CONCEPT_ID_PATTERN, KB_CONFIDENCES, KB_DIR, KB_DOCTOR_CHECKS, KB_EDGE_KINDS, KB_MATERIALITIES, KB_RECORD_STATUSES, KB_RECORD_TYPES, KB_SLUG_PATTERN, type KbActorStamp, type KbAdjudicated, type KbAnchor, 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, KbInvalidConceptIdError, 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 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, type KbValidationProblem, type KbVerifiedEvent, type KbWarning, KbWriteConflictError, type KbWriteInput, LOG_FILE, type MatchOptions, NO_DECISION_SLUG, PINS_FILE, PINS_LOCAL_FILE, PIN_LAYERS, type QmdModule, RECORD_TYPES, SEARCH_INDEX_FILE, type SearchHit, type SearchOptions, type SymbolRange, TRACE_EDGES, adjudicate, assertBaseNotFrozen, buildContext, catalog, composeDecisionRecord, composeInputSchema, composeNoDecisionRecord, composeRecord, contextProfileBudgets, createKbMcpServer, decisionInputSchema, doctor, edgeNeighbours, indexIsStale, isKbRecordType, isNoDecisionRecord, kbActorStampSchema, kbAnchorSchema, kbConceptIdSchema, kbJsonSchemas, kbLogEntrySchema, kbRecordFrontmatterSchema, kbSourceSchema, kbVerifiedEventSchema, listPins, loadQmd, matchToDiff, mergedContextBudgets, neighbours, pack, parseLog, parseMarkdownWithFrontmatter, pinBase, readMergedPins, readPinsLayer, renderCatalogLine, renderIndex, renderIndexLine, renderLogEntry, resolveHeads, resolveHits, resolvePinPath, runKbCli, runKbMcpServer, searchBase, selectDecisions, splitMarkdownFrontmatter, stringifyMarkdownWithFrontmatter, syncInstructions, toHookJson, trace, unpinBase, validateBundle };
package/dist/index.js CHANGED
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  runKbCli
3
- } from "./chunk-KVEEISYQ.js";
3
+ } from "./chunk-RGK3K6LN.js";
4
4
  import {
5
5
  createKbMcpServer,
6
6
  runKbMcpServer
7
- } from "./chunk-MWWDD23L.js";
7
+ } from "./chunk-NMTP7V7E.js";
8
8
  import {
9
9
  BaseError,
10
10
  CONTEXT_BEGIN,
@@ -33,6 +33,7 @@ import {
33
33
  KB_SLUG_PATTERN,
34
34
  KbBaseFrozenError,
35
35
  KbInvalidConceptIdError,
36
+ KbMissingFlagValueError,
36
37
  KbPackBudgetExceededError,
37
38
  KbPinsMalformedError,
38
39
  KbRecordAlreadyExistsError,
@@ -51,6 +52,7 @@ import {
51
52
  adjudicate,
52
53
  assertBaseNotFrozen,
53
54
  buildContext,
55
+ catalog,
54
56
  composeDecisionRecord,
55
57
  composeInputSchema,
56
58
  composeNoDecisionRecord,
@@ -80,6 +82,7 @@ import {
80
82
  pinBase,
81
83
  readMergedPins,
82
84
  readPinsLayer,
85
+ renderCatalogLine,
83
86
  renderIndex,
84
87
  renderIndexLine,
85
88
  renderLogEntry,
@@ -95,7 +98,7 @@ import {
95
98
  trace,
96
99
  unpinBase,
97
100
  validateBundle
98
- } from "./chunk-OFDWRMY6.js";
101
+ } from "./chunk-EJQPZWN5.js";
99
102
 
100
103
  // src/match-diff.ts
101
104
  function matchToDiff(files, records, options = {}) {
@@ -204,6 +207,7 @@ export {
204
207
  KB_SLUG_PATTERN,
205
208
  KbBaseFrozenError,
206
209
  KbInvalidConceptIdError,
210
+ KbMissingFlagValueError,
207
211
  KbPackBudgetExceededError,
208
212
  KbPinsMalformedError,
209
213
  KbRecordAlreadyExistsError,
@@ -222,6 +226,7 @@ export {
222
226
  adjudicate,
223
227
  assertBaseNotFrozen,
224
228
  buildContext,
229
+ catalog,
225
230
  composeDecisionRecord,
226
231
  composeInputSchema,
227
232
  composeNoDecisionRecord,
@@ -253,6 +258,7 @@ export {
253
258
  pinBase,
254
259
  readMergedPins,
255
260
  readPinsLayer,
261
+ renderCatalogLine,
256
262
  renderIndex,
257
263
  renderIndexLine,
258
264
  renderLogEntry,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/match-diff.ts"],"sourcesContent":["import { adjudicate, type KbAdjudicated } from \"./adjudicate.js\";\nimport type { KbAnchor, KbRecord } from \"./kb-record.schema.js\";\n\n/**\n * Which records apply to which part of a change.\n *\n * Takes a structural description of a diff rather than a patch, so this package\n * carries no diff parser: callers already have one, and a knowledge base has no\n * business preferring a particular flavour of unified diff.\n *\n * Deterministic on purpose. Every step here is mechanical — the one judgment,\n * whether a matched record is worth showing a reviewer, is deliberately absent.\n * A model placed here would sit between the reviewer and their diff on every\n * review, to answer a question nobody has yet shown needs asking.\n *\n * Distinct from `load()`, which hands a reader the whole base. That answers\n * \"does anything address this question\"; this answers \"what is attached to this\n * code\", and an anchor is the author's own statement rather than an inference\n * from one. A reader guessing which record relates to a hunk would be guessing\n * at something already written down — and a diff has dozens of hunks, which is\n * dozens of reader calls against microseconds of matching. Where they compose:\n * this narrows a hunk to a few records, and a reader asked to explain them gets\n * those, not the base.\n */\nexport type DiffHunk = {\n /** 1-based, inclusive, in the file's post-change line numbering. */\n startLine: number;\n endLine: number;\n};\n\nexport type DiffFile = {\n /** Repo-relative, matching how anchors are written. */\n filePath: string;\n hunks: DiffHunk[];\n};\n\n/**\n * A symbol resolved to lines. Supplied by whatever the caller uses to index\n * symbols; absence is tolerated — see `place()`.\n */\nexport type SymbolRange = {\n file: string;\n symbol: string;\n startLine: number;\n endLine: number;\n};\n\nexport type DiffMatch = {\n filePath: string;\n hunk: DiffHunk;\n /** Current records first — what still holds should be read before what does not. */\n records: KbAdjudicated[];\n /**\n * `symbol` when every record here was placed by a resolved symbol range,\n * `file` when at least one fell back to the whole file. Reported rather than\n * hidden: a caller showing a file-level match as though it were pinned to\n * these lines is claiming a precision it does not have.\n */\n precision: \"symbol\" | \"file\";\n};\n\nexport type MatchOptions = {\n /** Without these, symbol anchors degrade to file level rather than vanishing. */\n symbolRanges?: SymbolRange[];\n now?: Date;\n};\n\nexport function matchToDiff(\n files: DiffFile[],\n records: KbRecord[],\n options: MatchOptions = {},\n): DiffMatch[] {\n const ranges = indexRanges(options.symbolRanges ?? []);\n const anchored = records.filter(\n (record) => (record.frontmatter.strauss_anchors ?? []).length > 0,\n );\n const matches: DiffMatch[] = [];\n\n for (const file of files) {\n const candidates = anchored\n .map((record) => ({\n record,\n anchors: (record.frontmatter.strauss_anchors ?? []).filter(\n (anchor) => normalize(anchor.file) === normalize(file.filePath),\n ),\n }))\n .filter(({ anchors }) => anchors.length > 0);\n if (!candidates.length) continue;\n\n for (const hunk of file.hunks) {\n const hits: KbRecord[] = [];\n let precision: DiffMatch[\"precision\"] = \"symbol\";\n\n for (const { record, anchors } of candidates) {\n const placement = place(anchors, file.filePath, hunk, ranges);\n if (placement === \"miss\") continue;\n if (placement === \"file\") precision = \"file\";\n hits.push(record);\n }\n\n if (!hits.length) continue;\n matches.push({\n filePath: file.filePath,\n hunk,\n records: order(adjudicate(hits, records, options.now)),\n precision,\n });\n }\n }\n\n return matches;\n}\n\n/**\n * Whether any of a record's anchors puts it on this hunk.\n *\n * An anchor naming only a file is about the whole file, so it lands on every\n * hunk in it. One naming a symbol lands only where that symbol's lines overlap\n * — unless nothing resolved the symbol, in which case it falls back to the file\n * rather than disappearing. A record silently absent because a resolver was\n * unavailable is worse than one shown imprecisely and labelled as such.\n */\nfunction place(\n anchors: KbAnchor[],\n filePath: string,\n hunk: DiffHunk,\n ranges: Map<string, SymbolRange[]>,\n): \"symbol\" | \"file\" | \"miss\" {\n let fallback: \"file\" | \"miss\" = \"miss\";\n\n for (const anchor of anchors) {\n if (!anchor.symbol) return \"file\";\n\n const resolved = ranges.get(key(filePath, anchor.symbol));\n if (!resolved?.length) {\n fallback = \"file\";\n continue;\n }\n if (resolved.some((range) => overlaps(range, hunk))) return \"symbol\";\n }\n\n return fallback;\n}\n\nfunction overlaps(range: SymbolRange, hunk: DiffHunk): boolean {\n return range.startLine <= hunk.endLine && hunk.startLine <= range.endLine;\n}\n\n/** Current before superseded, then oldest first, so an arc reads in order. */\nfunction order(records: KbAdjudicated[]): KbAdjudicated[] {\n const rank: Record<string, number> = {\n current: 0,\n unsettled: 1,\n open: 2,\n superseded: 3,\n rejected: 4,\n };\n return [...records].sort(\n (left, right) =>\n (rank[left.standing] ?? 9) - (rank[right.standing] ?? 9) ||\n (left.record.frontmatter.generated?.at ?? \"\").localeCompare(\n right.record.frontmatter.generated?.at ?? \"\",\n ),\n );\n}\n\nfunction indexRanges(ranges: SymbolRange[]): Map<string, SymbolRange[]> {\n const byKey = new Map<string, SymbolRange[]>();\n for (const range of ranges) {\n const id = key(range.file, range.symbol);\n byKey.set(id, [...(byKey.get(id) ?? []), range]);\n }\n return byKey;\n}\n\nfunction key(file: string, symbol: string): string {\n return `${normalize(file)}#${symbol}`;\n}\n\n/** Anchors are written by hand often enough that `./` shows up. */\nfunction normalize(path: string): string {\n return path.replace(/^\\.\\//, \"\");\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmEO,SAAS,YACd,OACA,SACA,UAAwB,CAAC,GACZ;AACb,QAAM,SAAS,YAAY,QAAQ,gBAAgB,CAAC,CAAC;AACrD,QAAM,WAAW,QAAQ;AAAA,IACvB,CAAC,YAAY,OAAO,YAAY,mBAAmB,CAAC,GAAG,SAAS;AAAA,EAClE;AACA,QAAM,UAAuB,CAAC;AAE9B,aAAW,QAAQ,OAAO;AACxB,UAAM,aAAa,SAChB,IAAI,CAAC,YAAY;AAAA,MAChB;AAAA,MACA,UAAU,OAAO,YAAY,mBAAmB,CAAC,GAAG;AAAA,QAClD,CAAC,WAAW,UAAU,OAAO,IAAI,MAAM,UAAU,KAAK,QAAQ;AAAA,MAChE;AAAA,IACF,EAAE,EACD,OAAO,CAAC,EAAE,QAAQ,MAAM,QAAQ,SAAS,CAAC;AAC7C,QAAI,CAAC,WAAW,OAAQ;AAExB,eAAW,QAAQ,KAAK,OAAO;AAC7B,YAAM,OAAmB,CAAC;AAC1B,UAAI,YAAoC;AAExC,iBAAW,EAAE,QAAQ,QAAQ,KAAK,YAAY;AAC5C,cAAM,YAAY,MAAM,SAAS,KAAK,UAAU,MAAM,MAAM;AAC5D,YAAI,cAAc,OAAQ;AAC1B,YAAI,cAAc,OAAQ,aAAY;AACtC,aAAK,KAAK,MAAM;AAAA,MAClB;AAEA,UAAI,CAAC,KAAK,OAAQ;AAClB,cAAQ,KAAK;AAAA,QACX,UAAU,KAAK;AAAA,QACf;AAAA,QACA,SAAS,MAAM,WAAW,MAAM,SAAS,QAAQ,GAAG,CAAC;AAAA,QACrD;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AAEA,SAAO;AACT;AAWA,SAAS,MACP,SACA,UACA,MACA,QAC4B;AAC5B,MAAI,WAA4B;AAEhC,aAAW,UAAU,SAAS;AAC5B,QAAI,CAAC,OAAO,OAAQ,QAAO;AAE3B,UAAM,WAAW,OAAO,IAAI,IAAI,UAAU,OAAO,MAAM,CAAC;AACxD,QAAI,CAAC,UAAU,QAAQ;AACrB,iBAAW;AACX;AAAA,IACF;AACA,QAAI,SAAS,KAAK,CAAC,UAAU,SAAS,OAAO,IAAI,CAAC,EAAG,QAAO;AAAA,EAC9D;AAEA,SAAO;AACT;AAEA,SAAS,SAAS,OAAoB,MAAyB;AAC7D,SAAO,MAAM,aAAa,KAAK,WAAW,KAAK,aAAa,MAAM;AACpE;AAGA,SAAS,MAAM,SAA2C;AACxD,QAAM,OAA+B;AAAA,IACnC,SAAS;AAAA,IACT,WAAW;AAAA,IACX,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,UAAU;AAAA,EACZ;AACA,SAAO,CAAC,GAAG,OAAO,EAAE;AAAA,IAClB,CAAC,MAAM,WACJ,KAAK,KAAK,QAAQ,KAAK,MAAM,KAAK,MAAM,QAAQ,KAAK,OACrD,KAAK,OAAO,YAAY,WAAW,MAAM,IAAI;AAAA,MAC5C,MAAM,OAAO,YAAY,WAAW,MAAM;AAAA,IAC5C;AAAA,EACJ;AACF;AAEA,SAAS,YAAY,QAAmD;AACtE,QAAM,QAAQ,oBAAI,IAA2B;AAC7C,aAAW,SAAS,QAAQ;AAC1B,UAAM,KAAK,IAAI,MAAM,MAAM,MAAM,MAAM;AACvC,UAAM,IAAI,IAAI,CAAC,GAAI,MAAM,IAAI,EAAE,KAAK,CAAC,GAAI,KAAK,CAAC;AAAA,EACjD;AACA,SAAO;AACT;AAEA,SAAS,IAAI,MAAc,QAAwB;AACjD,SAAO,GAAG,UAAU,IAAI,CAAC,IAAI,MAAM;AACrC;AAGA,SAAS,UAAU,MAAsB;AACvC,SAAO,KAAK,QAAQ,SAAS,EAAE;AACjC;","names":[]}
1
+ {"version":3,"sources":["../src/match-diff.ts"],"sourcesContent":["import { adjudicate, type KbAdjudicated } from \"./adjudicate.js\";\nimport type { KbAnchor, KbRecord } from \"./kb-record.schema.js\";\n\n/**\n * Which records apply to which part of a change.\n *\n * Takes a structural description of a diff rather than a patch, so this package\n * carries no diff parser: callers already have one, and a knowledge base has no\n * business preferring a particular flavour of unified diff.\n *\n * Deterministic on purpose. Every step here is mechanical — the one judgment,\n * whether a matched record is worth showing a reviewer, is deliberately absent.\n * A model placed here would sit between the reviewer and their diff on every\n * review, to answer a question nobody has yet shown needs asking.\n *\n * Distinct from `load()`, which hands a reader the whole base. That answers\n * \"does anything address this question\"; this answers \"what is attached to this\n * code\", and an anchor is the author's own statement rather than an inference\n * from one. A reader guessing which record relates to a hunk would be guessing\n * at something already written down — and a diff has dozens of hunks, which is\n * dozens of reader calls against microseconds of matching. Where they compose:\n * this narrows a hunk to a few records, and a reader asked to explain them gets\n * those, not the base.\n */\nexport type DiffHunk = {\n /** 1-based, inclusive, in the file's post-change line numbering. */\n startLine: number;\n endLine: number;\n};\n\nexport type DiffFile = {\n /** Repo-relative, matching how anchors are written. */\n filePath: string;\n hunks: DiffHunk[];\n};\n\n/**\n * A symbol resolved to lines. Supplied by whatever the caller uses to index\n * symbols; absence is tolerated — see `place()`.\n */\nexport type SymbolRange = {\n file: string;\n symbol: string;\n startLine: number;\n endLine: number;\n};\n\nexport type DiffMatch = {\n filePath: string;\n hunk: DiffHunk;\n /** Current records first — what still holds should be read before what does not. */\n records: KbAdjudicated[];\n /**\n * `symbol` when every record here was placed by a resolved symbol range,\n * `file` when at least one fell back to the whole file. Reported rather than\n * hidden: a caller showing a file-level match as though it were pinned to\n * these lines is claiming a precision it does not have.\n */\n precision: \"symbol\" | \"file\";\n};\n\nexport type MatchOptions = {\n /** Without these, symbol anchors degrade to file level rather than vanishing. */\n symbolRanges?: SymbolRange[];\n now?: Date;\n};\n\nexport function matchToDiff(\n files: DiffFile[],\n records: KbRecord[],\n options: MatchOptions = {},\n): DiffMatch[] {\n const ranges = indexRanges(options.symbolRanges ?? []);\n const anchored = records.filter(\n (record) => (record.frontmatter.strauss_anchors ?? []).length > 0,\n );\n const matches: DiffMatch[] = [];\n\n for (const file of files) {\n const candidates = anchored\n .map((record) => ({\n record,\n anchors: (record.frontmatter.strauss_anchors ?? []).filter(\n (anchor) => normalize(anchor.file) === normalize(file.filePath),\n ),\n }))\n .filter(({ anchors }) => anchors.length > 0);\n if (!candidates.length) continue;\n\n for (const hunk of file.hunks) {\n const hits: KbRecord[] = [];\n let precision: DiffMatch[\"precision\"] = \"symbol\";\n\n for (const { record, anchors } of candidates) {\n const placement = place(anchors, file.filePath, hunk, ranges);\n if (placement === \"miss\") continue;\n if (placement === \"file\") precision = \"file\";\n hits.push(record);\n }\n\n if (!hits.length) continue;\n matches.push({\n filePath: file.filePath,\n hunk,\n records: order(adjudicate(hits, records, options.now)),\n precision,\n });\n }\n }\n\n return matches;\n}\n\n/**\n * Whether any of a record's anchors puts it on this hunk.\n *\n * An anchor naming only a file is about the whole file, so it lands on every\n * hunk in it. One naming a symbol lands only where that symbol's lines overlap\n * — unless nothing resolved the symbol, in which case it falls back to the file\n * rather than disappearing. A record silently absent because a resolver was\n * unavailable is worse than one shown imprecisely and labelled as such.\n */\nfunction place(\n anchors: KbAnchor[],\n filePath: string,\n hunk: DiffHunk,\n ranges: Map<string, SymbolRange[]>,\n): \"symbol\" | \"file\" | \"miss\" {\n let fallback: \"file\" | \"miss\" = \"miss\";\n\n for (const anchor of anchors) {\n if (!anchor.symbol) return \"file\";\n\n const resolved = ranges.get(key(filePath, anchor.symbol));\n if (!resolved?.length) {\n fallback = \"file\";\n continue;\n }\n if (resolved.some((range) => overlaps(range, hunk))) return \"symbol\";\n }\n\n return fallback;\n}\n\nfunction overlaps(range: SymbolRange, hunk: DiffHunk): boolean {\n return range.startLine <= hunk.endLine && hunk.startLine <= range.endLine;\n}\n\n/** Current before superseded, then oldest first, so an arc reads in order. */\nfunction order(records: KbAdjudicated[]): KbAdjudicated[] {\n const rank: Record<string, number> = {\n current: 0,\n unsettled: 1,\n open: 2,\n superseded: 3,\n rejected: 4,\n };\n return [...records].sort(\n (left, right) =>\n (rank[left.standing] ?? 9) - (rank[right.standing] ?? 9) ||\n (left.record.frontmatter.generated?.at ?? \"\").localeCompare(\n right.record.frontmatter.generated?.at ?? \"\",\n ),\n );\n}\n\nfunction indexRanges(ranges: SymbolRange[]): Map<string, SymbolRange[]> {\n const byKey = new Map<string, SymbolRange[]>();\n for (const range of ranges) {\n const id = key(range.file, range.symbol);\n byKey.set(id, [...(byKey.get(id) ?? []), range]);\n }\n return byKey;\n}\n\nfunction key(file: string, symbol: string): string {\n return `${normalize(file)}#${symbol}`;\n}\n\n/** Anchors are written by hand often enough that `./` shows up. */\nfunction normalize(path: string): string {\n return path.replace(/^\\.\\//, \"\");\n}\n"],"mappings":"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","names":[]}