@saasontools/strauss-kb 0.1.11 → 0.1.12

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
@@ -590,6 +590,12 @@ type KbLoadResult = {
590
590
  tokensLoaded: number;
591
591
  /** `null` when loaded via `all`: no ceiling was applied. */
592
592
  budgetTokens: number | null;
593
+ /**
594
+ * Sha256 over every record's content and standing, sorted by concept
595
+ * id. Flips when a body, frontmatter, or standing changes; it's the
596
+ * base's content stamp, compared by hooks and `kb_stamp` (SAA-719).
597
+ */
598
+ digest: string;
593
599
  } | {
594
600
  loaded: false;
595
601
  recordCount: number;
@@ -597,6 +603,13 @@ type KbLoadResult = {
597
603
  budgetTokens: number;
598
604
  /** The refusal in words, naming the budget and what to call next. */
599
605
  message: string;
606
+ /**
607
+ * Same digest a successful load would carry, computed over what would
608
+ * have been handed back. Cheap here — adjudication already ran before
609
+ * the refusal — and it lets a caller notice a refused bundle's content
610
+ * changed (say, after a narrower `type` filter) without loading it.
611
+ */
612
+ digest: string;
600
613
  };
601
614
  type KbWriteInput = {
602
615
  type: string;
package/dist/index.d.ts CHANGED
@@ -590,6 +590,12 @@ type KbLoadResult = {
590
590
  tokensLoaded: number;
591
591
  /** `null` when loaded via `all`: no ceiling was applied. */
592
592
  budgetTokens: number | null;
593
+ /**
594
+ * Sha256 over every record's content and standing, sorted by concept
595
+ * id. Flips when a body, frontmatter, or standing changes; it's the
596
+ * base's content stamp, compared by hooks and `kb_stamp` (SAA-719).
597
+ */
598
+ digest: string;
593
599
  } | {
594
600
  loaded: false;
595
601
  recordCount: number;
@@ -597,6 +603,13 @@ type KbLoadResult = {
597
603
  budgetTokens: number;
598
604
  /** The refusal in words, naming the budget and what to call next. */
599
605
  message: string;
606
+ /**
607
+ * Same digest a successful load would carry, computed over what would
608
+ * have been handed back. Cheap here — adjudication already ran before
609
+ * the refusal — and it lets a caller notice a refused bundle's content
610
+ * changed (say, after a narrower `type` filter) without loading it.
611
+ */
612
+ digest: string;
600
613
  };
601
614
  type KbWriteInput = {
602
615
  type: string;
package/dist/index.js CHANGED
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  runKbCli
3
- } from "./chunk-I3WW4F6X.js";
3
+ } from "./chunk-F2U2YLWV.js";
4
4
  import {
5
5
  createKbMcpServer,
6
6
  runKbMcpServer
7
- } from "./chunk-CWWXMD35.js";
7
+ } from "./chunk-EXKK2KUN.js";
8
8
  import {
9
9
  BaseError,
10
10
  CONTEXT_BEGIN,
@@ -103,7 +103,7 @@ import {
103
103
  trace,
104
104
  unpinBase,
105
105
  validateBundle
106
- } from "./chunk-OVRQCQ6P.js";
106
+ } from "./chunk-33ZCBEUV.js";
107
107
 
108
108
  // src/match-diff.ts
109
109
  function matchToDiff(files, records, options = {}) {
package/dist/mcp-main.cjs CHANGED
@@ -2471,7 +2471,7 @@ var loadCommand = define({
2471
2471
  name: "load",
2472
2472
  tool: "kb_load",
2473
2473
  usage: "load [type] [--budget N | --all] [--repo-root PATH]",
2474
- description: "Loads the whole knowledge base at once, each record with its standing. Superseded records arrive as stubs (name, replacement, date); rejected and open records arrive whole. Refuses past the token budget rather than truncating \u2014 call kb_catalog, then kb_pack on the record that matters, or narrow with `type`; kb_query for a lookup by wording. `all` bypasses the budget.",
2474
+ description: "Loads the whole knowledge base at once, each record with its standing. Superseded records arrive as stubs; rejected and open records arrive whole. Refuses past the token budget \u2014 call kb_catalog, kb_pack on it; `all` bypasses the budget. Never read record files directly. Cache-stable; `digest` is the base's content stamp \u2014 hooks use it to tell you when to reload.",
2475
2475
  input: import_zod12.z.object({
2476
2476
  bundlePath,
2477
2477
  type: import_zod12.z.enum(KB_RECORD_TYPES).optional(),
@@ -2714,7 +2714,7 @@ var queryCommand = define({
2714
2714
  name: "query",
2715
2715
  tool: "kb_query",
2716
2716
  usage: "query <text...> [--repo-root PATH]",
2717
- description: "Search and return each match with its standing. Results are flagged, never filtered: a superseded record comes back alongside whatever replaced it, and a rejected one is marked as something explicitly not adopted. This is the lookup-by-wording rung, and the narrowest of the three: use it when you know roughly what the record says. The decision rule around it \u2014 while the base fits kb_load's token budget, kb_load it whole, because on this package's measurements a reader holding the whole base answered eight of nine questions whose wording appears in no record where embedding search answered four; once kb_load refuses, kb_catalog for one line per record and then kb_pack on the record the work centres on; and kb_query when the question is a point lookup rather than a neighbourhood. A query cannot tell you that nothing was decided \u2014 it returns its nearest hit whatever the distance \u2014 so reach for kb_catalog when the question is what exists. Never read record files directly: this tool (with kb_load, kb_catalog, kb_pack and kb_trace) is the only supported way to read a base; a file read bypasses supersession resolution and returns replaced records as if current.",
2717
+ description: "Search; every hit carries its standing. Flagged, never filtered: a superseded hit returns with its replacement, a rejected one is marked. Prefer kb_load when the base fits its budget \u2014 a full read beats search. Results are volatile: place them at the tail, not the cached prefix. Never read record files directly.",
2718
2718
  input: import_zod18.z.object({
2719
2719
  bundlePath,
2720
2720
  text: import_zod18.z.string().optional(),
@@ -3734,6 +3734,7 @@ ${answer}
3734
3734
  const records = adjudicated.filter((hit) => hit.standing !== "superseded");
3735
3735
  const superseded = adjudicated.filter((hit) => hit.standing === "superseded").map(stub);
3736
3736
  const approxTokens2 = records.reduce((total, hit) => total + estimateTokens(hit.record), 0) + superseded.reduce((total, entry) => total + estimateStubTokens(entry), 0);
3737
+ const bundleDigestValue = bundleDigest(records, superseded);
3737
3738
  if (!options.all && approxTokens2 > budgetTokens) {
3738
3739
  return {
3739
3740
  loaded: false,
@@ -3744,7 +3745,8 @@ ${answer}
3744
3745
  approxTokens: approxTokens2,
3745
3746
  budgetTokens,
3746
3747
  type: options.type
3747
- })
3748
+ }),
3749
+ digest: bundleDigestValue
3748
3750
  };
3749
3751
  }
3750
3752
  return {
@@ -3753,7 +3755,8 @@ ${answer}
3753
3755
  tokensLoaded: approxTokens2,
3754
3756
  budgetTokens: options.all ? null : budgetTokens,
3755
3757
  records,
3756
- superseded
3758
+ superseded,
3759
+ digest: bundleDigestValue
3757
3760
  };
3758
3761
  }
3759
3762
  /** How a position was arrived at, as a timeline. See `trace.ts`. */
@@ -4070,9 +4073,25 @@ function normalizeActor(id) {
4070
4073
  function digest(contents) {
4071
4074
  return (0, import_node_crypto2.createHash)("sha256").update(contents).digest("hex");
4072
4075
  }
4076
+ function bundleDigest(records, superseded) {
4077
+ const entries = [
4078
+ ...records.map(
4079
+ (hit) => `${hit.record.conceptId}:current:${digest(
4080
+ stringifyMarkdownWithFrontmatter(
4081
+ hit.record.body,
4082
+ hit.record.frontmatter
4083
+ )
4084
+ )}`
4085
+ ),
4086
+ ...superseded.map(
4087
+ (entry) => `${entry.conceptId}:superseded:${digest(JSON.stringify(entry))}`
4088
+ )
4089
+ ].sort();
4090
+ return digest(entries.join("\n"));
4091
+ }
4073
4092
 
4074
4093
  // src/version.ts
4075
- var VERSION = true ? "0.1.11" : "0.0.0-dev";
4094
+ var VERSION = true ? "0.1.12" : "0.0.0-dev";
4076
4095
 
4077
4096
  // src/mcp.ts
4078
4097
  function createKbMcpServer() {