@saasontools/strauss-kb 0.1.22 → 0.1.23
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 +4 -3
- package/dist/{chunk-TSE4YQEG.js → chunk-3EZ3PAPA.js} +2 -2
- package/dist/{chunk-DVSPHL4B.js → chunk-5IPQVXCM.js} +2 -2
- package/dist/{chunk-AEO5U42S.js → chunk-XENLCPL5.js} +460 -367
- package/dist/chunk-XENLCPL5.js.map +1 -0
- package/dist/cli-main.cjs +530 -437
- package/dist/cli-main.cjs.map +1 -1
- package/dist/cli-main.js +2 -2
- package/dist/index.cjs +452 -361
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +38 -3
- package/dist/index.d.ts +38 -3
- package/dist/index.js +3 -3
- package/dist/mcp-main.cjs +530 -437
- package/dist/mcp-main.cjs.map +1 -1
- package/dist/mcp-main.js +2 -2
- package/package.json +1 -1
- package/dist/chunk-AEO5U42S.js.map +0 -1
- /package/dist/{chunk-TSE4YQEG.js.map → chunk-3EZ3PAPA.js.map} +0 -0
- /package/dist/{chunk-DVSPHL4B.js.map → chunk-5IPQVXCM.js.map} +0 -0
package/dist/index.cjs
CHANGED
|
@@ -5767,8 +5767,8 @@ function selectDecisions(records) {
|
|
|
5767
5767
|
);
|
|
5768
5768
|
}
|
|
5769
5769
|
|
|
5770
|
-
// src/commands/anchor-resolve.ts
|
|
5771
|
-
var
|
|
5770
|
+
// src/commands/anchor-resolve/command.ts
|
|
5771
|
+
var import_zod10 = require("zod");
|
|
5772
5772
|
|
|
5773
5773
|
// src/commands/model.ts
|
|
5774
5774
|
var import_zod8 = require("zod");
|
|
@@ -5834,26 +5834,270 @@ function argvPositional(argv, ...names) {
|
|
|
5834
5834
|
);
|
|
5835
5835
|
}
|
|
5836
5836
|
|
|
5837
|
-
// src/commands/anchor-resolve.ts
|
|
5837
|
+
// src/commands/anchor-resolve/apply.ts
|
|
5838
|
+
var import_zod9 = require("zod");
|
|
5839
|
+
async function baseFrozen(cwd, bundlePath2) {
|
|
5840
|
+
try {
|
|
5841
|
+
await assertBaseNotFrozen(cwd, bundlePath2);
|
|
5842
|
+
return false;
|
|
5843
|
+
} catch (caught) {
|
|
5844
|
+
if (!(caught instanceof KbBaseFrozenError)) throw caught;
|
|
5845
|
+
return true;
|
|
5846
|
+
}
|
|
5847
|
+
}
|
|
5848
|
+
async function applyPlan(plans, target) {
|
|
5849
|
+
if (!plans.some((plan) => plan.write)) {
|
|
5850
|
+
return { results: plans.map((plan) => plan.finding) };
|
|
5851
|
+
}
|
|
5852
|
+
let failure = target.frozen ? "frozen" : void 0;
|
|
5853
|
+
let error;
|
|
5854
|
+
if (!failure) {
|
|
5855
|
+
try {
|
|
5856
|
+
await target.store.updateAnchors(
|
|
5857
|
+
target.bundlePath,
|
|
5858
|
+
target.conceptId,
|
|
5859
|
+
plans.map((plan) => plan.anchor),
|
|
5860
|
+
target.actor
|
|
5861
|
+
);
|
|
5862
|
+
} catch (caught) {
|
|
5863
|
+
if (caught instanceof BaseError || caught instanceof import_zod9.z.ZodError) {
|
|
5864
|
+
throw caught;
|
|
5865
|
+
}
|
|
5866
|
+
failure = "write-failed";
|
|
5867
|
+
error = clamp(caught instanceof Error ? caught.message : String(caught));
|
|
5868
|
+
}
|
|
5869
|
+
}
|
|
5870
|
+
return {
|
|
5871
|
+
results: plans.map((plan) => settle(plan, failure)),
|
|
5872
|
+
...error ? { error } : {}
|
|
5873
|
+
};
|
|
5874
|
+
}
|
|
5875
|
+
function settle(plan, failure) {
|
|
5876
|
+
if (!plan.write) return plan.finding;
|
|
5877
|
+
if (failure) {
|
|
5878
|
+
return { ...plan.finding, outcome: "failed", outcomeReason: failure };
|
|
5879
|
+
}
|
|
5880
|
+
if (plan.write === "refresh") return plan.finding;
|
|
5881
|
+
return plan.write === "stamp" ? { ...plan.finding, state: "stamped", outcome: "applied" } : { ...plan.finding, outcome: "applied", rebaselined: true };
|
|
5882
|
+
}
|
|
5883
|
+
function clamp(message) {
|
|
5884
|
+
const line = message.split("\n")[0] ?? "";
|
|
5885
|
+
return line.length > 200 ? `${line.slice(0, 199)}\u2026` : line;
|
|
5886
|
+
}
|
|
5887
|
+
|
|
5888
|
+
// src/commands/anchor-resolve/sources.ts
|
|
5889
|
+
async function readSources(anchors, root, offline) {
|
|
5890
|
+
const origin = new LazyOrigin(root);
|
|
5891
|
+
if (anchors.some((anchor) => anchor.repo)) await origin.prime();
|
|
5892
|
+
const foreign = new Map(
|
|
5893
|
+
anchors.map((anchor) => [anchor, origin.isForeign(anchor)])
|
|
5894
|
+
);
|
|
5895
|
+
const local = anchors.filter(
|
|
5896
|
+
(anchor) => !foreign.get(anchor) && anchor.side !== "old"
|
|
5897
|
+
);
|
|
5898
|
+
const committed = anchors.filter(
|
|
5899
|
+
(anchor) => !foreign.get(anchor) && anchor.side === "old"
|
|
5900
|
+
);
|
|
5901
|
+
const remote = anchors.filter((anchor) => foreign.get(anchor));
|
|
5902
|
+
const reads = await readAnchorFiles(
|
|
5903
|
+
local.map((anchor) => anchor.file),
|
|
5904
|
+
anchorFileReader(root)
|
|
5905
|
+
);
|
|
5906
|
+
const atRef = await readCommitted(root, committed);
|
|
5907
|
+
const blobs = await readRemoteAnchors(remote.flatMap(remoteWants), {
|
|
5908
|
+
offline
|
|
5909
|
+
});
|
|
5910
|
+
const sources = /* @__PURE__ */ new Map();
|
|
5911
|
+
for (const anchor of local) {
|
|
5912
|
+
const read = reads.get(anchor.file);
|
|
5913
|
+
sources.set(
|
|
5914
|
+
anchor,
|
|
5915
|
+
read.ok ? { ok: true, source: read.source } : { ok: false, reason: read.reason }
|
|
5916
|
+
);
|
|
5917
|
+
}
|
|
5918
|
+
for (const anchor of committed) {
|
|
5919
|
+
const read = atRef.get(atRefKey(anchor));
|
|
5920
|
+
sources.set(
|
|
5921
|
+
anchor,
|
|
5922
|
+
read.ok ? { ok: true, source: read.source } : { ok: false, reason: read.reason }
|
|
5923
|
+
);
|
|
5924
|
+
}
|
|
5925
|
+
for (const anchor of remote) {
|
|
5926
|
+
const repo = anchor.repo;
|
|
5927
|
+
const key2 = normalizeRepoUrl(repo);
|
|
5928
|
+
const atDefault = blobs.get(wantKey(key2, void 0, anchor.file));
|
|
5929
|
+
const primary = anchor.ref ? blobs.get(wantKey(key2, anchor.ref, anchor.file)) : atDefault;
|
|
5930
|
+
if (!primary?.ok) {
|
|
5931
|
+
sources.set(anchor, {
|
|
5932
|
+
ok: false,
|
|
5933
|
+
reason: primary?.ok === false ? primary.reason : "remote-unreachable",
|
|
5934
|
+
repo
|
|
5935
|
+
});
|
|
5936
|
+
continue;
|
|
5937
|
+
}
|
|
5938
|
+
sources.set(anchor, {
|
|
5939
|
+
ok: true,
|
|
5940
|
+
source: primary.source,
|
|
5941
|
+
repo,
|
|
5942
|
+
...anchor.ref && atDefault?.ok ? { head: atDefault.source } : {}
|
|
5943
|
+
});
|
|
5944
|
+
}
|
|
5945
|
+
return sources;
|
|
5946
|
+
}
|
|
5947
|
+
|
|
5948
|
+
// src/commands/anchor-resolve/plan.ts
|
|
5949
|
+
async function planAnchors(anchors, options) {
|
|
5950
|
+
const { root, offline, rebaseline, restamp, check, frozen, now } = options;
|
|
5951
|
+
const sources = await readSources(anchors, root, offline);
|
|
5952
|
+
const resolvers = defaultAnchorResolvers({ offline });
|
|
5953
|
+
await prepareResolvers(
|
|
5954
|
+
resolvers,
|
|
5955
|
+
anchors.map((anchor) => anchor.file)
|
|
5956
|
+
);
|
|
5957
|
+
const plans = [];
|
|
5958
|
+
for (const anchor of anchors) {
|
|
5959
|
+
const base2 = {
|
|
5960
|
+
file: anchor.file,
|
|
5961
|
+
...anchor.symbol ? { symbol: anchor.symbol } : {},
|
|
5962
|
+
...anchor.side === "old" ? { side: "old" } : {},
|
|
5963
|
+
// Carried onto unresolved findings too: an anchor that once hashed
|
|
5964
|
+
// and now resolves to nothing is a broken anchor, and the exit code
|
|
5965
|
+
// has to be able to tell it from one nobody ever stamped.
|
|
5966
|
+
...anchor.hash ? { storedHash: anchor.hash } : {}
|
|
5967
|
+
};
|
|
5968
|
+
const source = sources.get(anchor);
|
|
5969
|
+
if (source.repo) base2.repo = source.repo;
|
|
5970
|
+
if (!source.ok) {
|
|
5971
|
+
plans.push({
|
|
5972
|
+
finding: { ...base2, state: "unresolved", reason: source.reason },
|
|
5973
|
+
anchor
|
|
5974
|
+
});
|
|
5975
|
+
continue;
|
|
5976
|
+
}
|
|
5977
|
+
const outcome = resolveAnchorSpan(source.source, anchor, resolvers);
|
|
5978
|
+
if (!outcome.ok) {
|
|
5979
|
+
plans.push({
|
|
5980
|
+
finding: { ...base2, state: "unresolved", reason: outcome.reason },
|
|
5981
|
+
anchor
|
|
5982
|
+
});
|
|
5983
|
+
continue;
|
|
5984
|
+
}
|
|
5985
|
+
const resolved = outcome.span;
|
|
5986
|
+
const producedBy = outcome.resolver;
|
|
5987
|
+
const { hash: currentHash, kind } = anchorHashOf(anchor, outcome);
|
|
5988
|
+
const currentLines = resolved.endLine - resolved.startLine + 1;
|
|
5989
|
+
const stampedKind = outcome.normalized ? "ast" : "raw";
|
|
5990
|
+
const stampedHash = outcome.normalized ? anchorHashOf({ ...anchor, hash: void 0 }, outcome).hash : currentHash;
|
|
5991
|
+
const stamped = {
|
|
5992
|
+
...anchor,
|
|
5993
|
+
hash: stampedHash,
|
|
5994
|
+
hash_kind: stampedKind,
|
|
5995
|
+
lines: currentLines,
|
|
5996
|
+
resolved_at: now(),
|
|
5997
|
+
...producedBy ? { resolver: producedBy } : {}
|
|
5998
|
+
};
|
|
5999
|
+
const pinned = anchor.ref !== void 0 && source.repo !== void 0;
|
|
6000
|
+
if (!anchor.hash) {
|
|
6001
|
+
plans.push({
|
|
6002
|
+
finding: {
|
|
6003
|
+
...base2,
|
|
6004
|
+
state: "unstamped",
|
|
6005
|
+
currentHash: stampedHash,
|
|
6006
|
+
hashKind: stampedKind,
|
|
6007
|
+
...producedBy ? { resolver: producedBy } : {}
|
|
6008
|
+
},
|
|
6009
|
+
anchor: check ? anchor : stamped,
|
|
6010
|
+
...check ? {} : { write: "stamp" }
|
|
6011
|
+
});
|
|
6012
|
+
continue;
|
|
6013
|
+
}
|
|
6014
|
+
if (anchor.hash !== currentHash) {
|
|
6015
|
+
plans.push({
|
|
6016
|
+
finding: {
|
|
6017
|
+
...base2,
|
|
6018
|
+
state: "drifted",
|
|
6019
|
+
currentHash,
|
|
6020
|
+
hashKind: kind,
|
|
6021
|
+
diffSize: lineDelta(anchor, currentLines),
|
|
6022
|
+
...producedBy ? { resolver: producedBy } : {},
|
|
6023
|
+
// A regex-stamped anchor re-read by tree-sitter drifts because the
|
|
6024
|
+
// resolver changed, not because the code did.
|
|
6025
|
+
...resolverChanged(source.source, anchor, producedBy) ? { reason: "resolver-changed" } : {},
|
|
6026
|
+
...pinned ? { remoteState: "drifted-from-ref" } : {}
|
|
6027
|
+
},
|
|
6028
|
+
anchor: rebaseline && !check ? stamped : anchor,
|
|
6029
|
+
...rebaseline && !check ? { write: "rebaseline" } : {}
|
|
6030
|
+
});
|
|
6031
|
+
continue;
|
|
6032
|
+
}
|
|
6033
|
+
const onDefault = pinned ? headHash(source, anchor, resolvers) : void 0;
|
|
6034
|
+
if (onDefault && onDefault.hash !== anchor.hash) {
|
|
6035
|
+
plans.push({
|
|
6036
|
+
finding: {
|
|
6037
|
+
...base2,
|
|
6038
|
+
state: "drifted",
|
|
6039
|
+
currentHash: onDefault.hash,
|
|
6040
|
+
diffSize: lineDelta(anchor, onDefault.lines),
|
|
6041
|
+
remoteState: "drifted-on-default",
|
|
6042
|
+
...rebaseline ? {
|
|
6043
|
+
outcome: "skipped",
|
|
6044
|
+
outcomeReason: "pinned-ref"
|
|
6045
|
+
} : {}
|
|
6046
|
+
},
|
|
6047
|
+
anchor
|
|
6048
|
+
});
|
|
6049
|
+
continue;
|
|
6050
|
+
}
|
|
6051
|
+
const backfill = anchor.resolved_at === void 0 && !frozen;
|
|
6052
|
+
const refresh = !check && (restamp || backfill);
|
|
6053
|
+
plans.push({
|
|
6054
|
+
finding: {
|
|
6055
|
+
...base2,
|
|
6056
|
+
state: "match",
|
|
6057
|
+
currentHash,
|
|
6058
|
+
hashKind: kind,
|
|
6059
|
+
...producedBy ? { resolver: producedBy } : {},
|
|
6060
|
+
...pinned ? { remoteState: "matches-ref" } : {}
|
|
6061
|
+
},
|
|
6062
|
+
anchor: refresh ? { ...anchor, resolved_at: now() } : anchor,
|
|
6063
|
+
...refresh ? { write: "refresh" } : {}
|
|
6064
|
+
});
|
|
6065
|
+
}
|
|
6066
|
+
return plans;
|
|
6067
|
+
}
|
|
6068
|
+
function lineDelta(anchor, current) {
|
|
6069
|
+
return anchor.lines === void 0 ? null : Math.abs(current - anchor.lines);
|
|
6070
|
+
}
|
|
6071
|
+
function headHash(source, anchor, resolvers) {
|
|
6072
|
+
if (source.head === void 0) return void 0;
|
|
6073
|
+
const outcome = resolveAnchorSpan(source.head, anchor, resolvers);
|
|
6074
|
+
if (!outcome.ok) return void 0;
|
|
6075
|
+
return {
|
|
6076
|
+
hash: hashAnchorText(outcome.span.text),
|
|
6077
|
+
lines: outcome.span.endLine - outcome.span.startLine + 1
|
|
6078
|
+
};
|
|
6079
|
+
}
|
|
6080
|
+
|
|
6081
|
+
// src/commands/anchor-resolve/command.ts
|
|
5838
6082
|
var anchorResolveCommand = define({
|
|
5839
6083
|
name: "anchor-resolve",
|
|
5840
6084
|
tool: "kb_anchor_resolve",
|
|
5841
6085
|
usage: "anchor-resolve <concept-id> [--repo-root <path>] [--offline] [--rebaseline] [--restamp] [--check]",
|
|
5842
|
-
description: "Resolve a record's anchors: stamp a hash onto anchors that lack one, report drift where the code moved. An anchor naming another repository is read from that remote through a bare cache; --offline uses the cache only. Never writes verified[]; a judgment is kb_verify.
|
|
5843
|
-
input:
|
|
6086
|
+
description: "Resolve a record's anchors: stamp a hash onto anchors that lack one, report drift where the code moved. An anchor naming another repository is read from that remote through a bare cache; --offline uses the cache only. Never writes verified[]; a judgment is kb_verify. Each result says what it compared and whether the write applied.",
|
|
6087
|
+
input: import_zod10.z.object({
|
|
5844
6088
|
bundlePath,
|
|
5845
6089
|
conceptId,
|
|
5846
|
-
repoRoot:
|
|
5847
|
-
offline:
|
|
6090
|
+
repoRoot: import_zod10.z.string().min(1).optional(),
|
|
6091
|
+
offline: import_zod10.z.boolean().optional().describe(
|
|
5848
6092
|
"Resolve foreign anchors from the local repo cache only, never fetching."
|
|
5849
6093
|
),
|
|
5850
|
-
rebaseline:
|
|
6094
|
+
rebaseline: import_zod10.z.boolean().optional().describe(
|
|
5851
6095
|
"Accept the current code as the new baseline for anchors that drifted."
|
|
5852
6096
|
),
|
|
5853
|
-
restamp:
|
|
6097
|
+
restamp: import_zod10.z.boolean().optional().describe(
|
|
5854
6098
|
"Refresh `resolved_at` on anchors that already match. Off by default, so a green run writes nothing."
|
|
5855
6099
|
),
|
|
5856
|
-
check:
|
|
6100
|
+
check: import_zod10.z.boolean().optional().describe(
|
|
5857
6101
|
"Resolve and report only: no hash, no `resolved_at`, no log entry."
|
|
5858
6102
|
)
|
|
5859
6103
|
}),
|
|
@@ -5892,246 +6136,87 @@ var anchorResolveCommand = define({
|
|
|
5892
6136
|
note: "record has no anchors"
|
|
5893
6137
|
};
|
|
5894
6138
|
}
|
|
5895
|
-
const
|
|
5896
|
-
const
|
|
5897
|
-
|
|
5898
|
-
|
|
5899
|
-
|
|
5900
|
-
|
|
5901
|
-
|
|
5902
|
-
|
|
5903
|
-
|
|
5904
|
-
|
|
5905
|
-
|
|
5906
|
-
|
|
5907
|
-
|
|
5908
|
-
|
|
5909
|
-
|
|
5910
|
-
|
|
5911
|
-
|
|
5912
|
-
|
|
5913
|
-
|
|
5914
|
-
const source = sources.get(anchor);
|
|
5915
|
-
if (source.repo) base2.repo = source.repo;
|
|
5916
|
-
if (!source.ok) {
|
|
5917
|
-
results.push({ ...base2, state: "unresolved", reason: source.reason });
|
|
5918
|
-
updated.push(anchor);
|
|
5919
|
-
continue;
|
|
5920
|
-
}
|
|
5921
|
-
const outcome = resolveAnchorSpan(source.source, anchor, resolvers);
|
|
5922
|
-
if (!outcome.ok) {
|
|
5923
|
-
results.push({
|
|
5924
|
-
...base2,
|
|
5925
|
-
state: "unresolved",
|
|
5926
|
-
reason: outcome.reason
|
|
5927
|
-
});
|
|
5928
|
-
updated.push(anchor);
|
|
5929
|
-
continue;
|
|
5930
|
-
}
|
|
5931
|
-
const resolved = outcome.span;
|
|
5932
|
-
const producedBy = outcome.resolver;
|
|
5933
|
-
const { hash: currentHash, kind } = anchorHashOf(anchor, outcome);
|
|
5934
|
-
const currentLines = resolved.endLine - resolved.startLine + 1;
|
|
5935
|
-
const stampedKind = outcome.normalized ? "ast" : "raw";
|
|
5936
|
-
const stampedHash = outcome.normalized ? anchorHashOf({ ...anchor, hash: void 0 }, outcome).hash : currentHash;
|
|
5937
|
-
const stamped = {
|
|
5938
|
-
...anchor,
|
|
5939
|
-
hash: stampedHash,
|
|
5940
|
-
hash_kind: stampedKind,
|
|
5941
|
-
lines: currentLines,
|
|
5942
|
-
resolved_at: now(),
|
|
5943
|
-
...producedBy ? { resolver: producedBy } : {}
|
|
5944
|
-
};
|
|
5945
|
-
const pinned = anchor.ref !== void 0 && source.repo !== void 0;
|
|
5946
|
-
if (!anchor.hash) {
|
|
5947
|
-
results.push({
|
|
5948
|
-
...base2,
|
|
5949
|
-
state: check ? "unstamped" : "stamped",
|
|
5950
|
-
currentHash: stampedHash,
|
|
5951
|
-
hashKind: stampedKind,
|
|
5952
|
-
...producedBy ? { resolver: producedBy } : {}
|
|
5953
|
-
});
|
|
5954
|
-
updated.push(stamped);
|
|
5955
|
-
dirty = true;
|
|
5956
|
-
continue;
|
|
5957
|
-
}
|
|
5958
|
-
if (anchor.hash !== currentHash) {
|
|
5959
|
-
results.push({
|
|
5960
|
-
...base2,
|
|
5961
|
-
state: "drifted",
|
|
5962
|
-
currentHash,
|
|
5963
|
-
hashKind: kind,
|
|
5964
|
-
diffSize: lineDelta(anchor, currentLines),
|
|
5965
|
-
...producedBy ? { resolver: producedBy } : {},
|
|
5966
|
-
// A regex-stamped anchor re-read by tree-sitter drifts because the
|
|
5967
|
-
// resolver changed, not because the code did.
|
|
5968
|
-
...resolverChanged(source.source, anchor, producedBy) ? { reason: "resolver-changed" } : {},
|
|
5969
|
-
...pinned ? { remoteState: "drifted-from-ref" } : {},
|
|
5970
|
-
...rebaseline ? { rebaselined: true } : {}
|
|
5971
|
-
});
|
|
5972
|
-
updated.push(rebaseline ? stamped : anchor);
|
|
5973
|
-
if (rebaseline) dirty = true;
|
|
5974
|
-
continue;
|
|
5975
|
-
}
|
|
5976
|
-
const onDefault = pinned ? headHash(source, anchor, resolvers) : void 0;
|
|
5977
|
-
if (onDefault && onDefault.hash !== anchor.hash) {
|
|
5978
|
-
results.push({
|
|
5979
|
-
...base2,
|
|
5980
|
-
state: "drifted",
|
|
5981
|
-
currentHash: onDefault.hash,
|
|
5982
|
-
diffSize: lineDelta(anchor, onDefault.lines),
|
|
5983
|
-
remoteState: "drifted-on-default"
|
|
5984
|
-
});
|
|
5985
|
-
updated.push(anchor);
|
|
5986
|
-
continue;
|
|
5987
|
-
}
|
|
5988
|
-
results.push({
|
|
5989
|
-
...base2,
|
|
5990
|
-
state: "match",
|
|
5991
|
-
currentHash,
|
|
5992
|
-
hashKind: kind,
|
|
5993
|
-
...producedBy ? { resolver: producedBy } : {},
|
|
5994
|
-
...pinned ? { remoteState: "matches-ref" } : {}
|
|
5995
|
-
});
|
|
5996
|
-
const refresh = restamp || anchor.resolved_at === void 0;
|
|
5997
|
-
updated.push(refresh ? { ...anchor, resolved_at: now() } : anchor);
|
|
5998
|
-
if (refresh) dirty = true;
|
|
5999
|
-
}
|
|
6000
|
-
let frozen = false;
|
|
6001
|
-
if (dirty && !check) {
|
|
6002
|
-
try {
|
|
6003
|
-
await assertBaseNotFrozen(process.cwd(), path);
|
|
6004
|
-
} catch (error) {
|
|
6005
|
-
if (!(error instanceof KbBaseFrozenError)) throw error;
|
|
6006
|
-
frozen = true;
|
|
6007
|
-
}
|
|
6008
|
-
if (!frozen) await store.updateAnchors(path, id, updated, actor);
|
|
6009
|
-
}
|
|
6010
|
-
const frozenNote = frozen ? { frozen: true, note: "base is frozen: nothing was stamped" } : {};
|
|
6139
|
+
const frozen = check ? false : await baseFrozen(process.cwd(), path);
|
|
6140
|
+
const plans = await planAnchors(anchors, {
|
|
6141
|
+
root,
|
|
6142
|
+
offline: offline === true,
|
|
6143
|
+
rebaseline: rebaseline === true,
|
|
6144
|
+
restamp: restamp === true,
|
|
6145
|
+
check: check === true,
|
|
6146
|
+
frozen,
|
|
6147
|
+
now
|
|
6148
|
+
});
|
|
6149
|
+
const applied = await applyPlan(plans, {
|
|
6150
|
+
store,
|
|
6151
|
+
actor,
|
|
6152
|
+
bundlePath: path,
|
|
6153
|
+
conceptId: id,
|
|
6154
|
+
frozen
|
|
6155
|
+
});
|
|
6156
|
+
const results = applied.results;
|
|
6157
|
+
const refused = frozen && plans.some((plan) => plan.write);
|
|
6011
6158
|
const hints = grammarHints();
|
|
6012
6159
|
const hintNote = hints.length ? { hints } : {};
|
|
6013
6160
|
const unreachable = results.filter(
|
|
6014
6161
|
(entry) => isUncheckedReason(entry.reason)
|
|
6015
6162
|
).length;
|
|
6016
6163
|
const matches3 = results.filter((entry) => entry.state === "match").length;
|
|
6017
|
-
const note =
|
|
6164
|
+
const note = [
|
|
6165
|
+
unreachable ? `${matches3}/${results.length - unreachable} anchors match, ${unreachable} unreachable` : "",
|
|
6166
|
+
refused ? "base is frozen: nothing was stamped" : "",
|
|
6167
|
+
applied.error ? `nothing was written: ${applied.error}` : ""
|
|
6168
|
+
].filter(Boolean).join("; ");
|
|
6018
6169
|
return {
|
|
6019
6170
|
conceptId: id,
|
|
6020
6171
|
results,
|
|
6021
|
-
...
|
|
6022
|
-
...
|
|
6172
|
+
...note ? { note } : {},
|
|
6173
|
+
...refused ? { frozen: true } : {},
|
|
6023
6174
|
...hintNote
|
|
6024
6175
|
};
|
|
6025
6176
|
},
|
|
6177
|
+
// Drift is a finding until a write settles it: a rebaseline the base took is
|
|
6178
|
+
// the answer to the drift it reports, while one refused, skipped, or never
|
|
6179
|
+
// asked for leaves the gate exactly what it was meant to catch.
|
|
6180
|
+
//
|
|
6026
6181
|
// A stored hash that no longer resolves is a broken anchor, not an absence:
|
|
6027
|
-
// the file was deleted or the symbol renamed
|
|
6028
|
-
//
|
|
6029
|
-
//
|
|
6030
|
-
//
|
|
6031
|
-
// would gate on work this command did not do.
|
|
6182
|
+
// the file was deleted or the symbol renamed. An anchor nobody ever stamped
|
|
6183
|
+
// is still just unstamped, and one whose remote nothing could reach was
|
|
6184
|
+
// never checked — failing CI on either would gate on work this command did
|
|
6185
|
+
// not do.
|
|
6032
6186
|
failsWhen: (result) => result.results.some(
|
|
6033
|
-
(entry) => entry.state === "drifted" || entry.state === "unresolved" && entry.storedHash !== void 0 && !isUncheckedReason(entry.reason)
|
|
6187
|
+
(entry) => entry.outcome === "failed" || entry.outcome === "skipped" || entry.state === "drifted" && entry.outcome !== "applied" || entry.state === "unresolved" && entry.storedHash !== void 0 && !isUncheckedReason(entry.reason)
|
|
6034
6188
|
)
|
|
6035
6189
|
});
|
|
6036
|
-
function lineDelta(anchor, current) {
|
|
6037
|
-
return anchor.lines === void 0 ? null : Math.abs(current - anchor.lines);
|
|
6038
|
-
}
|
|
6039
|
-
function headHash(source, anchor, resolvers) {
|
|
6040
|
-
if (source.head === void 0) return void 0;
|
|
6041
|
-
const outcome = resolveAnchorSpan(source.head, anchor, resolvers);
|
|
6042
|
-
if (!outcome.ok) return void 0;
|
|
6043
|
-
return {
|
|
6044
|
-
hash: hashAnchorText(outcome.span.text),
|
|
6045
|
-
lines: outcome.span.endLine - outcome.span.startLine + 1
|
|
6046
|
-
};
|
|
6047
|
-
}
|
|
6048
|
-
async function readSources(anchors, root, offline) {
|
|
6049
|
-
const origin = new LazyOrigin(root);
|
|
6050
|
-
if (anchors.some((anchor) => anchor.repo)) await origin.prime();
|
|
6051
|
-
const foreign = new Map(
|
|
6052
|
-
anchors.map((anchor) => [anchor, origin.isForeign(anchor)])
|
|
6053
|
-
);
|
|
6054
|
-
const local = anchors.filter(
|
|
6055
|
-
(anchor) => !foreign.get(anchor) && anchor.side !== "old"
|
|
6056
|
-
);
|
|
6057
|
-
const committed = anchors.filter(
|
|
6058
|
-
(anchor) => !foreign.get(anchor) && anchor.side === "old"
|
|
6059
|
-
);
|
|
6060
|
-
const remote = anchors.filter((anchor) => foreign.get(anchor));
|
|
6061
|
-
const reads = await readAnchorFiles(
|
|
6062
|
-
local.map((anchor) => anchor.file),
|
|
6063
|
-
anchorFileReader(root)
|
|
6064
|
-
);
|
|
6065
|
-
const atRef = await readCommitted(root, committed);
|
|
6066
|
-
const blobs = await readRemoteAnchors(remote.flatMap(remoteWants), {
|
|
6067
|
-
offline
|
|
6068
|
-
});
|
|
6069
|
-
const sources = /* @__PURE__ */ new Map();
|
|
6070
|
-
for (const anchor of local) {
|
|
6071
|
-
const read = reads.get(anchor.file);
|
|
6072
|
-
sources.set(
|
|
6073
|
-
anchor,
|
|
6074
|
-
read.ok ? { ok: true, source: read.source } : { ok: false, reason: read.reason }
|
|
6075
|
-
);
|
|
6076
|
-
}
|
|
6077
|
-
for (const anchor of committed) {
|
|
6078
|
-
const read = atRef.get(atRefKey(anchor));
|
|
6079
|
-
sources.set(
|
|
6080
|
-
anchor,
|
|
6081
|
-
read.ok ? { ok: true, source: read.source } : { ok: false, reason: read.reason }
|
|
6082
|
-
);
|
|
6083
|
-
}
|
|
6084
|
-
for (const anchor of remote) {
|
|
6085
|
-
const repo = anchor.repo;
|
|
6086
|
-
const key2 = normalizeRepoUrl(repo);
|
|
6087
|
-
const atDefault = blobs.get(wantKey(key2, void 0, anchor.file));
|
|
6088
|
-
const primary = anchor.ref ? blobs.get(wantKey(key2, anchor.ref, anchor.file)) : atDefault;
|
|
6089
|
-
if (!primary?.ok) {
|
|
6090
|
-
sources.set(anchor, {
|
|
6091
|
-
ok: false,
|
|
6092
|
-
reason: primary?.ok === false ? primary.reason : "remote-unreachable",
|
|
6093
|
-
repo
|
|
6094
|
-
});
|
|
6095
|
-
continue;
|
|
6096
|
-
}
|
|
6097
|
-
sources.set(anchor, {
|
|
6098
|
-
ok: true,
|
|
6099
|
-
source: primary.source,
|
|
6100
|
-
repo,
|
|
6101
|
-
...anchor.ref && atDefault?.ok ? { head: atDefault.source } : {}
|
|
6102
|
-
});
|
|
6103
|
-
}
|
|
6104
|
-
return sources;
|
|
6105
|
-
}
|
|
6106
6190
|
|
|
6107
6191
|
// src/commands/anchor-set/model.ts
|
|
6108
|
-
var
|
|
6109
|
-
var anchorSetInputSchema =
|
|
6110
|
-
reason:
|
|
6192
|
+
var import_zod11 = require("zod");
|
|
6193
|
+
var anchorSetInputSchema = import_zod11.z.object({
|
|
6194
|
+
reason: import_zod11.z.string().refine((text) => text.trim().length > 0, {
|
|
6111
6195
|
message: "reason must say what was reviewed"
|
|
6112
6196
|
}).describe(
|
|
6113
6197
|
"What the reviewer read that makes these the right pointers. Recorded in the log."
|
|
6114
6198
|
),
|
|
6115
|
-
anchors:
|
|
6199
|
+
anchors: import_zod11.z.array(kbAnchorWriteSchema).min(1).describe(
|
|
6116
6200
|
"The complete new anchor set. Carry an anchor's hash forward to keep drift visible until the new code is read."
|
|
6117
6201
|
)
|
|
6118
6202
|
}).strict();
|
|
6119
|
-
var anchorSetCommandInput =
|
|
6203
|
+
var anchorSetCommandInput = import_zod11.z.object({
|
|
6120
6204
|
bundlePath,
|
|
6121
6205
|
conceptId,
|
|
6122
6206
|
input: anchorSetInputSchema,
|
|
6123
|
-
resolve:
|
|
6207
|
+
resolve: import_zod11.z.boolean().optional().describe(
|
|
6124
6208
|
"Also resolve and stamp every anchor against the current code, as anchor-resolve --rebaseline does."
|
|
6125
6209
|
),
|
|
6126
|
-
repoRoot:
|
|
6210
|
+
repoRoot: import_zod11.z.string().min(1).optional().describe(
|
|
6127
6211
|
"Where the anchored source lives, for resolve. Defaults to the working directory."
|
|
6128
6212
|
),
|
|
6129
|
-
offline:
|
|
6213
|
+
offline: import_zod11.z.boolean().optional().describe("With resolve, read foreign anchors from the repo cache only.")
|
|
6130
6214
|
});
|
|
6131
6215
|
|
|
6132
6216
|
// src/commands/anchor-set/command.ts
|
|
6133
6217
|
var NOTE = "pointers only: nothing was resolved or verified. Run anchor-resolve to check the new pointers, --rebaseline to accept the code, or pass resolve to do both here.";
|
|
6134
6218
|
var STAMPED_NOTE = "pointers set and stamped against the current code. Not verification: run verify separately if someone reviewed it.";
|
|
6219
|
+
var INCOMPLETE_NOTE = "pointers set, but not every anchor was stamped: see each resolved entry's state and outcome.";
|
|
6135
6220
|
var anchorSetCommand = define({
|
|
6136
6221
|
name: "anchor-set",
|
|
6137
6222
|
tool: "kb_anchor_set",
|
|
@@ -6188,33 +6273,39 @@ var anchorSetCommand = define({
|
|
|
6188
6273
|
})
|
|
6189
6274
|
);
|
|
6190
6275
|
const after = await store.read(path, id);
|
|
6276
|
+
const stamped = resolved.results.every(
|
|
6277
|
+
(entry) => entry.state === "match" || entry.outcome === "applied"
|
|
6278
|
+
);
|
|
6191
6279
|
return {
|
|
6192
6280
|
conceptId: id,
|
|
6193
6281
|
reason: input.reason,
|
|
6194
6282
|
changes,
|
|
6195
6283
|
anchors: after?.frontmatter.strauss_anchors ?? [],
|
|
6196
|
-
baseline: "stamped",
|
|
6284
|
+
baseline: stamped ? "stamped" : "incomplete",
|
|
6197
6285
|
resolved: resolved.results,
|
|
6198
|
-
note: STAMPED_NOTE
|
|
6286
|
+
note: stamped ? STAMPED_NOTE : INCOMPLETE_NOTE
|
|
6199
6287
|
};
|
|
6200
6288
|
},
|
|
6201
6289
|
// With `resolve`, a pointer that names nothing is a failed set, not a
|
|
6202
|
-
// finding to read later
|
|
6203
|
-
//
|
|
6204
|
-
|
|
6205
|
-
|
|
6206
|
-
|
|
6207
|
-
|
|
6290
|
+
// finding to read later, and a stamp that did not land fails as it does in
|
|
6291
|
+
// anchor-resolve. A remote nothing could reach was never checked, so it does
|
|
6292
|
+
// not fail — the same line anchor-resolve draws.
|
|
6293
|
+
failsWhen: (result, input) => {
|
|
6294
|
+
const resolved = result.resolved ?? [];
|
|
6295
|
+
return resolved.some(
|
|
6296
|
+
(entry) => entry.state === "unresolved" && !isUncheckedReason(entry.reason)
|
|
6297
|
+
) || anchorResolveCommand.failsWhen?.({ results: resolved }, input) === true;
|
|
6298
|
+
}
|
|
6208
6299
|
});
|
|
6209
6300
|
|
|
6210
6301
|
// src/commands/answer.ts
|
|
6211
|
-
var
|
|
6302
|
+
var import_zod12 = require("zod");
|
|
6212
6303
|
var answerCommand = define({
|
|
6213
6304
|
name: "answer",
|
|
6214
6305
|
tool: "kb_answer",
|
|
6215
6306
|
usage: "answer <concept-id> <answer...>",
|
|
6216
6307
|
description: "Resolve an open question: set status, stamp who and when, append an Answer section. If the answer overturns a decision or assumption, supersede that record explicitly.",
|
|
6217
|
-
input:
|
|
6308
|
+
input: import_zod12.z.object({ bundlePath, conceptId, answer: import_zod12.z.string().min(1) }),
|
|
6218
6309
|
fromArgv: (argv, path) => ({
|
|
6219
6310
|
bundlePath: path,
|
|
6220
6311
|
conceptId: argv[1],
|
|
@@ -6228,27 +6319,27 @@ var answerCommand = define({
|
|
|
6228
6319
|
});
|
|
6229
6320
|
|
|
6230
6321
|
// src/commands/backlinks.ts
|
|
6231
|
-
var
|
|
6322
|
+
var import_zod13 = require("zod");
|
|
6232
6323
|
var backlinksCommand = define({
|
|
6233
6324
|
name: "backlinks",
|
|
6234
6325
|
tool: "kb_backlinks",
|
|
6235
6326
|
usage: "backlinks <concept-id>",
|
|
6236
6327
|
description: "Who points at this record: every inbound typed causal link (`strauss_links`), one hop, every rel including `related_to`, each with its rel and the standing of the record that made it. Use it when you need the exact edges \u2014 reviewing or renaming a record.",
|
|
6237
|
-
input:
|
|
6328
|
+
input: import_zod13.z.object({ bundlePath, conceptId }),
|
|
6238
6329
|
fromArgv: (argv, path) => ({ bundlePath: path, conceptId: argv[1] }),
|
|
6239
6330
|
run: async ({ store }, { bundlePath: path, conceptId: id }) => store.backlinks(path, id)
|
|
6240
6331
|
});
|
|
6241
6332
|
|
|
6242
6333
|
// src/commands/catalog.ts
|
|
6243
|
-
var
|
|
6334
|
+
var import_zod14 = require("zod");
|
|
6244
6335
|
var catalogCommand = define({
|
|
6245
6336
|
name: "catalog",
|
|
6246
6337
|
tool: "kb_catalog",
|
|
6247
6338
|
usage: "catalog [type] [--tag T]...",
|
|
6248
6339
|
description: "Lists every record as one line \u2014 concept id, type, title, standing, and a stale flag \u2014 at roughly thirty tokens each. Pick this over kb_load once kb_load refuses: kb_catalog never refuses. Superseded records show only their replacement; fetch bodies with kb_load, kb_pack, kb_query, or kb_trace.",
|
|
6249
|
-
input:
|
|
6340
|
+
input: import_zod14.z.object({
|
|
6250
6341
|
bundlePath,
|
|
6251
|
-
type:
|
|
6342
|
+
type: import_zod14.z.enum(KB_RECORD_TYPES).optional(),
|
|
6252
6343
|
tags: TAGS
|
|
6253
6344
|
}),
|
|
6254
6345
|
fromArgv: (argv, path) => {
|
|
@@ -6320,7 +6411,7 @@ function count(value, noun) {
|
|
|
6320
6411
|
var import_node_buffer = require("buffer");
|
|
6321
6412
|
var import_promises10 = require("fs/promises");
|
|
6322
6413
|
var import_node_path12 = require("path");
|
|
6323
|
-
var
|
|
6414
|
+
var import_zod17 = require("zod");
|
|
6324
6415
|
|
|
6325
6416
|
// src/drift/moved.ts
|
|
6326
6417
|
var import_promises9 = require("fs/promises");
|
|
@@ -6657,7 +6748,7 @@ function claimOf(record) {
|
|
|
6657
6748
|
}
|
|
6658
6749
|
|
|
6659
6750
|
// src/commands/match/command.ts
|
|
6660
|
-
var
|
|
6751
|
+
var import_zod16 = require("zod");
|
|
6661
6752
|
|
|
6662
6753
|
// src/commands/match/errors.ts
|
|
6663
6754
|
var KbMatchInputError = class extends BaseError {
|
|
@@ -6677,21 +6768,21 @@ var KbMatchInputError = class extends BaseError {
|
|
|
6677
6768
|
};
|
|
6678
6769
|
|
|
6679
6770
|
// src/commands/match/model.ts
|
|
6680
|
-
var
|
|
6681
|
-
var diffHunkSchema =
|
|
6682
|
-
startLine:
|
|
6683
|
-
endLine:
|
|
6684
|
-
side:
|
|
6771
|
+
var import_zod15 = require("zod");
|
|
6772
|
+
var diffHunkSchema = import_zod15.z.object({
|
|
6773
|
+
startLine: import_zod15.z.number().int().positive(),
|
|
6774
|
+
endLine: import_zod15.z.number().int().positive(),
|
|
6775
|
+
side: import_zod15.z.enum(["old", "new"]).optional()
|
|
6685
6776
|
}).passthrough();
|
|
6686
|
-
var diffFileSchema =
|
|
6687
|
-
filePath:
|
|
6688
|
-
hunks:
|
|
6777
|
+
var diffFileSchema = import_zod15.z.object({
|
|
6778
|
+
filePath: import_zod15.z.string().min(1).describe("Repo-relative, spelled the way anchors are."),
|
|
6779
|
+
hunks: import_zod15.z.array(diffHunkSchema)
|
|
6689
6780
|
});
|
|
6690
|
-
var symbolRangeSchema =
|
|
6691
|
-
file:
|
|
6692
|
-
symbol:
|
|
6693
|
-
startLine:
|
|
6694
|
-
endLine:
|
|
6781
|
+
var symbolRangeSchema = import_zod15.z.object({
|
|
6782
|
+
file: import_zod15.z.string().min(1),
|
|
6783
|
+
symbol: import_zod15.z.string().min(1),
|
|
6784
|
+
startLine: import_zod15.z.number().int().positive(),
|
|
6785
|
+
endLine: import_zod15.z.number().int().positive()
|
|
6695
6786
|
});
|
|
6696
6787
|
|
|
6697
6788
|
// src/commands/match/parse-unified-diff.ts
|
|
@@ -6940,17 +7031,17 @@ var matchCommand = define({
|
|
|
6940
7031
|
tool: "kb_match",
|
|
6941
7032
|
usage: "match --git <base>..<head> | --stdin [--repo-root <path>] [--offline] [--include-non-current]",
|
|
6942
7033
|
description: "Which records sit on each changed hunk: the anchored records per file range, current first, each with its standing and the anchor that matched. kb_load hands over a whole base; this narrows a diff. Symbol ranges resolve from repoRoot when omitted; non-current records need includeNonCurrent.",
|
|
6943
|
-
input:
|
|
7034
|
+
input: import_zod16.z.object({
|
|
6944
7035
|
bundlePath,
|
|
6945
|
-
files:
|
|
6946
|
-
symbolRanges:
|
|
7036
|
+
files: import_zod16.z.array(diffFileSchema).describe("The changed files, each with its post-change line ranges."),
|
|
7037
|
+
symbolRanges: import_zod16.z.array(symbolRangeSchema).optional().describe(
|
|
6947
7038
|
"Symbol spans the caller already has. Resolved from repoRoot when omitted."
|
|
6948
7039
|
),
|
|
6949
7040
|
repoRoot: REPO_ROOT,
|
|
6950
|
-
offline:
|
|
7041
|
+
offline: import_zod16.z.boolean().optional().describe(
|
|
6951
7042
|
"Resolve symbol ranges from what is already on disk, never fetching a grammar."
|
|
6952
7043
|
),
|
|
6953
|
-
includeNonCurrent:
|
|
7044
|
+
includeNonCurrent: import_zod16.z.boolean().optional().describe(
|
|
6954
7045
|
"Return superseded, rejected and unsettled records too, each carrying its standing."
|
|
6955
7046
|
)
|
|
6956
7047
|
}),
|
|
@@ -7054,22 +7145,22 @@ function project(match, ranges, all) {
|
|
|
7054
7145
|
|
|
7055
7146
|
// src/commands/classify.ts
|
|
7056
7147
|
var classifyFileSchema = diffFileSchema.extend({
|
|
7057
|
-
hunks:
|
|
7058
|
-
diffHunkSchema.extend({ lines:
|
|
7148
|
+
hunks: import_zod17.z.array(
|
|
7149
|
+
diffHunkSchema.extend({ lines: import_zod17.z.array(import_zod17.z.string()).optional() })
|
|
7059
7150
|
),
|
|
7060
|
-
renamedFrom:
|
|
7061
|
-
similarity:
|
|
7151
|
+
renamedFrom: import_zod17.z.string().min(1).optional().describe("Where `git diff -M` says the path came from."),
|
|
7152
|
+
similarity: import_zod17.z.number().min(0).max(100).optional()
|
|
7062
7153
|
});
|
|
7063
7154
|
var classifyCommand = define({
|
|
7064
7155
|
name: "classify",
|
|
7065
7156
|
tool: "kb_classify",
|
|
7066
7157
|
usage: "classify --git <base>..<head> | --stdin [--repo-root <path>] [--offline]",
|
|
7067
7158
|
description: "What kind of change each file carries: test, config, ci, docs, lockfile, generated, boilerplate, rename or source, with the rule that decided it. Derived from the diff and never stored; a `review:generated`, `review:boilerplate` or `review:move` fact anchored on a file overrides the heuristic. kb_match says what sits on a hunk; this says whether to read it.",
|
|
7068
|
-
input:
|
|
7159
|
+
input: import_zod17.z.object({
|
|
7069
7160
|
bundlePath,
|
|
7070
|
-
files:
|
|
7161
|
+
files: import_zod17.z.array(classifyFileSchema).describe("The changed files, each with its line ranges."),
|
|
7071
7162
|
repoRoot: REPO_ROOT,
|
|
7072
|
-
offline:
|
|
7163
|
+
offline: import_zod17.z.boolean().optional().describe(
|
|
7073
7164
|
"Resolve symbol ranges from what is already on disk, never fetching a grammar."
|
|
7074
7165
|
)
|
|
7075
7166
|
}),
|
|
@@ -7180,29 +7271,29 @@ function renderClassify(result) {
|
|
|
7180
7271
|
}
|
|
7181
7272
|
|
|
7182
7273
|
// src/commands/context.ts
|
|
7183
|
-
var
|
|
7274
|
+
var import_zod18 = require("zod");
|
|
7184
7275
|
var contextCommand = define({
|
|
7185
7276
|
name: "context",
|
|
7186
7277
|
tool: "kb_context",
|
|
7187
7278
|
usage: "context [--profile NAME] [--budget N] [--full-under N] [--exclude-tag T]... [--format json] [--event NAME]",
|
|
7188
7279
|
description: "Index block of pinned bases (ids, titles, standing) for injection at context birth. Takes no bundlePath \u2014 reads the workspace pin manifests. Empty when nothing is pinned; refuses over budget rather than truncating. Budget precedence: flags, then the manifest `context[profile]` over `context.default`, then the built-in profile, then package defaults.",
|
|
7189
|
-
input:
|
|
7190
|
-
budgetTokens:
|
|
7280
|
+
input: import_zod18.z.object({
|
|
7281
|
+
budgetTokens: import_zod18.z.number().int().positive().optional().describe(
|
|
7191
7282
|
"Ceiling on the whole emitted block; past it the command refuses with a list of bases rather than truncating. Defaults to 4000."
|
|
7192
7283
|
),
|
|
7193
|
-
fullUnderTokens:
|
|
7284
|
+
fullUnderTokens: import_zod18.z.number().int().positive().optional().describe(
|
|
7194
7285
|
"Per-base rendering threshold, applied before the budget: a base whose complete load fits under this arrives as full records instead of index lines, and the whole block still answers to budgetTokens. Off by default \u2014 index-only is the safe default at a context birth, because injected bodies outlive the qualifiers on them; the session-start profile opts tiny bases in at 1500."
|
|
7195
7286
|
),
|
|
7196
|
-
profile:
|
|
7287
|
+
profile: import_zod18.z.string().optional().describe(
|
|
7197
7288
|
"Named budget set: built-ins are session-start (full-under 1500), compact and turn (budget 2500); the manifests' `context` tables override per repo. Unknown names fall through to defaults rather than failing."
|
|
7198
7289
|
),
|
|
7199
|
-
excludeTags:
|
|
7290
|
+
excludeTags: import_zod18.z.array(import_zod18.z.string().min(1)).optional().describe(
|
|
7200
7291
|
"Frontmatter tags whose records stay out of the block. The base stays pinned and stays readable by tool; resolved like the budgets."
|
|
7201
7292
|
),
|
|
7202
|
-
format:
|
|
7293
|
+
format: import_zod18.z.enum(["markdown", "json"]).optional().describe(
|
|
7203
7294
|
"CLI envelope for hook protocols that require strict JSON on stdout. MCP callers omit this \u2014 the block itself is identical."
|
|
7204
7295
|
),
|
|
7205
|
-
event:
|
|
7296
|
+
event: import_zod18.z.string().optional().describe(
|
|
7206
7297
|
"hookEventName stamped into the JSON envelope. Only meaningful with format=json."
|
|
7207
7298
|
)
|
|
7208
7299
|
}),
|
|
@@ -7241,20 +7332,20 @@ var contextCommand = define({
|
|
|
7241
7332
|
});
|
|
7242
7333
|
|
|
7243
7334
|
// src/commands/doctor.ts
|
|
7244
|
-
var
|
|
7335
|
+
var import_zod20 = require("zod");
|
|
7245
7336
|
|
|
7246
7337
|
// src/commands/reassess.ts
|
|
7247
|
-
var
|
|
7338
|
+
var import_zod19 = require("zod");
|
|
7248
7339
|
var reassessCommand = define({
|
|
7249
7340
|
name: "reassess",
|
|
7250
7341
|
tool: "kb_reassess",
|
|
7251
7342
|
usage: "reassess <concept-id> [--repo-root <path>] [--with-diff]",
|
|
7252
7343
|
description: "One drifted record, as something to judge: its claim, each anchor's drift class, the old-vs-new span diff, and the records that depend on it. Formatting-only drift is dropped. Empty when there is nothing to reassess. Writes: relocates moved anchors, keeping their hash; never verifies, supersedes, or changes standing.",
|
|
7253
|
-
input:
|
|
7344
|
+
input: import_zod19.z.object({
|
|
7254
7345
|
bundlePath,
|
|
7255
7346
|
conceptId,
|
|
7256
7347
|
repoRoot: REPO_ROOT,
|
|
7257
|
-
withDiff:
|
|
7348
|
+
withDiff: import_zod19.z.boolean().optional().describe(
|
|
7258
7349
|
"Recover each anchor's committed span and render the diff. Reads git history."
|
|
7259
7350
|
)
|
|
7260
7351
|
}),
|
|
@@ -7399,13 +7490,13 @@ function at(file, symbol) {
|
|
|
7399
7490
|
}
|
|
7400
7491
|
|
|
7401
7492
|
// src/commands/doctor.ts
|
|
7402
|
-
var days = (what, fallback) =>
|
|
7493
|
+
var days = (what, fallback) => import_zod20.z.number().int().positive().optional().describe(`${what} Defaults to ${fallback}.`);
|
|
7403
7494
|
var doctorCommand = define({
|
|
7404
7495
|
name: "doctor",
|
|
7405
7496
|
tool: "kb_doctor",
|
|
7406
7497
|
usage: "doctor [--expiring-days N] [--unverified-days N] [--aging-days N] [--repo-root PATH] [--offline] [--strict] [--drifted [--with-diff]]",
|
|
7407
7498
|
description: "Read-only health sweep: expired, expiring, unverified, aging, orphaned, broken-supersession, superseded-but-cited, drifted and unchecked anchors. Every group is reported even when empty; nothing is written or re-stamped. `drifted` narrows it to a reassessment packet per drifted record, `with_diff` adding each anchor's old-vs-new span.",
|
|
7408
|
-
input:
|
|
7499
|
+
input: import_zod20.z.object({
|
|
7409
7500
|
bundlePath,
|
|
7410
7501
|
repoRoot: REPO_ROOT,
|
|
7411
7502
|
expiringDays: days(
|
|
@@ -7420,16 +7511,16 @@ var doctorCommand = define({
|
|
|
7420
7511
|
"How long a record may stay `open` or `proposed` before `aging` reports it, in days.",
|
|
7421
7512
|
DEFAULT_AGING_DAYS
|
|
7422
7513
|
),
|
|
7423
|
-
offline:
|
|
7514
|
+
offline: import_zod20.z.boolean().optional().describe(
|
|
7424
7515
|
"Read foreign anchors from the local repo cache only, never fetching."
|
|
7425
7516
|
),
|
|
7426
|
-
strict:
|
|
7517
|
+
strict: import_zod20.z.boolean().optional().describe(
|
|
7427
7518
|
"Turn an expired record into a non-zero exit for the CLI. No effect on the report itself."
|
|
7428
7519
|
),
|
|
7429
|
-
drifted:
|
|
7520
|
+
drifted: import_zod20.z.boolean().optional().describe(
|
|
7430
7521
|
"Report only drift, as a reassessment packet per record: claim, per-anchor class, and what depends on it."
|
|
7431
7522
|
),
|
|
7432
|
-
withDiff:
|
|
7523
|
+
withDiff: import_zod20.z.boolean().optional().describe(
|
|
7433
7524
|
"With `drifted`: recover each anchor's committed span and render the old-vs-new diff. Reads git history."
|
|
7434
7525
|
)
|
|
7435
7526
|
}),
|
|
@@ -7606,7 +7697,7 @@ function renderPackets(result) {
|
|
|
7606
7697
|
// src/commands/export.ts
|
|
7607
7698
|
var import_promises11 = require("fs/promises");
|
|
7608
7699
|
var import_node_path13 = require("path");
|
|
7609
|
-
var
|
|
7700
|
+
var import_zod21 = require("zod");
|
|
7610
7701
|
var NUMBERED = /^(\d{4})-(.+)\.md$/;
|
|
7611
7702
|
var MARKER = "<!-- strauss-kb export: ";
|
|
7612
7703
|
var exportCommand = define({
|
|
@@ -7614,10 +7705,10 @@ var exportCommand = define({
|
|
|
7614
7705
|
tool: "kb_export",
|
|
7615
7706
|
usage: "export --format madr --to <dir>",
|
|
7616
7707
|
description: "Write the base's decisions out as numbered MADR files, one per decision, for a repository that keeps ADRs of its own. Numbering is by slug, so a re-run rewrites its own files in place. A superseded decision is exported with what replaced it.",
|
|
7617
|
-
input:
|
|
7708
|
+
input: import_zod21.z.object({
|
|
7618
7709
|
bundlePath,
|
|
7619
|
-
format:
|
|
7620
|
-
to:
|
|
7710
|
+
format: import_zod21.z.enum(["madr"]).describe("Output layout. `madr` is the only one so far."),
|
|
7711
|
+
to: import_zod21.z.string().min(1).describe("Directory the ADR files are written into.")
|
|
7621
7712
|
}),
|
|
7622
7713
|
fromArgv: (argv, path) => ({
|
|
7623
7714
|
bundlePath: path,
|
|
@@ -7739,19 +7830,19 @@ function bodySections(body) {
|
|
|
7739
7830
|
}
|
|
7740
7831
|
|
|
7741
7832
|
// src/commands/impact.ts
|
|
7742
|
-
var
|
|
7833
|
+
var import_zod22 = require("zod");
|
|
7743
7834
|
var impactCommand = define({
|
|
7744
7835
|
name: "impact",
|
|
7745
7836
|
tool: "kb_impact",
|
|
7746
7837
|
usage: "impact <concept-id> [--depth N] [--rels a,b]",
|
|
7747
7838
|
description: "What breaks if this record changes: its transitive set of dependants, each with its standing. Each rel declares which of its ends depends on the other, and the walk follows each rel in its own direction. Naming `related_to` or an unknown rel in `rels` is an error. kb_backlinks gives one flat hop.",
|
|
7748
|
-
input:
|
|
7839
|
+
input: import_zod22.z.object({
|
|
7749
7840
|
bundlePath,
|
|
7750
7841
|
conceptId,
|
|
7751
|
-
depth:
|
|
7842
|
+
depth: import_zod22.z.number().int().positive().optional().describe(
|
|
7752
7843
|
"Hops out from the record. Unbounded when omitted; a walk this cuts reports truncated: true."
|
|
7753
7844
|
),
|
|
7754
|
-
rels:
|
|
7845
|
+
rels: import_zod22.z.array(import_zod22.z.enum(KB_CAUSAL_LINK_RELS)).optional().describe(
|
|
7755
7846
|
"Narrow which rels the walk follows. Defaults to every rel that carries a dependence \u2014 all but related_to."
|
|
7756
7847
|
)
|
|
7757
7848
|
}),
|
|
@@ -7772,15 +7863,15 @@ var impactCommand = define({
|
|
|
7772
7863
|
});
|
|
7773
7864
|
|
|
7774
7865
|
// src/commands/list.ts
|
|
7775
|
-
var
|
|
7866
|
+
var import_zod23 = require("zod");
|
|
7776
7867
|
var listCommand = define({
|
|
7777
7868
|
name: "list",
|
|
7778
7869
|
tool: "kb_list",
|
|
7779
7870
|
usage: "list [type] [--tag T]...",
|
|
7780
7871
|
description: "Every record, optionally one type or tag. For enumerating; use kb_query for a question.",
|
|
7781
|
-
input:
|
|
7872
|
+
input: import_zod23.z.object({
|
|
7782
7873
|
bundlePath,
|
|
7783
|
-
type:
|
|
7874
|
+
type: import_zod23.z.enum(KB_RECORD_TYPES).optional(),
|
|
7784
7875
|
tags: TAGS
|
|
7785
7876
|
}),
|
|
7786
7877
|
fromArgv: (argv, path) => {
|
|
@@ -7804,17 +7895,17 @@ var listCommand = define({
|
|
|
7804
7895
|
});
|
|
7805
7896
|
|
|
7806
7897
|
// src/commands/load.ts
|
|
7807
|
-
var
|
|
7898
|
+
var import_zod24 = require("zod");
|
|
7808
7899
|
var loadCommand = define({
|
|
7809
7900
|
name: "load",
|
|
7810
7901
|
tool: "kb_load",
|
|
7811
7902
|
usage: "load [type] [--budget N | --all] [--repo-root PATH]",
|
|
7812
7903
|
description: "Load the whole base, each record with its standing \u2014 call it first, at the point of use, since compaction drops it. Superseded records arrive as stubs; kb_trace has the history. Over budget it refuses: kb_catalog, then kb_pack, or narrow with `type`; `all` bypasses. Never read record files directly \u2014 only kb_* tools resolve supersession. `digest` stamps the base's content, so hooks know when to reload.",
|
|
7813
|
-
input:
|
|
7904
|
+
input: import_zod24.z.object({
|
|
7814
7905
|
bundlePath,
|
|
7815
|
-
type:
|
|
7816
|
-
budgetTokens:
|
|
7817
|
-
all:
|
|
7906
|
+
type: import_zod24.z.enum(KB_RECORD_TYPES).optional(),
|
|
7907
|
+
budgetTokens: import_zod24.z.number().int().positive().optional().describe("Approximate token ceiling. Defaults to 25000."),
|
|
7908
|
+
all: import_zod24.z.boolean().optional().describe(
|
|
7818
7909
|
"Loads the entire base regardless of size, bypassing the token budget; mutually exclusive with budgetTokens."
|
|
7819
7910
|
),
|
|
7820
7911
|
repoRoot: REPO_ROOT
|
|
@@ -7856,25 +7947,25 @@ var loadCommand = define({
|
|
|
7856
7947
|
});
|
|
7857
7948
|
|
|
7858
7949
|
// src/commands/log.ts
|
|
7859
|
-
var
|
|
7950
|
+
var import_zod25 = require("zod");
|
|
7860
7951
|
var logCommand = define({
|
|
7861
7952
|
name: "log",
|
|
7862
7953
|
tool: "kb_log",
|
|
7863
7954
|
usage: "log",
|
|
7864
7955
|
description: "Who touched what, and when. Append-only; malformed lines are reported, never repaired.",
|
|
7865
|
-
input:
|
|
7956
|
+
input: import_zod25.z.object({ bundlePath }),
|
|
7866
7957
|
fromArgv: (_argv, path) => ({ bundlePath: path }),
|
|
7867
7958
|
run: ({ store }, { bundlePath: path }) => store.readLog(path)
|
|
7868
7959
|
});
|
|
7869
7960
|
|
|
7870
7961
|
// src/commands/no-decision.ts
|
|
7871
|
-
var
|
|
7962
|
+
var import_zod26 = require("zod");
|
|
7872
7963
|
var noDecisionCommand = define({
|
|
7873
7964
|
name: "no-decision",
|
|
7874
7965
|
tool: "kb_no_decision",
|
|
7875
7966
|
usage: "no-decision <reason...>",
|
|
7876
7967
|
description: "Record in one sentence that a piece of work had nothing to decide. Idempotent.",
|
|
7877
|
-
input:
|
|
7968
|
+
input: import_zod26.z.object({ bundlePath, reason: import_zod26.z.string().min(1) }),
|
|
7878
7969
|
fromArgv: (argv, path) => ({
|
|
7879
7970
|
bundlePath: path,
|
|
7880
7971
|
reason: argv.slice(1).join(" ").trim()
|
|
@@ -7891,20 +7982,20 @@ var noDecisionCommand = define({
|
|
|
7891
7982
|
});
|
|
7892
7983
|
|
|
7893
7984
|
// src/commands/pack.ts
|
|
7894
|
-
var
|
|
7985
|
+
var import_zod27 = require("zod");
|
|
7895
7986
|
var packCommand = define({
|
|
7896
7987
|
name: "pack",
|
|
7897
7988
|
tool: "kb_pack",
|
|
7898
7989
|
usage: "pack <conceptId> [--hops N] [--max-nodes N] [--budget N]",
|
|
7899
7990
|
description: "Bounded neighbourhood around one record: within `hops`, ranked, cut to `maxNodes`, with every cut record named under Excluded. Use when the base is over kb_load's budget and the work centres on a record you can name. Refuses over budget rather than truncating. Everything below the header is byte-stable across runs. Resolves supersession like kb_load.",
|
|
7900
|
-
input:
|
|
7991
|
+
input: import_zod27.z.object({
|
|
7901
7992
|
bundlePath,
|
|
7902
7993
|
conceptId,
|
|
7903
|
-
hops:
|
|
7904
|
-
maxNodes:
|
|
7994
|
+
hops: import_zod27.z.number().int().positive().optional().describe("How far from the root the walk may reach. Defaults to 2."),
|
|
7995
|
+
maxNodes: import_zod27.z.number().int().positive().optional().describe(
|
|
7905
7996
|
"How many records the pack may hold, root included. Defaults to 20."
|
|
7906
7997
|
),
|
|
7907
|
-
budgetTokens:
|
|
7998
|
+
budgetTokens: import_zod27.z.number().int().positive().optional().describe(
|
|
7908
7999
|
"Approximate token ceiling over what is actually emitted. Defaults to 25000."
|
|
7909
8000
|
)
|
|
7910
8001
|
}),
|
|
@@ -7991,22 +8082,22 @@ function warningLabel(warning) {
|
|
|
7991
8082
|
}
|
|
7992
8083
|
|
|
7993
8084
|
// src/commands/pin.ts
|
|
7994
|
-
var
|
|
8085
|
+
var import_zod28 = require("zod");
|
|
7995
8086
|
var pinCommand = define({
|
|
7996
8087
|
name: "pin",
|
|
7997
8088
|
tool: "kb_pin",
|
|
7998
8089
|
usage: "pin [bundle-path] [--mode full|index] [--profiles a,b] [--local|--user] [--frozen|--unfreeze]",
|
|
7999
8090
|
description: "Pin a base into a workspace manifest so kb_context surfaces it. Layers, nearest wins: project `.strauss/kb-pins.json` (default), `--local` (personal, gitignored), `--user` (`~/.strauss`). Idempotent; `--mode full|index`, `--profiles`, `--frozen`/`--unfreeze` update only those fields. A path with no records pins with a warning. Never touches the base itself.",
|
|
8000
|
-
input:
|
|
8091
|
+
input: import_zod28.z.object({
|
|
8001
8092
|
bundlePath,
|
|
8002
|
-
mode:
|
|
8093
|
+
mode: import_zod28.z.enum(["full", "index"]).optional().describe(
|
|
8003
8094
|
"full: always emit this base's records whole (still under the block budget); index: never upgrade. Absent: the profile's full-under threshold decides."
|
|
8004
8095
|
),
|
|
8005
|
-
profiles:
|
|
8006
|
-
layer:
|
|
8096
|
+
profiles: import_zod28.z.array(import_zod28.z.string()).optional().describe("Context profiles this pin surfaces in. Absent: all of them."),
|
|
8097
|
+
layer: import_zod28.z.enum(["project", "local", "user"]).optional().describe(
|
|
8007
8098
|
"Which manifest to write: project (committed, default), local (personal, gitignored), user (~/.strauss, every workspace)."
|
|
8008
8099
|
),
|
|
8009
|
-
frozen:
|
|
8100
|
+
frozen: import_zod28.z.boolean().optional().describe(
|
|
8010
8101
|
"true: the base is concluded \u2014 writes against it refuse while pinned. false: lift a freeze."
|
|
8011
8102
|
)
|
|
8012
8103
|
}),
|
|
@@ -8035,13 +8126,13 @@ var pinCommand = define({
|
|
|
8035
8126
|
});
|
|
8036
8127
|
|
|
8037
8128
|
// src/commands/pins.ts
|
|
8038
|
-
var
|
|
8129
|
+
var import_zod29 = require("zod");
|
|
8039
8130
|
var pinsCommand = define({
|
|
8040
8131
|
name: "pins",
|
|
8041
8132
|
tool: "kb_pins",
|
|
8042
8133
|
usage: "pins",
|
|
8043
8134
|
description: "Every pinned base across the manifest layers, with its layer and whether it resolves to records. Takes no bundlePath.",
|
|
8044
|
-
input:
|
|
8135
|
+
input: import_zod29.z.object({}),
|
|
8045
8136
|
fromArgv: () => ({}),
|
|
8046
8137
|
run: ({ store }) => listPins(store, process.cwd())
|
|
8047
8138
|
});
|
|
@@ -8177,16 +8268,16 @@ function recordType(conceptId2) {
|
|
|
8177
8268
|
}
|
|
8178
8269
|
|
|
8179
8270
|
// src/commands/promote/model.ts
|
|
8180
|
-
var
|
|
8181
|
-
var promoteInputSchema =
|
|
8271
|
+
var import_zod30 = require("zod");
|
|
8272
|
+
var promoteInputSchema = import_zod30.z.object({
|
|
8182
8273
|
bundlePath,
|
|
8183
|
-
conceptIds:
|
|
8184
|
-
to:
|
|
8185
|
-
source:
|
|
8274
|
+
conceptIds: import_zod30.z.array(conceptId).max(64).optional().describe("Records to copy into the target base. Omit with `list`."),
|
|
8275
|
+
to: import_zod30.z.string().min(1).optional().describe("Absolute path to the base being promoted into."),
|
|
8276
|
+
source: import_zod30.z.string().min(1).optional().describe(
|
|
8186
8277
|
"Where the promotion came from, usually the pull request URL. Recorded on each copy as a source."
|
|
8187
8278
|
),
|
|
8188
|
-
force:
|
|
8189
|
-
list:
|
|
8279
|
+
force: import_zod30.z.boolean().optional().describe("Overwrite a record the target base already holds."),
|
|
8280
|
+
list: import_zod30.z.boolean().optional().describe("List the source base's candidates instead of promoting.")
|
|
8190
8281
|
}).refine((input) => input.list === true || input.to !== void 0, {
|
|
8191
8282
|
message: "promote needs a target base \u2014 pass --to <bundle>, or --list",
|
|
8192
8283
|
path: ["to"]
|
|
@@ -8323,17 +8414,17 @@ function renderPromote(result) {
|
|
|
8323
8414
|
}
|
|
8324
8415
|
|
|
8325
8416
|
// src/commands/query.ts
|
|
8326
|
-
var
|
|
8417
|
+
var import_zod31 = require("zod");
|
|
8327
8418
|
var queryCommand = define({
|
|
8328
8419
|
name: "query",
|
|
8329
8420
|
tool: "kb_query",
|
|
8330
8421
|
usage: "query <text...> [--tag T]... [--repo-root PATH]",
|
|
8331
8422
|
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.",
|
|
8332
|
-
input:
|
|
8423
|
+
input: import_zod31.z.object({
|
|
8333
8424
|
bundlePath,
|
|
8334
|
-
text:
|
|
8335
|
-
type:
|
|
8336
|
-
includeNonCurrent:
|
|
8425
|
+
text: import_zod31.z.string().optional(),
|
|
8426
|
+
type: import_zod31.z.enum(KB_RECORD_TYPES).optional(),
|
|
8427
|
+
includeNonCurrent: import_zod31.z.boolean().optional(),
|
|
8337
8428
|
tags: TAGS,
|
|
8338
8429
|
repoRoot: REPO_ROOT
|
|
8339
8430
|
}),
|
|
@@ -8367,43 +8458,43 @@ var queryCommand = define({
|
|
|
8367
8458
|
});
|
|
8368
8459
|
|
|
8369
8460
|
// src/commands/read-index.ts
|
|
8370
|
-
var
|
|
8461
|
+
var import_zod32 = require("zod");
|
|
8371
8462
|
var readIndexCommand = define({
|
|
8372
8463
|
name: "index",
|
|
8373
8464
|
tool: "kb_index",
|
|
8374
8465
|
usage: "index",
|
|
8375
8466
|
description: "The index \u2014 title, type, status, description per record \u2014 rebuilt if stale. Cheapest re-orientation after compaction: call it (or kb_context) first, then kb_load or fetch by id.",
|
|
8376
|
-
input:
|
|
8467
|
+
input: import_zod32.z.object({ bundlePath }),
|
|
8377
8468
|
fromArgv: (_argv, path) => ({ bundlePath: path }),
|
|
8378
8469
|
run: ({ store }, { bundlePath: path }) => store.readIndex(path)
|
|
8379
8470
|
});
|
|
8380
8471
|
|
|
8381
8472
|
// src/commands/schema.ts
|
|
8382
|
-
var
|
|
8473
|
+
var import_zod33 = require("zod");
|
|
8383
8474
|
var schemaCommand = define({
|
|
8384
8475
|
name: "schema",
|
|
8385
8476
|
tool: "kb_schema",
|
|
8386
8477
|
usage: "schema",
|
|
8387
8478
|
description: "JSON Schema for frontmatter, write input, and log entries, generated from the enforcing code.",
|
|
8388
|
-
input:
|
|
8479
|
+
input: import_zod33.z.object({}),
|
|
8389
8480
|
fromArgv: () => ({}),
|
|
8390
8481
|
run: () => Promise.resolve(kbJsonSchemas())
|
|
8391
8482
|
});
|
|
8392
8483
|
|
|
8393
8484
|
// src/commands/stamp.ts
|
|
8394
8485
|
var import_promises12 = require("fs/promises");
|
|
8395
|
-
var
|
|
8486
|
+
var import_zod34 = require("zod");
|
|
8396
8487
|
var DIGEST = /^[0-9a-f]{64}$/;
|
|
8397
8488
|
var stampCommand = define({
|
|
8398
8489
|
name: "stamp",
|
|
8399
8490
|
tool: "kb_stamp",
|
|
8400
8491
|
usage: "stamp [--bundle PATH] [--since DIGEST|FILE]",
|
|
8401
8492
|
description: "Content stamp of a base \u2014 `load`'s digest, record counts, per-record digests, how many records have drifted anchors \u2014 without any bodies. Takes no bundlePath to stamp every pinned base. With `since`, reports only the bases that moved, naming the changed ids. Reads, never writes.",
|
|
8402
|
-
input:
|
|
8403
|
-
bundlePath:
|
|
8493
|
+
input: import_zod34.z.object({
|
|
8494
|
+
bundlePath: import_zod34.z.string().min(1).optional().describe(
|
|
8404
8495
|
"Absolute path to one knowledge base. Omit to stamp every pinned base."
|
|
8405
8496
|
),
|
|
8406
|
-
since:
|
|
8497
|
+
since: import_zod34.z.string().min(1).optional().describe(
|
|
8407
8498
|
"Prior digest, or path to a prior `stamp --json`; only moved bases return, with changed ids when the baseline is a file."
|
|
8408
8499
|
)
|
|
8409
8500
|
}),
|
|
@@ -8489,16 +8580,16 @@ async function readBaseline(since) {
|
|
|
8489
8580
|
}
|
|
8490
8581
|
|
|
8491
8582
|
// src/commands/status.ts
|
|
8492
|
-
var
|
|
8583
|
+
var import_zod35 = require("zod");
|
|
8493
8584
|
var statusCommand = define({
|
|
8494
8585
|
name: "status",
|
|
8495
8586
|
tool: "kb_status",
|
|
8496
8587
|
usage: "status <concept-id> <status>",
|
|
8497
8588
|
description: "Move a record's status. Compare-and-swap: a concurrent change fails instead of being overwritten.",
|
|
8498
|
-
input:
|
|
8589
|
+
input: import_zod35.z.object({
|
|
8499
8590
|
bundlePath,
|
|
8500
8591
|
conceptId,
|
|
8501
|
-
status:
|
|
8592
|
+
status: import_zod35.z.enum(KB_RECORD_STATUSES)
|
|
8502
8593
|
}),
|
|
8503
8594
|
fromArgv: (argv, path) => ({
|
|
8504
8595
|
bundlePath: path,
|
|
@@ -8513,13 +8604,13 @@ var statusCommand = define({
|
|
|
8513
8604
|
});
|
|
8514
8605
|
|
|
8515
8606
|
// src/commands/supersede.ts
|
|
8516
|
-
var
|
|
8607
|
+
var import_zod36 = require("zod");
|
|
8517
8608
|
var supersedeCommand = define({
|
|
8518
8609
|
name: "supersede",
|
|
8519
8610
|
tool: "kb_supersede",
|
|
8520
8611
|
usage: "supersede <concept-id> <replacement-id>",
|
|
8521
8612
|
description: "Mark a record superseded by another, linked in both directions. Use instead of editing a record whose meaning changed.",
|
|
8522
|
-
input:
|
|
8613
|
+
input: import_zod36.z.object({ bundlePath, conceptId, replacementId: conceptId }),
|
|
8523
8614
|
fromArgv: (argv, path) => ({
|
|
8524
8615
|
bundlePath: path,
|
|
8525
8616
|
conceptId: argv[1],
|
|
@@ -8533,7 +8624,7 @@ var supersedeCommand = define({
|
|
|
8533
8624
|
});
|
|
8534
8625
|
|
|
8535
8626
|
// src/commands/sweep.ts
|
|
8536
|
-
var
|
|
8627
|
+
var import_zod37 = require("zod");
|
|
8537
8628
|
var TERMINAL = [
|
|
8538
8629
|
"resolved",
|
|
8539
8630
|
"rejected",
|
|
@@ -8544,15 +8635,15 @@ var sweepCommand = define({
|
|
|
8544
8635
|
tool: "kb_sweep",
|
|
8545
8636
|
usage: "sweep --tag <tag> --terminal [--dry-run]",
|
|
8546
8637
|
description: "Delete tagged records that are resolved, rejected or superseded. Refuses without --tag, keeps any record a surviving record still points at, and logs each deletion.",
|
|
8547
|
-
input:
|
|
8638
|
+
input: import_zod37.z.object({
|
|
8548
8639
|
bundlePath,
|
|
8549
|
-
tag:
|
|
8550
|
-
terminal:
|
|
8640
|
+
tag: import_zod37.z.string({ error: "sweep needs --tag: it never sweeps a whole base" }).min(1).describe("Only records carrying this tag are considered."),
|
|
8641
|
+
terminal: import_zod37.z.literal(true, {
|
|
8551
8642
|
error: "sweep needs --terminal: it deletes only settled records"
|
|
8552
8643
|
}).describe(
|
|
8553
8644
|
"Required. Names the only scope sweep deletes: resolved, rejected and superseded records."
|
|
8554
8645
|
),
|
|
8555
|
-
dryRun:
|
|
8646
|
+
dryRun: import_zod37.z.boolean().optional().describe("Report what would go, and delete nothing.")
|
|
8556
8647
|
}),
|
|
8557
8648
|
fromArgv: (argv, path) => ({
|
|
8558
8649
|
bundlePath: path,
|
|
@@ -8669,16 +8760,16 @@ function renderSweep(result) {
|
|
|
8669
8760
|
}
|
|
8670
8761
|
|
|
8671
8762
|
// src/commands/sync-instructions.ts
|
|
8672
|
-
var
|
|
8763
|
+
var import_zod38 = require("zod");
|
|
8673
8764
|
var syncInstructionsCommand = define({
|
|
8674
8765
|
name: "sync-instructions",
|
|
8675
8766
|
usage: "sync-instructions <file> [--profile NAME] [--budget N] [--full-under N]",
|
|
8676
8767
|
description: "CLI-only: plant the kb_context block between sentinel comments in AGENTS.md or CLAUDE.md, idempotently.",
|
|
8677
|
-
input:
|
|
8678
|
-
file:
|
|
8679
|
-
budgetTokens:
|
|
8680
|
-
fullUnderTokens:
|
|
8681
|
-
profile:
|
|
8768
|
+
input: import_zod38.z.object({
|
|
8769
|
+
file: import_zod38.z.string().min(1).describe("The instruction file to edit in place."),
|
|
8770
|
+
budgetTokens: import_zod38.z.number().int().positive().optional(),
|
|
8771
|
+
fullUnderTokens: import_zod38.z.number().int().positive().optional(),
|
|
8772
|
+
profile: import_zod38.z.string().optional()
|
|
8682
8773
|
}),
|
|
8683
8774
|
fromArgv: (argv) => {
|
|
8684
8775
|
const budget = argvFlag(argv, "--budget");
|
|
@@ -8704,17 +8795,17 @@ var syncInstructionsCommand = define({
|
|
|
8704
8795
|
});
|
|
8705
8796
|
|
|
8706
8797
|
// src/commands/trace.ts
|
|
8707
|
-
var
|
|
8798
|
+
var import_zod39 = require("zod");
|
|
8708
8799
|
var traceCommand = define({
|
|
8709
8800
|
name: "trace",
|
|
8710
8801
|
tool: "kb_trace",
|
|
8711
8802
|
usage: "trace <concept-id> [edges...]",
|
|
8712
8803
|
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".',
|
|
8713
|
-
input:
|
|
8804
|
+
input: import_zod39.z.object({
|
|
8714
8805
|
bundlePath,
|
|
8715
8806
|
conceptId,
|
|
8716
|
-
edges:
|
|
8717
|
-
depth:
|
|
8807
|
+
edges: import_zod39.z.array(import_zod39.z.enum(TRACE_EDGES)).optional(),
|
|
8808
|
+
depth: import_zod39.z.number().int().positive().optional()
|
|
8718
8809
|
}),
|
|
8719
8810
|
fromArgv: (argv, path) => ({
|
|
8720
8811
|
bundlePath: path,
|
|
@@ -8736,37 +8827,37 @@ var traceCommand = define({
|
|
|
8736
8827
|
});
|
|
8737
8828
|
|
|
8738
8829
|
// src/commands/types.ts
|
|
8739
|
-
var
|
|
8830
|
+
var import_zod40 = require("zod");
|
|
8740
8831
|
var typesCommand = define({
|
|
8741
8832
|
name: "types",
|
|
8742
8833
|
tool: "kb_types",
|
|
8743
8834
|
usage: "types",
|
|
8744
8835
|
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.",
|
|
8745
|
-
input:
|
|
8836
|
+
input: import_zod40.z.object({}),
|
|
8746
8837
|
fromArgv: () => ({}),
|
|
8747
8838
|
run: () => Promise.resolve(RECORD_TYPES)
|
|
8748
8839
|
});
|
|
8749
8840
|
|
|
8750
8841
|
// src/commands/unpin.ts
|
|
8751
|
-
var
|
|
8842
|
+
var import_zod41 = require("zod");
|
|
8752
8843
|
var unpinCommand = define({
|
|
8753
8844
|
name: "unpin",
|
|
8754
8845
|
tool: "kb_unpin",
|
|
8755
8846
|
usage: "unpin [bundle-path]",
|
|
8756
8847
|
description: "Remove a base from every manifest layer that holds it. Reports the layers touched.",
|
|
8757
|
-
input:
|
|
8848
|
+
input: import_zod41.z.object({ bundlePath }),
|
|
8758
8849
|
fromArgv: (argv, path) => ({ bundlePath: argv[1] ?? path }),
|
|
8759
8850
|
run: (_ctx, { bundlePath: path }) => unpinBase(process.cwd(), path)
|
|
8760
8851
|
});
|
|
8761
8852
|
|
|
8762
8853
|
// src/commands/validate.ts
|
|
8763
|
-
var
|
|
8854
|
+
var import_zod42 = require("zod");
|
|
8764
8855
|
var validateCommand = define({
|
|
8765
8856
|
name: "validate",
|
|
8766
8857
|
tool: "kb_validate",
|
|
8767
8858
|
usage: "validate",
|
|
8768
8859
|
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.",
|
|
8769
|
-
input:
|
|
8860
|
+
input: import_zod42.z.object({ bundlePath }),
|
|
8770
8861
|
fromArgv: (_argv, path) => ({ bundlePath: path }),
|
|
8771
8862
|
run: async ({ store }, { bundlePath: path }) => validateBundle(await store.list(path)),
|
|
8772
8863
|
// Warnings never fail the exit code; every other severity does.
|
|
@@ -8776,16 +8867,16 @@ var validateCommand = define({
|
|
|
8776
8867
|
});
|
|
8777
8868
|
|
|
8778
8869
|
// src/commands/verify.ts
|
|
8779
|
-
var
|
|
8870
|
+
var import_zod43 = require("zod");
|
|
8780
8871
|
var verifyCommand = define({
|
|
8781
8872
|
name: "verify",
|
|
8782
8873
|
tool: "kb_verify",
|
|
8783
8874
|
usage: "verify <concept-id> --note <text>",
|
|
8784
8875
|
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.",
|
|
8785
|
-
input:
|
|
8876
|
+
input: import_zod43.z.object({
|
|
8786
8877
|
bundlePath,
|
|
8787
8878
|
conceptId,
|
|
8788
|
-
note:
|
|
8879
|
+
note: import_zod43.z.string().refine((s) => s.trim().length > 0, {
|
|
8789
8880
|
message: "note must say what the check found"
|
|
8790
8881
|
})
|
|
8791
8882
|
}),
|
|
@@ -8805,15 +8896,15 @@ var verifyCommand = define({
|
|
|
8805
8896
|
});
|
|
8806
8897
|
|
|
8807
8898
|
// src/commands/write.ts
|
|
8808
|
-
var
|
|
8899
|
+
var import_zod44 = require("zod");
|
|
8809
8900
|
var writeCommand = define({
|
|
8810
8901
|
name: "write",
|
|
8811
8902
|
tool: "kb_write",
|
|
8812
8903
|
usage: "write <type> < record.json",
|
|
8813
8904
|
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.",
|
|
8814
|
-
input:
|
|
8905
|
+
input: import_zod44.z.object({
|
|
8815
8906
|
bundlePath,
|
|
8816
|
-
type:
|
|
8907
|
+
type: import_zod44.z.enum(KB_RECORD_TYPES),
|
|
8817
8908
|
input: composeInputSchema
|
|
8818
8909
|
}),
|
|
8819
8910
|
fromArgv: async (argv, path, stdin) => ({
|
|
@@ -8837,13 +8928,13 @@ var writeCommand = define({
|
|
|
8837
8928
|
});
|
|
8838
8929
|
|
|
8839
8930
|
// src/commands/write-decision.ts
|
|
8840
|
-
var
|
|
8931
|
+
var import_zod45 = require("zod");
|
|
8841
8932
|
var writeDecisionCommand = define({
|
|
8842
8933
|
name: "write-decision",
|
|
8843
8934
|
tool: "kb_write_decision",
|
|
8844
8935
|
usage: "write-decision < decision.json",
|
|
8845
8936
|
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.",
|
|
8846
|
-
input:
|
|
8937
|
+
input: import_zod45.z.object({ bundlePath, input: decisionInputSchema }),
|
|
8847
8938
|
fromArgv: async (_argv, path, stdin) => ({
|
|
8848
8939
|
bundlePath: path,
|
|
8849
8940
|
input: JSON.parse(await stdin())
|
|
@@ -8910,7 +9001,7 @@ var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
|
8910
9001
|
var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
8911
9002
|
|
|
8912
9003
|
// src/version.ts
|
|
8913
|
-
var VERSION = true ? "0.1.
|
|
9004
|
+
var VERSION = true ? "0.1.23" : "0.0.0-dev";
|
|
8914
9005
|
|
|
8915
9006
|
// src/mcp.ts
|
|
8916
9007
|
function createKbMcpServer() {
|