@saasontools/strauss-kb 0.1.15 → 0.1.16

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/cli-main.js CHANGED
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  runKbCli
4
- } from "./chunk-MK7GU4DX.js";
5
- import "./chunk-KNIUBCZY.js";
4
+ } from "./chunk-RINBOAQZ.js";
5
+ import "./chunk-H5W53NVU.js";
6
6
 
7
7
  // src/cli-main.ts
8
8
  runKbCli(process.argv.slice(2)).catch((error) => {
package/dist/index.cjs CHANGED
@@ -149,7 +149,6 @@ __export(index_exports, {
149
149
  module.exports = __toCommonJS(index_exports);
150
150
 
151
151
  // src/kb-store.ts
152
- var import_node_crypto2 = require("crypto");
153
152
  var import_promises4 = require("fs/promises");
154
153
  var import_node_path4 = require("path");
155
154
 
@@ -345,6 +344,8 @@ var ErrorTypes = /* @__PURE__ */ ((ErrorTypes2) => {
345
344
  ErrorTypes2["KbPackBudgetExceeded"] = "KbPackBudgetExceeded";
346
345
  ErrorTypes2["KbRecordNotFound"] = "KbRecordNotFound";
347
346
  ErrorTypes2["KbSelfVerification"] = "KbSelfVerification";
347
+ ErrorTypes2["KbStampBaselineUnreadable"] = "KbStampBaselineUnreadable";
348
+ ErrorTypes2["KbStampDigestBaselineAmbiguous"] = "KbStampDigestBaselineAmbiguous";
348
349
  ErrorTypes2["KbUnknownLinkRel"] = "KbUnknownLinkRel";
349
350
  ErrorTypes2["KbWriteConflict"] = "KbWriteConflict";
350
351
  return ErrorTypes2;
@@ -499,6 +500,36 @@ var KbInvalidConceptIdError = class extends BaseError {
499
500
  });
500
501
  }
501
502
  };
503
+ var KbStampBaselineError = class extends BaseError {
504
+ constructor(since) {
505
+ super({
506
+ message: `kb: --since ${since} is neither a 64-character digest nor a readable stamp file`,
507
+ errorType: "KbStampBaselineUnreadable" /* KbStampBaselineUnreadable */,
508
+ code: 400,
509
+ fault: "User" /* User */,
510
+ retriable: false,
511
+ reportToUser: true,
512
+ details: { since }
513
+ });
514
+ this.since = since;
515
+ }
516
+ since;
517
+ };
518
+ var KbStampDigestBaselineError = class extends BaseError {
519
+ constructor(since) {
520
+ super({
521
+ message: `kb: --since ${since} is a digest, which needs --bundle (one base) \u2014 a file baseline works for many`,
522
+ errorType: "KbStampDigestBaselineAmbiguous" /* KbStampDigestBaselineAmbiguous */,
523
+ code: 400,
524
+ fault: "User" /* User */,
525
+ retriable: false,
526
+ reportToUser: true,
527
+ details: { since }
528
+ });
529
+ this.since = since;
530
+ }
531
+ since;
532
+ };
502
533
 
503
534
  // src/kb-index.ts
504
535
  var INDEX_FILE = "INDEX.md";
@@ -1068,6 +1099,38 @@ function successors(record, byId) {
1068
1099
  return { records, missing };
1069
1100
  }
1070
1101
 
1102
+ // src/kb-stamp.ts
1103
+ var import_node_crypto = require("crypto");
1104
+ function sha256(contents) {
1105
+ return (0, import_node_crypto.createHash)("sha256").update(contents).digest("hex");
1106
+ }
1107
+ function bundleStamp(records, superseded) {
1108
+ const entries = [
1109
+ ...records.map((hit) => ({
1110
+ conceptId: hit.record.conceptId,
1111
+ digest: `current:${sha256(
1112
+ stringifyMarkdownWithFrontmatter(
1113
+ hit.record.body,
1114
+ hit.record.frontmatter
1115
+ )
1116
+ )}`
1117
+ })),
1118
+ ...superseded.map((entry) => ({
1119
+ conceptId: entry.conceptId,
1120
+ digest: `superseded:${sha256(JSON.stringify(entry))}`
1121
+ }))
1122
+ ].sort((a, b) => a.conceptId < b.conceptId ? -1 : 1);
1123
+ return {
1124
+ digest: sha256(
1125
+ entries.map((entry) => `${entry.conceptId}:${entry.digest}`).join("\n")
1126
+ ),
1127
+ records: entries
1128
+ };
1129
+ }
1130
+ function bundleDigest(records, superseded) {
1131
+ return bundleStamp(records, superseded).digest;
1132
+ }
1133
+
1071
1134
  // src/anchor-resolver/read.ts
1072
1135
  var import_promises2 = require("fs/promises");
1073
1136
  var import_node_path2 = require("path");
@@ -1159,7 +1222,7 @@ async function readAnchorFiles(files, read, concurrency = DEFAULT_IO_CONCURRENCY
1159
1222
  }
1160
1223
 
1161
1224
  // src/anchor-resolver/resolver.ts
1162
- var import_node_crypto = require("crypto");
1225
+ var import_node_crypto2 = require("crypto");
1163
1226
  var PARENT_SCOPE_LINES = 50;
1164
1227
  var CLEAN_STATE = { blockComment: false, template: false };
1165
1228
  function stripLine(line, state) {
@@ -1320,7 +1383,7 @@ function distanceToParent(lines, index, parent) {
1320
1383
  return Number.POSITIVE_INFINITY;
1321
1384
  }
1322
1385
  function hashAnchorText(text) {
1323
- return `sha256:${(0, import_node_crypto.createHash)("sha256").update(text.replace(/\r\n/g, "\n")).digest("hex")}`;
1386
+ return `sha256:${(0, import_node_crypto2.createHash)("sha256").update(text.replace(/\r\n/g, "\n")).digest("hex")}`;
1324
1387
  }
1325
1388
  function resolveAnchor(source, anchor, resolver = regexResolver) {
1326
1389
  const normalized = source.replace(/\r\n/g, "\n");
@@ -2523,6 +2586,28 @@ ${answer}
2523
2586
  digest: bundleDigestValue
2524
2587
  };
2525
2588
  }
2589
+ /**
2590
+ * `load`'s digest without `load`'s bodies — the same records, adjudicated
2591
+ * the same way, handed back as a stamp. Skips the anchor drift pass, which
2592
+ * reads source files and only ever adds warnings: no warning reaches the
2593
+ * digest, so the value is identical to the one `load` returns.
2594
+ */
2595
+ async stamp(bundlePath2) {
2596
+ const bundle = await this.list(bundlePath2);
2597
+ const adjudicated = adjudicate(bundle, bundle, /* @__PURE__ */ new Date());
2598
+ const current = adjudicated.filter((hit) => hit.standing !== "superseded");
2599
+ const superseded = adjudicated.filter((hit) => hit.standing === "superseded").map(stub);
2600
+ const stamped = bundleStamp(current, superseded);
2601
+ const dates = bundle.map((record) => record.frontmatter.generated?.at ?? null).filter((at) => typeof at === "string").sort();
2602
+ return {
2603
+ path: bundlePath2,
2604
+ digest: stamped.digest,
2605
+ recordCount: bundle.length,
2606
+ superseded: superseded.length,
2607
+ newestAt: dates.at(-1) ?? null,
2608
+ records: stamped.records
2609
+ };
2610
+ }
2526
2611
  /** How a position was arrived at, as a timeline. See `trace.ts`. */
2527
2612
  async trace(bundlePath2, seedId, options = {}) {
2528
2613
  return trace(seedId, await this.list(bundlePath2), options);
@@ -2634,7 +2719,7 @@ ${answer}
2634
2719
  const body = changeBody(parsed.body);
2635
2720
  const contents = stringifyMarkdownWithFrontmatter(body, frontmatter);
2636
2721
  const witness = await (0, import_promises4.readFile)(target, "utf8").catch(() => null);
2637
- if (witness === null || digest(witness) !== digest(before)) {
2722
+ if (witness === null || sha256(witness) !== sha256(before)) {
2638
2723
  throw new KbWriteConflictError(conceptId2);
2639
2724
  }
2640
2725
  await this.publish(target, contents, true, conceptId2);
@@ -2842,25 +2927,6 @@ function normalizeActor(id) {
2842
2927
  if (colon === -1) return id.toLowerCase();
2843
2928
  return id.slice(0, colon + 1).toLowerCase() + id.slice(colon + 1);
2844
2929
  }
2845
- function digest(contents) {
2846
- return (0, import_node_crypto2.createHash)("sha256").update(contents).digest("hex");
2847
- }
2848
- function bundleDigest(records, superseded) {
2849
- const entries = [
2850
- ...records.map(
2851
- (hit) => `${hit.record.conceptId}:current:${digest(
2852
- stringifyMarkdownWithFrontmatter(
2853
- hit.record.body,
2854
- hit.record.frontmatter
2855
- )
2856
- )}`
2857
- ),
2858
- ...superseded.map(
2859
- (entry) => `${entry.conceptId}:superseded:${digest(JSON.stringify(entry))}`
2860
- )
2861
- ].sort();
2862
- return digest(entries.join("\n"));
2863
- }
2864
2930
 
2865
2931
  // src/compose.ts
2866
2932
  var import_zod3 = require("zod");
@@ -4921,17 +4987,115 @@ var schemaCommand = define({
4921
4987
  run: () => Promise.resolve(kbJsonSchemas())
4922
4988
  });
4923
4989
 
4924
- // src/commands/status.ts
4990
+ // src/commands/stamp.ts
4991
+ var import_promises7 = require("fs/promises");
4925
4992
  var import_zod25 = require("zod");
4993
+ var DIGEST = /^[0-9a-f]{64}$/;
4994
+ var stampCommand = define({
4995
+ name: "stamp",
4996
+ tool: "kb_stamp",
4997
+ usage: "stamp [--bundle PATH] [--since DIGEST|FILE]",
4998
+ description: "Content stamp of a base \u2014 `load`'s digest, record counts, per-record digests \u2014 without any bodies. Takes no bundlePath to stamp every pinned base. With `since`, reports only the bases that moved, naming the changed ids when the baseline is a prior stamp; silent when nothing changed. Reads, never writes.",
4999
+ input: import_zod25.z.object({
5000
+ bundlePath: import_zod25.z.string().min(1).optional().describe(
5001
+ "Absolute path to one knowledge base. Omit to stamp every pinned base."
5002
+ ),
5003
+ since: import_zod25.z.string().min(1).optional().describe(
5004
+ "Prior digest, or path to a prior `stamp --json`; only moved bases return, with changed ids when the baseline is a file."
5005
+ )
5006
+ }),
5007
+ fromArgv: (argv, path, _stdin, bundleExplicit) => {
5008
+ const since = argvFlag(argv, "--since");
5009
+ return {
5010
+ ...bundleExplicit ? { bundlePath: path } : {},
5011
+ ...since !== void 0 ? { since } : {}
5012
+ };
5013
+ },
5014
+ run: async ({ store }, { bundlePath: bundlePath2, since }) => {
5015
+ const targets = bundlePath2 ? [bundlePath2] : (await readMergedPins(process.cwd())).pins.map(
5016
+ (pin) => pin.absolutePath
5017
+ );
5018
+ if (since !== void 0 && DIGEST.test(since) && targets.length > 1) {
5019
+ throw new KbStampDigestBaselineError(since);
5020
+ }
5021
+ const stamps = await Promise.all(
5022
+ targets.map((target) => store.stamp(target))
5023
+ );
5024
+ if (since === void 0) {
5025
+ return stamps.map((stamp) => ({ ...stamp, changed: null }));
5026
+ }
5027
+ const baseline = await readBaseline(since);
5028
+ const reports = [];
5029
+ for (const stamp of stamps) {
5030
+ const before = baseline.byPath.get(stamp.path);
5031
+ if (baseline.digest !== null) {
5032
+ if (baseline.digest === stamp.digest) continue;
5033
+ reports.push({ ...stamp, changed: null });
5034
+ continue;
5035
+ }
5036
+ if (before && before.digest === stamp.digest) continue;
5037
+ reports.push({ ...stamp, changed: changedIds(before?.records, stamp) });
5038
+ }
5039
+ return reports;
5040
+ },
5041
+ render: (result) => result.map((report) => {
5042
+ const counts = `${report.recordCount} record(s), ${report.superseded} superseded`;
5043
+ const head = `${report.path} ${report.digest} ${counts}${report.newestAt ? ` newest ${report.newestAt}` : ""}`;
5044
+ return report.changed?.length ? `${head}
5045
+ changed: ${report.changed.join(", ")}` : head;
5046
+ }).join("\n")
5047
+ });
5048
+ function changedIds(before, stamp) {
5049
+ const now = new Map(
5050
+ stamp.records.map((record) => [record.conceptId, record.digest])
5051
+ );
5052
+ const ids = /* @__PURE__ */ new Set();
5053
+ for (const [conceptId2, digest] of now) {
5054
+ if (before?.get(conceptId2) !== digest) ids.add(conceptId2);
5055
+ }
5056
+ for (const conceptId2 of before?.keys() ?? []) {
5057
+ if (!now.has(conceptId2)) ids.add(conceptId2);
5058
+ }
5059
+ return [...ids].sort();
5060
+ }
5061
+ async function readBaseline(since) {
5062
+ if (DIGEST.test(since)) return { digest: since, byPath: /* @__PURE__ */ new Map() };
5063
+ let parsed;
5064
+ try {
5065
+ parsed = JSON.parse(await (0, import_promises7.readFile)(since, "utf8"));
5066
+ } catch {
5067
+ throw new KbStampBaselineError(since);
5068
+ }
5069
+ const entries = Array.isArray(parsed) ? parsed : parsed?.stamps ?? [];
5070
+ const byPath = /* @__PURE__ */ new Map();
5071
+ for (const entry of entries) {
5072
+ if (typeof entry?.path !== "string" || typeof entry?.digest !== "string") {
5073
+ continue;
5074
+ }
5075
+ byPath.set(entry.path, {
5076
+ digest: entry.digest,
5077
+ records: new Map(
5078
+ (entry.records ?? []).map((record) => [
5079
+ record.conceptId,
5080
+ record.digest
5081
+ ])
5082
+ )
5083
+ });
5084
+ }
5085
+ return { digest: null, byPath };
5086
+ }
5087
+
5088
+ // src/commands/status.ts
5089
+ var import_zod26 = require("zod");
4926
5090
  var statusCommand = define({
4927
5091
  name: "status",
4928
5092
  tool: "kb_status",
4929
5093
  usage: "status <concept-id> <status>",
4930
5094
  description: "Move a record's status. Compare-and-swap: a concurrent change fails instead of being overwritten.",
4931
- input: import_zod25.z.object({
5095
+ input: import_zod26.z.object({
4932
5096
  bundlePath,
4933
5097
  conceptId,
4934
- status: import_zod25.z.enum(KB_RECORD_STATUSES)
5098
+ status: import_zod26.z.enum(KB_RECORD_STATUSES)
4935
5099
  }),
4936
5100
  fromArgv: (argv, path) => ({
4937
5101
  bundlePath: path,
@@ -4946,13 +5110,13 @@ var statusCommand = define({
4946
5110
  });
4947
5111
 
4948
5112
  // src/commands/supersede.ts
4949
- var import_zod26 = require("zod");
5113
+ var import_zod27 = require("zod");
4950
5114
  var supersedeCommand = define({
4951
5115
  name: "supersede",
4952
5116
  tool: "kb_supersede",
4953
5117
  usage: "supersede <concept-id> <replacement-id>",
4954
5118
  description: "Mark a record superseded by another, linked in both directions. Use instead of editing a record whose meaning changed.",
4955
- input: import_zod26.z.object({ bundlePath, conceptId, replacementId: conceptId }),
5119
+ input: import_zod27.z.object({ bundlePath, conceptId, replacementId: conceptId }),
4956
5120
  fromArgv: (argv, path) => ({
4957
5121
  bundlePath: path,
4958
5122
  conceptId: argv[1],
@@ -4966,16 +5130,16 @@ var supersedeCommand = define({
4966
5130
  });
4967
5131
 
4968
5132
  // src/commands/sync-instructions.ts
4969
- var import_zod27 = require("zod");
5133
+ var import_zod28 = require("zod");
4970
5134
  var syncInstructionsCommand = define({
4971
5135
  name: "sync-instructions",
4972
5136
  usage: "sync-instructions <file> [--profile NAME] [--budget N] [--full-under N]",
4973
5137
  description: "CLI-only: plant the kb_context block between sentinel comments in AGENTS.md or CLAUDE.md, idempotently.",
4974
- input: import_zod27.z.object({
4975
- file: import_zod27.z.string().min(1).describe("The instruction file to edit in place."),
4976
- budgetTokens: import_zod27.z.number().int().positive().optional(),
4977
- fullUnderTokens: import_zod27.z.number().int().positive().optional(),
4978
- profile: import_zod27.z.string().optional()
5138
+ input: import_zod28.z.object({
5139
+ file: import_zod28.z.string().min(1).describe("The instruction file to edit in place."),
5140
+ budgetTokens: import_zod28.z.number().int().positive().optional(),
5141
+ fullUnderTokens: import_zod28.z.number().int().positive().optional(),
5142
+ profile: import_zod28.z.string().optional()
4979
5143
  }),
4980
5144
  fromArgv: (argv) => {
4981
5145
  const budget = argvFlag(argv, "--budget");
@@ -5001,17 +5165,17 @@ var syncInstructionsCommand = define({
5001
5165
  });
5002
5166
 
5003
5167
  // src/commands/trace.ts
5004
- var import_zod28 = require("zod");
5168
+ var import_zod29 = require("zod");
5005
5169
  var traceCommand = define({
5006
5170
  name: "trace",
5007
5171
  tool: "kb_trace",
5008
5172
  usage: "trace <concept-id> [edges...]",
5009
5173
  description: 'Timeline of how a position was reached, ordered by write time, following supersession, shared anchors and shared sources. Includes rejected, draft and superseded records \u2014 in a history they are the content. For "why is it like this"; kb_load answers "what holds now".',
5010
- input: import_zod28.z.object({
5174
+ input: import_zod29.z.object({
5011
5175
  bundlePath,
5012
5176
  conceptId,
5013
- edges: import_zod28.z.array(import_zod28.z.enum(TRACE_EDGES)).optional(),
5014
- depth: import_zod28.z.number().int().positive().optional()
5177
+ edges: import_zod29.z.array(import_zod29.z.enum(TRACE_EDGES)).optional(),
5178
+ depth: import_zod29.z.number().int().positive().optional()
5015
5179
  }),
5016
5180
  fromArgv: (argv, path) => ({
5017
5181
  bundlePath: path,
@@ -5033,37 +5197,37 @@ var traceCommand = define({
5033
5197
  });
5034
5198
 
5035
5199
  // src/commands/types.ts
5036
- var import_zod29 = require("zod");
5200
+ var import_zod30 = require("zod");
5037
5201
  var typesCommand = define({
5038
5202
  name: "types",
5039
5203
  tool: "kb_types",
5040
5204
  usage: "types",
5041
5205
  description: "The twelve record types with their purpose, body sections, and starting status. Read this before writing rather than guessing headings \u2014 a section the type does not define is rejected.",
5042
- input: import_zod29.z.object({}),
5206
+ input: import_zod30.z.object({}),
5043
5207
  fromArgv: () => ({}),
5044
5208
  run: () => Promise.resolve(RECORD_TYPES)
5045
5209
  });
5046
5210
 
5047
5211
  // src/commands/unpin.ts
5048
- var import_zod30 = require("zod");
5212
+ var import_zod31 = require("zod");
5049
5213
  var unpinCommand = define({
5050
5214
  name: "unpin",
5051
5215
  tool: "kb_unpin",
5052
5216
  usage: "unpin [bundle-path]",
5053
5217
  description: "Remove a base from every manifest layer that holds it. Reports the layers touched.",
5054
- input: import_zod30.z.object({ bundlePath }),
5218
+ input: import_zod31.z.object({ bundlePath }),
5055
5219
  fromArgv: (argv, path) => ({ bundlePath: argv[1] ?? path }),
5056
5220
  run: (_ctx, { bundlePath: path }) => unpinBase(process.cwd(), path)
5057
5221
  });
5058
5222
 
5059
5223
  // src/commands/validate.ts
5060
- var import_zod31 = require("zod");
5224
+ var import_zod32 = require("zod");
5061
5225
  var validateCommand = define({
5062
5226
  name: "validate",
5063
5227
  tool: "kb_validate",
5064
5228
  usage: "validate",
5065
5229
  description: "Check pointers no single record can see: supersession links that disagree between the two records, typed causal links, and assumptions that cite sources. Each finding carries a severity: errors fail the exit code, warnings do not.",
5066
- input: import_zod31.z.object({ bundlePath }),
5230
+ input: import_zod32.z.object({ bundlePath }),
5067
5231
  fromArgv: (_argv, path) => ({ bundlePath: path }),
5068
5232
  run: async ({ store }, { bundlePath: path }) => validateBundle(await store.list(path)),
5069
5233
  // Warnings never fail the exit code; every other severity does.
@@ -5073,16 +5237,16 @@ var validateCommand = define({
5073
5237
  });
5074
5238
 
5075
5239
  // src/commands/verify.ts
5076
- var import_zod32 = require("zod");
5240
+ var import_zod33 = require("zod");
5077
5241
  var verifyCommand = define({
5078
5242
  name: "verify",
5079
5243
  tool: "kb_verify",
5080
5244
  usage: "verify <concept-id> --note <text>",
5081
5245
  description: "Append a verified[] event: who checked, when, and what was found. Append-only. A record's own generator is refused unless the actor is `human:`-prefixed.",
5082
- input: import_zod32.z.object({
5246
+ input: import_zod33.z.object({
5083
5247
  bundlePath,
5084
5248
  conceptId,
5085
- note: import_zod32.z.string().refine((s) => s.trim().length > 0, {
5249
+ note: import_zod33.z.string().refine((s) => s.trim().length > 0, {
5086
5250
  message: "note must say what the check found"
5087
5251
  })
5088
5252
  }),
@@ -5102,15 +5266,15 @@ var verifyCommand = define({
5102
5266
  });
5103
5267
 
5104
5268
  // src/commands/write.ts
5105
- var import_zod33 = require("zod");
5269
+ var import_zod34 = require("zod");
5106
5270
  var writeCommand = define({
5107
5271
  name: "write",
5108
5272
  tool: "kb_write",
5109
5273
  usage: "write <type> < record.json",
5110
5274
  description: "Write one record. Search first \u2014 a duplicate concept id is rejected, not overwritten; kb_types lists each type's sections. An unsourced claim is an `assumption` with assumption: true, never a vague `fact`. Conflicting records get a `risk`, `open-question`, or superseding `decision`. Prefer a new short record over overloading one. Never delete; supersede.",
5111
- input: import_zod33.z.object({
5275
+ input: import_zod34.z.object({
5112
5276
  bundlePath,
5113
- type: import_zod33.z.enum(KB_RECORD_TYPES),
5277
+ type: import_zod34.z.enum(KB_RECORD_TYPES),
5114
5278
  input: composeInputSchema
5115
5279
  }),
5116
5280
  fromArgv: async (argv, path, stdin) => ({
@@ -5134,13 +5298,13 @@ var writeCommand = define({
5134
5298
  });
5135
5299
 
5136
5300
  // src/commands/write-decision.ts
5137
- var import_zod34 = require("zod");
5301
+ var import_zod35 = require("zod");
5138
5302
  var writeDecisionCommand = define({
5139
5303
  name: "write-decision",
5140
5304
  tool: "kb_write_decision",
5141
5305
  usage: "write-decision < decision.json",
5142
5306
  description: "Write a decision, with `alternative` (what was rejected and why) and `impact` as fields. Record one when a later reader would otherwise simplify the constraint away; skip when the diff already answers it. `sources` for material read, `anchors` for code, `relatedConceptIds` for records.",
5143
- input: import_zod34.z.object({ bundlePath, input: decisionInputSchema }),
5307
+ input: import_zod35.z.object({ bundlePath, input: decisionInputSchema }),
5144
5308
  fromArgv: async (_argv, path, stdin) => ({
5145
5309
  bundlePath: path,
5146
5310
  input: JSON.parse(await stdin())
@@ -5180,6 +5344,7 @@ var KB_COMMANDS = [
5180
5344
  listCommand,
5181
5345
  readIndexCommand,
5182
5346
  logCommand,
5347
+ stampCommand,
5183
5348
  validateCommand,
5184
5349
  doctorCommand,
5185
5350
  schemaCommand,
@@ -5199,7 +5364,7 @@ var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
5199
5364
  var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
5200
5365
 
5201
5366
  // src/version.ts
5202
- var VERSION = true ? "0.1.15" : "0.0.0-dev";
5367
+ var VERSION = true ? "0.1.16" : "0.0.0-dev";
5203
5368
 
5204
5369
  // src/mcp.ts
5205
5370
  function createKbMcpServer() {
@@ -5241,7 +5406,11 @@ async function runKbMcpServer() {
5241
5406
  var import_node_path9 = require("path");
5242
5407
  async function runKbCli(argv) {
5243
5408
  const { flags, literal } = takeLiteral(argv);
5244
- const { bundle, rest: withFlags } = takeBundle(flags);
5409
+ const {
5410
+ bundle,
5411
+ explicit: bundleExplicit,
5412
+ rest: withFlags
5413
+ } = takeBundle(flags);
5245
5414
  const name = withFlags[0] ?? "";
5246
5415
  if (!name || name === "-h" || name === "--help") {
5247
5416
  process.stdout.write(usage());
@@ -5262,7 +5431,7 @@ async function runKbCli(argv) {
5262
5431
  ...json ? withFlags.filter((argument) => argument !== "--json") : withFlags,
5263
5432
  ...literal
5264
5433
  ];
5265
- const raw = await command.fromArgv(rest, bundle, readStdin);
5434
+ const raw = await command.fromArgv(rest, bundle, readStdin, bundleExplicit);
5266
5435
  const parsed = command.input.safeParse(raw);
5267
5436
  if (!parsed.success) {
5268
5437
  die(
@@ -5284,6 +5453,7 @@ async function runKbCli(argv) {
5284
5453
  if (command.failsWhen?.(result, parsed.data)) process.exitCode = 1;
5285
5454
  if (result === "") return;
5286
5455
  const text = command.render && !json ? command.render(result) : typeof result === "string" ? result : JSON.stringify(result, null, 2);
5456
+ if (text === "") return;
5287
5457
  process.stdout.write(text.endsWith("\n") ? text : `${text}
5288
5458
  `);
5289
5459
  }
@@ -5295,11 +5465,15 @@ function takeLiteral(argv) {
5295
5465
  function takeBundle(argv) {
5296
5466
  const at = argv.indexOf("--bundle");
5297
5467
  if (at === -1) {
5298
- return { bundle: (0, import_node_path9.join)(process.cwd(), KB_DIR), rest: argv };
5468
+ return { bundle: (0, import_node_path9.join)(process.cwd(), KB_DIR), explicit: false, rest: argv };
5299
5469
  }
5300
5470
  const bundle = argv[at + 1];
5301
5471
  if (!bundle) die("--bundle requires a path");
5302
- return { bundle, rest: [...argv.slice(0, at), ...argv.slice(at + 2)] };
5472
+ return {
5473
+ bundle,
5474
+ explicit: true,
5475
+ rest: [...argv.slice(0, at), ...argv.slice(at + 2)]
5476
+ };
5303
5477
  }
5304
5478
  function readStdin() {
5305
5479
  return new Promise((resolve6, reject) => {