@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/README.md +17 -11
- package/dist/{chunk-KNIUBCZY.js → chunk-H5W53NVU.js} +225 -60
- package/dist/chunk-H5W53NVU.js.map +1 -0
- package/dist/{chunk-LACCRB2Y.js → chunk-MEZCF646.js} +2 -2
- package/dist/{chunk-MK7GU4DX.js → chunk-RINBOAQZ.js} +15 -6
- package/dist/chunk-RINBOAQZ.js.map +1 -0
- package/dist/cli-main.cjs +247 -75
- package/dist/cli-main.cjs.map +1 -1
- package/dist/cli-main.js +2 -2
- package/dist/index.cjs +231 -57
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +30 -2
- package/dist/index.d.ts +30 -2
- package/dist/index.js +3 -3
- package/dist/mcp-main.cjs +234 -71
- package/dist/mcp-main.cjs.map +1 -1
- package/dist/mcp-main.js +2 -2
- package/package.json +1 -1
- package/dist/chunk-KNIUBCZY.js.map +0 -1
- package/dist/chunk-MK7GU4DX.js.map +0 -1
- /package/dist/{chunk-LACCRB2Y.js.map → chunk-MEZCF646.js.map} +0 -0
package/dist/cli-main.js
CHANGED
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
|
|
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,
|
|
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 ||
|
|
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/
|
|
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:
|
|
5095
|
+
input: import_zod26.z.object({
|
|
4932
5096
|
bundlePath,
|
|
4933
5097
|
conceptId,
|
|
4934
|
-
status:
|
|
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
|
|
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:
|
|
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
|
|
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:
|
|
4975
|
-
file:
|
|
4976
|
-
budgetTokens:
|
|
4977
|
-
fullUnderTokens:
|
|
4978
|
-
profile:
|
|
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
|
|
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:
|
|
5174
|
+
input: import_zod29.z.object({
|
|
5011
5175
|
bundlePath,
|
|
5012
5176
|
conceptId,
|
|
5013
|
-
edges:
|
|
5014
|
-
depth:
|
|
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
|
|
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:
|
|
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
|
|
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:
|
|
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
|
|
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:
|
|
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
|
|
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:
|
|
5246
|
+
input: import_zod33.z.object({
|
|
5083
5247
|
bundlePath,
|
|
5084
5248
|
conceptId,
|
|
5085
|
-
note:
|
|
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
|
|
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:
|
|
5275
|
+
input: import_zod34.z.object({
|
|
5112
5276
|
bundlePath,
|
|
5113
|
-
type:
|
|
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
|
|
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:
|
|
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.
|
|
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 {
|
|
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 {
|
|
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) => {
|