@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/README.md +71 -39
- package/dist/{chunk-OFDWRMY6.js → chunk-EJQPZWN5.js} +397 -233
- package/dist/chunk-EJQPZWN5.js.map +1 -0
- package/dist/{chunk-MWWDD23L.js → chunk-NMTP7V7E.js} +2 -2
- package/dist/{chunk-KVEEISYQ.js → chunk-RGK3K6LN.js} +2 -2
- package/dist/cli-main.cjs +386 -222
- package/dist/cli-main.cjs.map +1 -1
- package/dist/cli-main.js +2 -2
- package/dist/index.cjs +255 -88
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +104 -4
- package/dist/index.d.ts +104 -4
- package/dist/index.js +9 -3
- package/dist/index.js.map +1 -1
- package/dist/mcp-main.cjs +386 -222
- package/dist/mcp-main.cjs.map +1 -1
- package/dist/mcp-main.js +2 -2
- package/package.json +1 -1
- package/dist/chunk-OFDWRMY6.js.map +0 -1
- /package/dist/{chunk-MWWDD23L.js.map → chunk-NMTP7V7E.js.map} +0 -0
- /package/dist/{chunk-KVEEISYQ.js.map → chunk-RGK3K6LN.js.map} +0 -0
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
|
-
*
|
|
513
|
-
*
|
|
514
|
-
*
|
|
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
|
-
*
|
|
513
|
-
*
|
|
514
|
-
*
|
|
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-
|
|
3
|
+
} from "./chunk-RGK3K6LN.js";
|
|
4
4
|
import {
|
|
5
5
|
createKbMcpServer,
|
|
6
6
|
runKbMcpServer
|
|
7
|
-
} from "./chunk-
|
|
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-
|
|
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":"
|
|
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":[]}
|