@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
|
@@ -3044,27 +3044,273 @@ var anchorSetCommandInput = z7.object({
|
|
|
3044
3044
|
offline: z7.boolean().optional().describe("With resolve, read foreign anchors from the repo cache only.")
|
|
3045
3045
|
});
|
|
3046
3046
|
|
|
3047
|
-
// src/commands/anchor-resolve.ts
|
|
3047
|
+
// src/commands/anchor-resolve/command.ts
|
|
3048
|
+
import { z as z9 } from "zod";
|
|
3049
|
+
|
|
3050
|
+
// src/commands/anchor-resolve/apply.ts
|
|
3048
3051
|
import { z as z8 } from "zod";
|
|
3052
|
+
async function baseFrozen(cwd, bundlePath2) {
|
|
3053
|
+
try {
|
|
3054
|
+
await assertBaseNotFrozen(cwd, bundlePath2);
|
|
3055
|
+
return false;
|
|
3056
|
+
} catch (caught) {
|
|
3057
|
+
if (!(caught instanceof KbBaseFrozenError)) throw caught;
|
|
3058
|
+
return true;
|
|
3059
|
+
}
|
|
3060
|
+
}
|
|
3061
|
+
async function applyPlan(plans, target) {
|
|
3062
|
+
if (!plans.some((plan) => plan.write)) {
|
|
3063
|
+
return { results: plans.map((plan) => plan.finding) };
|
|
3064
|
+
}
|
|
3065
|
+
let failure = target.frozen ? "frozen" : void 0;
|
|
3066
|
+
let error;
|
|
3067
|
+
if (!failure) {
|
|
3068
|
+
try {
|
|
3069
|
+
await target.store.updateAnchors(
|
|
3070
|
+
target.bundlePath,
|
|
3071
|
+
target.conceptId,
|
|
3072
|
+
plans.map((plan) => plan.anchor),
|
|
3073
|
+
target.actor
|
|
3074
|
+
);
|
|
3075
|
+
} catch (caught) {
|
|
3076
|
+
if (caught instanceof BaseError || caught instanceof z8.ZodError) {
|
|
3077
|
+
throw caught;
|
|
3078
|
+
}
|
|
3079
|
+
failure = "write-failed";
|
|
3080
|
+
error = clamp(caught instanceof Error ? caught.message : String(caught));
|
|
3081
|
+
}
|
|
3082
|
+
}
|
|
3083
|
+
return {
|
|
3084
|
+
results: plans.map((plan) => settle(plan, failure)),
|
|
3085
|
+
...error ? { error } : {}
|
|
3086
|
+
};
|
|
3087
|
+
}
|
|
3088
|
+
function settle(plan, failure) {
|
|
3089
|
+
if (!plan.write) return plan.finding;
|
|
3090
|
+
if (failure) {
|
|
3091
|
+
return { ...plan.finding, outcome: "failed", outcomeReason: failure };
|
|
3092
|
+
}
|
|
3093
|
+
if (plan.write === "refresh") return plan.finding;
|
|
3094
|
+
return plan.write === "stamp" ? { ...plan.finding, state: "stamped", outcome: "applied" } : { ...plan.finding, outcome: "applied", rebaselined: true };
|
|
3095
|
+
}
|
|
3096
|
+
function clamp(message) {
|
|
3097
|
+
const line = message.split("\n")[0] ?? "";
|
|
3098
|
+
return line.length > 200 ? `${line.slice(0, 199)}\u2026` : line;
|
|
3099
|
+
}
|
|
3100
|
+
|
|
3101
|
+
// src/commands/anchor-resolve/sources.ts
|
|
3102
|
+
async function readSources(anchors, root, offline) {
|
|
3103
|
+
const origin = new LazyOrigin(root);
|
|
3104
|
+
if (anchors.some((anchor) => anchor.repo)) await origin.prime();
|
|
3105
|
+
const foreign = new Map(
|
|
3106
|
+
anchors.map((anchor) => [anchor, origin.isForeign(anchor)])
|
|
3107
|
+
);
|
|
3108
|
+
const local = anchors.filter(
|
|
3109
|
+
(anchor) => !foreign.get(anchor) && anchor.side !== "old"
|
|
3110
|
+
);
|
|
3111
|
+
const committed = anchors.filter(
|
|
3112
|
+
(anchor) => !foreign.get(anchor) && anchor.side === "old"
|
|
3113
|
+
);
|
|
3114
|
+
const remote = anchors.filter((anchor) => foreign.get(anchor));
|
|
3115
|
+
const reads = await readAnchorFiles(
|
|
3116
|
+
local.map((anchor) => anchor.file),
|
|
3117
|
+
anchorFileReader(root)
|
|
3118
|
+
);
|
|
3119
|
+
const atRef = await readCommitted(root, committed);
|
|
3120
|
+
const blobs = await readRemoteAnchors(remote.flatMap(remoteWants), {
|
|
3121
|
+
offline
|
|
3122
|
+
});
|
|
3123
|
+
const sources = /* @__PURE__ */ new Map();
|
|
3124
|
+
for (const anchor of local) {
|
|
3125
|
+
const read = reads.get(anchor.file);
|
|
3126
|
+
sources.set(
|
|
3127
|
+
anchor,
|
|
3128
|
+
read.ok ? { ok: true, source: read.source } : { ok: false, reason: read.reason }
|
|
3129
|
+
);
|
|
3130
|
+
}
|
|
3131
|
+
for (const anchor of committed) {
|
|
3132
|
+
const read = atRef.get(atRefKey(anchor));
|
|
3133
|
+
sources.set(
|
|
3134
|
+
anchor,
|
|
3135
|
+
read.ok ? { ok: true, source: read.source } : { ok: false, reason: read.reason }
|
|
3136
|
+
);
|
|
3137
|
+
}
|
|
3138
|
+
for (const anchor of remote) {
|
|
3139
|
+
const repo = anchor.repo;
|
|
3140
|
+
const key2 = normalizeRepoUrl(repo);
|
|
3141
|
+
const atDefault = blobs.get(wantKey(key2, void 0, anchor.file));
|
|
3142
|
+
const primary = anchor.ref ? blobs.get(wantKey(key2, anchor.ref, anchor.file)) : atDefault;
|
|
3143
|
+
if (!primary?.ok) {
|
|
3144
|
+
sources.set(anchor, {
|
|
3145
|
+
ok: false,
|
|
3146
|
+
reason: primary?.ok === false ? primary.reason : "remote-unreachable",
|
|
3147
|
+
repo
|
|
3148
|
+
});
|
|
3149
|
+
continue;
|
|
3150
|
+
}
|
|
3151
|
+
sources.set(anchor, {
|
|
3152
|
+
ok: true,
|
|
3153
|
+
source: primary.source,
|
|
3154
|
+
repo,
|
|
3155
|
+
...anchor.ref && atDefault?.ok ? { head: atDefault.source } : {}
|
|
3156
|
+
});
|
|
3157
|
+
}
|
|
3158
|
+
return sources;
|
|
3159
|
+
}
|
|
3160
|
+
|
|
3161
|
+
// src/commands/anchor-resolve/plan.ts
|
|
3162
|
+
async function planAnchors(anchors, options) {
|
|
3163
|
+
const { root, offline, rebaseline, restamp, check, frozen, now } = options;
|
|
3164
|
+
const sources = await readSources(anchors, root, offline);
|
|
3165
|
+
const resolvers = defaultAnchorResolvers({ offline });
|
|
3166
|
+
await prepareResolvers(
|
|
3167
|
+
resolvers,
|
|
3168
|
+
anchors.map((anchor) => anchor.file)
|
|
3169
|
+
);
|
|
3170
|
+
const plans = [];
|
|
3171
|
+
for (const anchor of anchors) {
|
|
3172
|
+
const base2 = {
|
|
3173
|
+
file: anchor.file,
|
|
3174
|
+
...anchor.symbol ? { symbol: anchor.symbol } : {},
|
|
3175
|
+
...anchor.side === "old" ? { side: "old" } : {},
|
|
3176
|
+
// Carried onto unresolved findings too: an anchor that once hashed
|
|
3177
|
+
// and now resolves to nothing is a broken anchor, and the exit code
|
|
3178
|
+
// has to be able to tell it from one nobody ever stamped.
|
|
3179
|
+
...anchor.hash ? { storedHash: anchor.hash } : {}
|
|
3180
|
+
};
|
|
3181
|
+
const source = sources.get(anchor);
|
|
3182
|
+
if (source.repo) base2.repo = source.repo;
|
|
3183
|
+
if (!source.ok) {
|
|
3184
|
+
plans.push({
|
|
3185
|
+
finding: { ...base2, state: "unresolved", reason: source.reason },
|
|
3186
|
+
anchor
|
|
3187
|
+
});
|
|
3188
|
+
continue;
|
|
3189
|
+
}
|
|
3190
|
+
const outcome = resolveAnchorSpan(source.source, anchor, resolvers);
|
|
3191
|
+
if (!outcome.ok) {
|
|
3192
|
+
plans.push({
|
|
3193
|
+
finding: { ...base2, state: "unresolved", reason: outcome.reason },
|
|
3194
|
+
anchor
|
|
3195
|
+
});
|
|
3196
|
+
continue;
|
|
3197
|
+
}
|
|
3198
|
+
const resolved = outcome.span;
|
|
3199
|
+
const producedBy = outcome.resolver;
|
|
3200
|
+
const { hash: currentHash, kind } = anchorHashOf(anchor, outcome);
|
|
3201
|
+
const currentLines = resolved.endLine - resolved.startLine + 1;
|
|
3202
|
+
const stampedKind = outcome.normalized ? "ast" : "raw";
|
|
3203
|
+
const stampedHash = outcome.normalized ? anchorHashOf({ ...anchor, hash: void 0 }, outcome).hash : currentHash;
|
|
3204
|
+
const stamped = {
|
|
3205
|
+
...anchor,
|
|
3206
|
+
hash: stampedHash,
|
|
3207
|
+
hash_kind: stampedKind,
|
|
3208
|
+
lines: currentLines,
|
|
3209
|
+
resolved_at: now(),
|
|
3210
|
+
...producedBy ? { resolver: producedBy } : {}
|
|
3211
|
+
};
|
|
3212
|
+
const pinned = anchor.ref !== void 0 && source.repo !== void 0;
|
|
3213
|
+
if (!anchor.hash) {
|
|
3214
|
+
plans.push({
|
|
3215
|
+
finding: {
|
|
3216
|
+
...base2,
|
|
3217
|
+
state: "unstamped",
|
|
3218
|
+
currentHash: stampedHash,
|
|
3219
|
+
hashKind: stampedKind,
|
|
3220
|
+
...producedBy ? { resolver: producedBy } : {}
|
|
3221
|
+
},
|
|
3222
|
+
anchor: check ? anchor : stamped,
|
|
3223
|
+
...check ? {} : { write: "stamp" }
|
|
3224
|
+
});
|
|
3225
|
+
continue;
|
|
3226
|
+
}
|
|
3227
|
+
if (anchor.hash !== currentHash) {
|
|
3228
|
+
plans.push({
|
|
3229
|
+
finding: {
|
|
3230
|
+
...base2,
|
|
3231
|
+
state: "drifted",
|
|
3232
|
+
currentHash,
|
|
3233
|
+
hashKind: kind,
|
|
3234
|
+
diffSize: lineDelta(anchor, currentLines),
|
|
3235
|
+
...producedBy ? { resolver: producedBy } : {},
|
|
3236
|
+
// A regex-stamped anchor re-read by tree-sitter drifts because the
|
|
3237
|
+
// resolver changed, not because the code did.
|
|
3238
|
+
...resolverChanged(source.source, anchor, producedBy) ? { reason: "resolver-changed" } : {},
|
|
3239
|
+
...pinned ? { remoteState: "drifted-from-ref" } : {}
|
|
3240
|
+
},
|
|
3241
|
+
anchor: rebaseline && !check ? stamped : anchor,
|
|
3242
|
+
...rebaseline && !check ? { write: "rebaseline" } : {}
|
|
3243
|
+
});
|
|
3244
|
+
continue;
|
|
3245
|
+
}
|
|
3246
|
+
const onDefault = pinned ? headHash(source, anchor, resolvers) : void 0;
|
|
3247
|
+
if (onDefault && onDefault.hash !== anchor.hash) {
|
|
3248
|
+
plans.push({
|
|
3249
|
+
finding: {
|
|
3250
|
+
...base2,
|
|
3251
|
+
state: "drifted",
|
|
3252
|
+
currentHash: onDefault.hash,
|
|
3253
|
+
diffSize: lineDelta(anchor, onDefault.lines),
|
|
3254
|
+
remoteState: "drifted-on-default",
|
|
3255
|
+
...rebaseline ? {
|
|
3256
|
+
outcome: "skipped",
|
|
3257
|
+
outcomeReason: "pinned-ref"
|
|
3258
|
+
} : {}
|
|
3259
|
+
},
|
|
3260
|
+
anchor
|
|
3261
|
+
});
|
|
3262
|
+
continue;
|
|
3263
|
+
}
|
|
3264
|
+
const backfill = anchor.resolved_at === void 0 && !frozen;
|
|
3265
|
+
const refresh = !check && (restamp || backfill);
|
|
3266
|
+
plans.push({
|
|
3267
|
+
finding: {
|
|
3268
|
+
...base2,
|
|
3269
|
+
state: "match",
|
|
3270
|
+
currentHash,
|
|
3271
|
+
hashKind: kind,
|
|
3272
|
+
...producedBy ? { resolver: producedBy } : {},
|
|
3273
|
+
...pinned ? { remoteState: "matches-ref" } : {}
|
|
3274
|
+
},
|
|
3275
|
+
anchor: refresh ? { ...anchor, resolved_at: now() } : anchor,
|
|
3276
|
+
...refresh ? { write: "refresh" } : {}
|
|
3277
|
+
});
|
|
3278
|
+
}
|
|
3279
|
+
return plans;
|
|
3280
|
+
}
|
|
3281
|
+
function lineDelta(anchor, current) {
|
|
3282
|
+
return anchor.lines === void 0 ? null : Math.abs(current - anchor.lines);
|
|
3283
|
+
}
|
|
3284
|
+
function headHash(source, anchor, resolvers) {
|
|
3285
|
+
if (source.head === void 0) return void 0;
|
|
3286
|
+
const outcome = resolveAnchorSpan(source.head, anchor, resolvers);
|
|
3287
|
+
if (!outcome.ok) return void 0;
|
|
3288
|
+
return {
|
|
3289
|
+
hash: hashAnchorText(outcome.span.text),
|
|
3290
|
+
lines: outcome.span.endLine - outcome.span.startLine + 1
|
|
3291
|
+
};
|
|
3292
|
+
}
|
|
3293
|
+
|
|
3294
|
+
// src/commands/anchor-resolve/command.ts
|
|
3049
3295
|
var anchorResolveCommand = define({
|
|
3050
3296
|
name: "anchor-resolve",
|
|
3051
3297
|
tool: "kb_anchor_resolve",
|
|
3052
3298
|
usage: "anchor-resolve <concept-id> [--repo-root <path>] [--offline] [--rebaseline] [--restamp] [--check]",
|
|
3053
|
-
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.
|
|
3054
|
-
input:
|
|
3299
|
+
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.",
|
|
3300
|
+
input: z9.object({
|
|
3055
3301
|
bundlePath,
|
|
3056
3302
|
conceptId,
|
|
3057
|
-
repoRoot:
|
|
3058
|
-
offline:
|
|
3303
|
+
repoRoot: z9.string().min(1).optional(),
|
|
3304
|
+
offline: z9.boolean().optional().describe(
|
|
3059
3305
|
"Resolve foreign anchors from the local repo cache only, never fetching."
|
|
3060
3306
|
),
|
|
3061
|
-
rebaseline:
|
|
3307
|
+
rebaseline: z9.boolean().optional().describe(
|
|
3062
3308
|
"Accept the current code as the new baseline for anchors that drifted."
|
|
3063
3309
|
),
|
|
3064
|
-
restamp:
|
|
3310
|
+
restamp: z9.boolean().optional().describe(
|
|
3065
3311
|
"Refresh `resolved_at` on anchors that already match. Off by default, so a green run writes nothing."
|
|
3066
3312
|
),
|
|
3067
|
-
check:
|
|
3313
|
+
check: z9.boolean().optional().describe(
|
|
3068
3314
|
"Resolve and report only: no hash, no `resolved_at`, no log entry."
|
|
3069
3315
|
)
|
|
3070
3316
|
}),
|
|
@@ -3103,221 +3349,62 @@ var anchorResolveCommand = define({
|
|
|
3103
3349
|
note: "record has no anchors"
|
|
3104
3350
|
};
|
|
3105
3351
|
}
|
|
3106
|
-
const
|
|
3107
|
-
const
|
|
3108
|
-
|
|
3109
|
-
|
|
3110
|
-
|
|
3111
|
-
|
|
3112
|
-
|
|
3113
|
-
|
|
3114
|
-
|
|
3115
|
-
|
|
3116
|
-
|
|
3117
|
-
|
|
3118
|
-
|
|
3119
|
-
|
|
3120
|
-
|
|
3121
|
-
|
|
3122
|
-
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
const source = sources.get(anchor);
|
|
3126
|
-
if (source.repo) base2.repo = source.repo;
|
|
3127
|
-
if (!source.ok) {
|
|
3128
|
-
results.push({ ...base2, state: "unresolved", reason: source.reason });
|
|
3129
|
-
updated.push(anchor);
|
|
3130
|
-
continue;
|
|
3131
|
-
}
|
|
3132
|
-
const outcome = resolveAnchorSpan(source.source, anchor, resolvers);
|
|
3133
|
-
if (!outcome.ok) {
|
|
3134
|
-
results.push({
|
|
3135
|
-
...base2,
|
|
3136
|
-
state: "unresolved",
|
|
3137
|
-
reason: outcome.reason
|
|
3138
|
-
});
|
|
3139
|
-
updated.push(anchor);
|
|
3140
|
-
continue;
|
|
3141
|
-
}
|
|
3142
|
-
const resolved = outcome.span;
|
|
3143
|
-
const producedBy = outcome.resolver;
|
|
3144
|
-
const { hash: currentHash, kind } = anchorHashOf(anchor, outcome);
|
|
3145
|
-
const currentLines = resolved.endLine - resolved.startLine + 1;
|
|
3146
|
-
const stampedKind = outcome.normalized ? "ast" : "raw";
|
|
3147
|
-
const stampedHash = outcome.normalized ? anchorHashOf({ ...anchor, hash: void 0 }, outcome).hash : currentHash;
|
|
3148
|
-
const stamped = {
|
|
3149
|
-
...anchor,
|
|
3150
|
-
hash: stampedHash,
|
|
3151
|
-
hash_kind: stampedKind,
|
|
3152
|
-
lines: currentLines,
|
|
3153
|
-
resolved_at: now(),
|
|
3154
|
-
...producedBy ? { resolver: producedBy } : {}
|
|
3155
|
-
};
|
|
3156
|
-
const pinned = anchor.ref !== void 0 && source.repo !== void 0;
|
|
3157
|
-
if (!anchor.hash) {
|
|
3158
|
-
results.push({
|
|
3159
|
-
...base2,
|
|
3160
|
-
state: check ? "unstamped" : "stamped",
|
|
3161
|
-
currentHash: stampedHash,
|
|
3162
|
-
hashKind: stampedKind,
|
|
3163
|
-
...producedBy ? { resolver: producedBy } : {}
|
|
3164
|
-
});
|
|
3165
|
-
updated.push(stamped);
|
|
3166
|
-
dirty = true;
|
|
3167
|
-
continue;
|
|
3168
|
-
}
|
|
3169
|
-
if (anchor.hash !== currentHash) {
|
|
3170
|
-
results.push({
|
|
3171
|
-
...base2,
|
|
3172
|
-
state: "drifted",
|
|
3173
|
-
currentHash,
|
|
3174
|
-
hashKind: kind,
|
|
3175
|
-
diffSize: lineDelta(anchor, currentLines),
|
|
3176
|
-
...producedBy ? { resolver: producedBy } : {},
|
|
3177
|
-
// A regex-stamped anchor re-read by tree-sitter drifts because the
|
|
3178
|
-
// resolver changed, not because the code did.
|
|
3179
|
-
...resolverChanged(source.source, anchor, producedBy) ? { reason: "resolver-changed" } : {},
|
|
3180
|
-
...pinned ? { remoteState: "drifted-from-ref" } : {},
|
|
3181
|
-
...rebaseline ? { rebaselined: true } : {}
|
|
3182
|
-
});
|
|
3183
|
-
updated.push(rebaseline ? stamped : anchor);
|
|
3184
|
-
if (rebaseline) dirty = true;
|
|
3185
|
-
continue;
|
|
3186
|
-
}
|
|
3187
|
-
const onDefault = pinned ? headHash(source, anchor, resolvers) : void 0;
|
|
3188
|
-
if (onDefault && onDefault.hash !== anchor.hash) {
|
|
3189
|
-
results.push({
|
|
3190
|
-
...base2,
|
|
3191
|
-
state: "drifted",
|
|
3192
|
-
currentHash: onDefault.hash,
|
|
3193
|
-
diffSize: lineDelta(anchor, onDefault.lines),
|
|
3194
|
-
remoteState: "drifted-on-default"
|
|
3195
|
-
});
|
|
3196
|
-
updated.push(anchor);
|
|
3197
|
-
continue;
|
|
3198
|
-
}
|
|
3199
|
-
results.push({
|
|
3200
|
-
...base2,
|
|
3201
|
-
state: "match",
|
|
3202
|
-
currentHash,
|
|
3203
|
-
hashKind: kind,
|
|
3204
|
-
...producedBy ? { resolver: producedBy } : {},
|
|
3205
|
-
...pinned ? { remoteState: "matches-ref" } : {}
|
|
3206
|
-
});
|
|
3207
|
-
const refresh = restamp || anchor.resolved_at === void 0;
|
|
3208
|
-
updated.push(refresh ? { ...anchor, resolved_at: now() } : anchor);
|
|
3209
|
-
if (refresh) dirty = true;
|
|
3210
|
-
}
|
|
3211
|
-
let frozen = false;
|
|
3212
|
-
if (dirty && !check) {
|
|
3213
|
-
try {
|
|
3214
|
-
await assertBaseNotFrozen(process.cwd(), path);
|
|
3215
|
-
} catch (error) {
|
|
3216
|
-
if (!(error instanceof KbBaseFrozenError)) throw error;
|
|
3217
|
-
frozen = true;
|
|
3218
|
-
}
|
|
3219
|
-
if (!frozen) await store.updateAnchors(path, id, updated, actor);
|
|
3220
|
-
}
|
|
3221
|
-
const frozenNote = frozen ? { frozen: true, note: "base is frozen: nothing was stamped" } : {};
|
|
3352
|
+
const frozen = check ? false : await baseFrozen(process.cwd(), path);
|
|
3353
|
+
const plans = await planAnchors(anchors, {
|
|
3354
|
+
root,
|
|
3355
|
+
offline: offline === true,
|
|
3356
|
+
rebaseline: rebaseline === true,
|
|
3357
|
+
restamp: restamp === true,
|
|
3358
|
+
check: check === true,
|
|
3359
|
+
frozen,
|
|
3360
|
+
now
|
|
3361
|
+
});
|
|
3362
|
+
const applied = await applyPlan(plans, {
|
|
3363
|
+
store,
|
|
3364
|
+
actor,
|
|
3365
|
+
bundlePath: path,
|
|
3366
|
+
conceptId: id,
|
|
3367
|
+
frozen
|
|
3368
|
+
});
|
|
3369
|
+
const results = applied.results;
|
|
3370
|
+
const refused = frozen && plans.some((plan) => plan.write);
|
|
3222
3371
|
const hints = grammarHints();
|
|
3223
3372
|
const hintNote = hints.length ? { hints } : {};
|
|
3224
3373
|
const unreachable = results.filter(
|
|
3225
3374
|
(entry) => isUncheckedReason(entry.reason)
|
|
3226
3375
|
).length;
|
|
3227
3376
|
const matches3 = results.filter((entry) => entry.state === "match").length;
|
|
3228
|
-
const note =
|
|
3377
|
+
const note = [
|
|
3378
|
+
unreachable ? `${matches3}/${results.length - unreachable} anchors match, ${unreachable} unreachable` : "",
|
|
3379
|
+
refused ? "base is frozen: nothing was stamped" : "",
|
|
3380
|
+
applied.error ? `nothing was written: ${applied.error}` : ""
|
|
3381
|
+
].filter(Boolean).join("; ");
|
|
3229
3382
|
return {
|
|
3230
3383
|
conceptId: id,
|
|
3231
3384
|
results,
|
|
3232
|
-
...
|
|
3233
|
-
...
|
|
3385
|
+
...note ? { note } : {},
|
|
3386
|
+
...refused ? { frozen: true } : {},
|
|
3234
3387
|
...hintNote
|
|
3235
3388
|
};
|
|
3236
3389
|
},
|
|
3390
|
+
// Drift is a finding until a write settles it: a rebaseline the base took is
|
|
3391
|
+
// the answer to the drift it reports, while one refused, skipped, or never
|
|
3392
|
+
// asked for leaves the gate exactly what it was meant to catch.
|
|
3393
|
+
//
|
|
3237
3394
|
// A stored hash that no longer resolves is a broken anchor, not an absence:
|
|
3238
|
-
// the file was deleted or the symbol renamed
|
|
3239
|
-
//
|
|
3240
|
-
//
|
|
3241
|
-
//
|
|
3242
|
-
// would gate on work this command did not do.
|
|
3395
|
+
// the file was deleted or the symbol renamed. An anchor nobody ever stamped
|
|
3396
|
+
// is still just unstamped, and one whose remote nothing could reach was
|
|
3397
|
+
// never checked — failing CI on either would gate on work this command did
|
|
3398
|
+
// not do.
|
|
3243
3399
|
failsWhen: (result) => result.results.some(
|
|
3244
|
-
(entry) => entry.state === "drifted" || entry.state === "unresolved" && entry.storedHash !== void 0 && !isUncheckedReason(entry.reason)
|
|
3400
|
+
(entry) => entry.outcome === "failed" || entry.outcome === "skipped" || entry.state === "drifted" && entry.outcome !== "applied" || entry.state === "unresolved" && entry.storedHash !== void 0 && !isUncheckedReason(entry.reason)
|
|
3245
3401
|
)
|
|
3246
3402
|
});
|
|
3247
|
-
function lineDelta(anchor, current) {
|
|
3248
|
-
return anchor.lines === void 0 ? null : Math.abs(current - anchor.lines);
|
|
3249
|
-
}
|
|
3250
|
-
function headHash(source, anchor, resolvers) {
|
|
3251
|
-
if (source.head === void 0) return void 0;
|
|
3252
|
-
const outcome = resolveAnchorSpan(source.head, anchor, resolvers);
|
|
3253
|
-
if (!outcome.ok) return void 0;
|
|
3254
|
-
return {
|
|
3255
|
-
hash: hashAnchorText(outcome.span.text),
|
|
3256
|
-
lines: outcome.span.endLine - outcome.span.startLine + 1
|
|
3257
|
-
};
|
|
3258
|
-
}
|
|
3259
|
-
async function readSources(anchors, root, offline) {
|
|
3260
|
-
const origin = new LazyOrigin(root);
|
|
3261
|
-
if (anchors.some((anchor) => anchor.repo)) await origin.prime();
|
|
3262
|
-
const foreign = new Map(
|
|
3263
|
-
anchors.map((anchor) => [anchor, origin.isForeign(anchor)])
|
|
3264
|
-
);
|
|
3265
|
-
const local = anchors.filter(
|
|
3266
|
-
(anchor) => !foreign.get(anchor) && anchor.side !== "old"
|
|
3267
|
-
);
|
|
3268
|
-
const committed = anchors.filter(
|
|
3269
|
-
(anchor) => !foreign.get(anchor) && anchor.side === "old"
|
|
3270
|
-
);
|
|
3271
|
-
const remote = anchors.filter((anchor) => foreign.get(anchor));
|
|
3272
|
-
const reads = await readAnchorFiles(
|
|
3273
|
-
local.map((anchor) => anchor.file),
|
|
3274
|
-
anchorFileReader(root)
|
|
3275
|
-
);
|
|
3276
|
-
const atRef = await readCommitted(root, committed);
|
|
3277
|
-
const blobs = await readRemoteAnchors(remote.flatMap(remoteWants), {
|
|
3278
|
-
offline
|
|
3279
|
-
});
|
|
3280
|
-
const sources = /* @__PURE__ */ new Map();
|
|
3281
|
-
for (const anchor of local) {
|
|
3282
|
-
const read = reads.get(anchor.file);
|
|
3283
|
-
sources.set(
|
|
3284
|
-
anchor,
|
|
3285
|
-
read.ok ? { ok: true, source: read.source } : { ok: false, reason: read.reason }
|
|
3286
|
-
);
|
|
3287
|
-
}
|
|
3288
|
-
for (const anchor of committed) {
|
|
3289
|
-
const read = atRef.get(atRefKey(anchor));
|
|
3290
|
-
sources.set(
|
|
3291
|
-
anchor,
|
|
3292
|
-
read.ok ? { ok: true, source: read.source } : { ok: false, reason: read.reason }
|
|
3293
|
-
);
|
|
3294
|
-
}
|
|
3295
|
-
for (const anchor of remote) {
|
|
3296
|
-
const repo = anchor.repo;
|
|
3297
|
-
const key2 = normalizeRepoUrl(repo);
|
|
3298
|
-
const atDefault = blobs.get(wantKey(key2, void 0, anchor.file));
|
|
3299
|
-
const primary = anchor.ref ? blobs.get(wantKey(key2, anchor.ref, anchor.file)) : atDefault;
|
|
3300
|
-
if (!primary?.ok) {
|
|
3301
|
-
sources.set(anchor, {
|
|
3302
|
-
ok: false,
|
|
3303
|
-
reason: primary?.ok === false ? primary.reason : "remote-unreachable",
|
|
3304
|
-
repo
|
|
3305
|
-
});
|
|
3306
|
-
continue;
|
|
3307
|
-
}
|
|
3308
|
-
sources.set(anchor, {
|
|
3309
|
-
ok: true,
|
|
3310
|
-
source: primary.source,
|
|
3311
|
-
repo,
|
|
3312
|
-
...anchor.ref && atDefault?.ok ? { head: atDefault.source } : {}
|
|
3313
|
-
});
|
|
3314
|
-
}
|
|
3315
|
-
return sources;
|
|
3316
|
-
}
|
|
3317
3403
|
|
|
3318
3404
|
// src/commands/anchor-set/command.ts
|
|
3319
3405
|
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.";
|
|
3320
3406
|
var STAMPED_NOTE = "pointers set and stamped against the current code. Not verification: run verify separately if someone reviewed it.";
|
|
3407
|
+
var INCOMPLETE_NOTE = "pointers set, but not every anchor was stamped: see each resolved entry's state and outcome.";
|
|
3321
3408
|
var anchorSetCommand = define({
|
|
3322
3409
|
name: "anchor-set",
|
|
3323
3410
|
tool: "kb_anchor_set",
|
|
@@ -3374,23 +3461,29 @@ var anchorSetCommand = define({
|
|
|
3374
3461
|
})
|
|
3375
3462
|
);
|
|
3376
3463
|
const after = await store.read(path, id);
|
|
3464
|
+
const stamped = resolved.results.every(
|
|
3465
|
+
(entry) => entry.state === "match" || entry.outcome === "applied"
|
|
3466
|
+
);
|
|
3377
3467
|
return {
|
|
3378
3468
|
conceptId: id,
|
|
3379
3469
|
reason: input.reason,
|
|
3380
3470
|
changes,
|
|
3381
3471
|
anchors: after?.frontmatter.strauss_anchors ?? [],
|
|
3382
|
-
baseline: "stamped",
|
|
3472
|
+
baseline: stamped ? "stamped" : "incomplete",
|
|
3383
3473
|
resolved: resolved.results,
|
|
3384
|
-
note: STAMPED_NOTE
|
|
3474
|
+
note: stamped ? STAMPED_NOTE : INCOMPLETE_NOTE
|
|
3385
3475
|
};
|
|
3386
3476
|
},
|
|
3387
3477
|
// With `resolve`, a pointer that names nothing is a failed set, not a
|
|
3388
|
-
// finding to read later
|
|
3389
|
-
//
|
|
3390
|
-
|
|
3391
|
-
|
|
3392
|
-
|
|
3393
|
-
|
|
3478
|
+
// finding to read later, and a stamp that did not land fails as it does in
|
|
3479
|
+
// anchor-resolve. A remote nothing could reach was never checked, so it does
|
|
3480
|
+
// not fail — the same line anchor-resolve draws.
|
|
3481
|
+
failsWhen: (result, input) => {
|
|
3482
|
+
const resolved = result.resolved ?? [];
|
|
3483
|
+
return resolved.some(
|
|
3484
|
+
(entry) => entry.state === "unresolved" && !isUncheckedReason(entry.reason)
|
|
3485
|
+
) || anchorResolveCommand.failsWhen?.({ results: resolved }, input) === true;
|
|
3486
|
+
}
|
|
3394
3487
|
});
|
|
3395
3488
|
|
|
3396
3489
|
// src/adjudicate.ts
|
|
@@ -5227,16 +5320,16 @@ function recordType(conceptId2) {
|
|
|
5227
5320
|
}
|
|
5228
5321
|
|
|
5229
5322
|
// src/commands/promote/model.ts
|
|
5230
|
-
import { z as
|
|
5231
|
-
var promoteInputSchema =
|
|
5323
|
+
import { z as z10 } from "zod";
|
|
5324
|
+
var promoteInputSchema = z10.object({
|
|
5232
5325
|
bundlePath,
|
|
5233
|
-
conceptIds:
|
|
5234
|
-
to:
|
|
5235
|
-
source:
|
|
5326
|
+
conceptIds: z10.array(conceptId).max(64).optional().describe("Records to copy into the target base. Omit with `list`."),
|
|
5327
|
+
to: z10.string().min(1).optional().describe("Absolute path to the base being promoted into."),
|
|
5328
|
+
source: z10.string().min(1).optional().describe(
|
|
5236
5329
|
"Where the promotion came from, usually the pull request URL. Recorded on each copy as a source."
|
|
5237
5330
|
),
|
|
5238
|
-
force:
|
|
5239
|
-
list:
|
|
5331
|
+
force: z10.boolean().optional().describe("Overwrite a record the target base already holds."),
|
|
5332
|
+
list: z10.boolean().optional().describe("List the source base's candidates instead of promoting.")
|
|
5240
5333
|
}).refine((input) => input.list === true || input.to !== void 0, {
|
|
5241
5334
|
message: "promote needs a target base \u2014 pass --to <bundle>, or --list",
|
|
5242
5335
|
path: ["to"]
|
|
@@ -5374,14 +5467,14 @@ function renderPromote(result) {
|
|
|
5374
5467
|
}
|
|
5375
5468
|
|
|
5376
5469
|
// src/kb-log.ts
|
|
5377
|
-
import { z as
|
|
5470
|
+
import { z as z11 } from "zod";
|
|
5378
5471
|
var LOG_FILE = "log.jsonl";
|
|
5379
|
-
var kbLogAnchorChangeSchema =
|
|
5380
|
-
op:
|
|
5472
|
+
var kbLogAnchorChangeSchema = z11.object({
|
|
5473
|
+
op: z11.enum(["move", "add", "drop"]),
|
|
5381
5474
|
from: kbAnchorLocatorSchema.optional(),
|
|
5382
5475
|
to: kbAnchorLocatorSchema.optional()
|
|
5383
5476
|
}).strict();
|
|
5384
|
-
var kbLogEntryFields =
|
|
5477
|
+
var kbLogEntryFields = z11.object({
|
|
5385
5478
|
// Validated, not just `min(1)`: `at` is a sort key (see `parseLog`
|
|
5386
5479
|
// below), and a value that isn't actually chronological — a Unix
|
|
5387
5480
|
// timestamp, a human-typed date, garbage — would sort wrong without
|
|
@@ -5390,23 +5483,23 @@ var kbLogEntryFields = z10.object({
|
|
|
5390
5483
|
// and rejects everything else, including a non-`Z` offset — so a
|
|
5391
5484
|
// malformed `at` is reported the same way a malformed line already is,
|
|
5392
5485
|
// rather than silently sorting into the wrong place.
|
|
5393
|
-
at:
|
|
5394
|
-
by:
|
|
5395
|
-
operation:
|
|
5396
|
-
conceptId:
|
|
5486
|
+
at: z11.iso.datetime(),
|
|
5487
|
+
by: z11.string().min(1),
|
|
5488
|
+
operation: z11.string().min(1),
|
|
5489
|
+
conceptId: z11.string().min(1),
|
|
5397
5490
|
/**
|
|
5398
5491
|
* The operation's other end, where it has one: a second concept id for
|
|
5399
5492
|
* supersession, the other base's path for promotion.
|
|
5400
5493
|
*/
|
|
5401
|
-
target:
|
|
5494
|
+
target: z11.string().min(1).optional(),
|
|
5402
5495
|
/**
|
|
5403
5496
|
* Why the operation was performed, where the operation demands one.
|
|
5404
5497
|
* `anchor-set` does: a pointer moved by a reader is only auditable if
|
|
5405
5498
|
* the reading is recorded beside it.
|
|
5406
5499
|
*/
|
|
5407
|
-
reason:
|
|
5500
|
+
reason: z11.string().min(1).optional(),
|
|
5408
5501
|
/** What `anchor-set` changed, derived from the record before and after. */
|
|
5409
|
-
anchors:
|
|
5502
|
+
anchors: z11.array(kbLogAnchorChangeSchema).optional()
|
|
5410
5503
|
});
|
|
5411
5504
|
var kbLogEntrySchema = kbLogEntryFields.passthrough();
|
|
5412
5505
|
var kbLogEntryWriteSchema = kbLogEntryFields.strict();
|
|
@@ -5450,14 +5543,14 @@ function parseLog(raw) {
|
|
|
5450
5543
|
}
|
|
5451
5544
|
|
|
5452
5545
|
// src/json-schema.ts
|
|
5453
|
-
import { z as
|
|
5546
|
+
import { z as z12 } from "zod";
|
|
5454
5547
|
function kbJsonSchemas() {
|
|
5455
5548
|
return {
|
|
5456
|
-
recordFrontmatter:
|
|
5549
|
+
recordFrontmatter: z12.toJSONSchema(kbRecordFrontmatterSchema, {
|
|
5457
5550
|
io: "input"
|
|
5458
5551
|
}),
|
|
5459
|
-
composeInput:
|
|
5460
|
-
logEntry:
|
|
5552
|
+
composeInput: z12.toJSONSchema(composeInputSchema, { io: "input" }),
|
|
5553
|
+
logEntry: z12.toJSONSchema(kbLogEntrySchema, { io: "input" })
|
|
5461
5554
|
};
|
|
5462
5555
|
}
|
|
5463
5556
|
|
|
@@ -5510,13 +5603,13 @@ function byGeneratedAt(left, right) {
|
|
|
5510
5603
|
}
|
|
5511
5604
|
|
|
5512
5605
|
// src/commands/answer.ts
|
|
5513
|
-
import { z as
|
|
5606
|
+
import { z as z13 } from "zod";
|
|
5514
5607
|
var answerCommand = define({
|
|
5515
5608
|
name: "answer",
|
|
5516
5609
|
tool: "kb_answer",
|
|
5517
5610
|
usage: "answer <concept-id> <answer...>",
|
|
5518
5611
|
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.",
|
|
5519
|
-
input:
|
|
5612
|
+
input: z13.object({ bundlePath, conceptId, answer: z13.string().min(1) }),
|
|
5520
5613
|
fromArgv: (argv, path) => ({
|
|
5521
5614
|
bundlePath: path,
|
|
5522
5615
|
conceptId: argv[1],
|
|
@@ -5530,27 +5623,27 @@ var answerCommand = define({
|
|
|
5530
5623
|
});
|
|
5531
5624
|
|
|
5532
5625
|
// src/commands/backlinks.ts
|
|
5533
|
-
import { z as
|
|
5626
|
+
import { z as z14 } from "zod";
|
|
5534
5627
|
var backlinksCommand = define({
|
|
5535
5628
|
name: "backlinks",
|
|
5536
5629
|
tool: "kb_backlinks",
|
|
5537
5630
|
usage: "backlinks <concept-id>",
|
|
5538
5631
|
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.",
|
|
5539
|
-
input:
|
|
5632
|
+
input: z14.object({ bundlePath, conceptId }),
|
|
5540
5633
|
fromArgv: (argv, path) => ({ bundlePath: path, conceptId: argv[1] }),
|
|
5541
5634
|
run: async ({ store }, { bundlePath: path, conceptId: id }) => store.backlinks(path, id)
|
|
5542
5635
|
});
|
|
5543
5636
|
|
|
5544
5637
|
// src/commands/catalog.ts
|
|
5545
|
-
import { z as
|
|
5638
|
+
import { z as z15 } from "zod";
|
|
5546
5639
|
var catalogCommand = define({
|
|
5547
5640
|
name: "catalog",
|
|
5548
5641
|
tool: "kb_catalog",
|
|
5549
5642
|
usage: "catalog [type] [--tag T]...",
|
|
5550
5643
|
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.",
|
|
5551
|
-
input:
|
|
5644
|
+
input: z15.object({
|
|
5552
5645
|
bundlePath,
|
|
5553
|
-
type:
|
|
5646
|
+
type: z15.enum(KB_RECORD_TYPES).optional(),
|
|
5554
5647
|
tags: TAGS
|
|
5555
5648
|
}),
|
|
5556
5649
|
fromArgv: (argv, path) => {
|
|
@@ -5622,10 +5715,10 @@ function count(value, noun) {
|
|
|
5622
5715
|
import { Buffer } from "buffer";
|
|
5623
5716
|
import { open } from "fs/promises";
|
|
5624
5717
|
import { join as join6 } from "path";
|
|
5625
|
-
import { z as
|
|
5718
|
+
import { z as z18 } from "zod";
|
|
5626
5719
|
|
|
5627
5720
|
// src/commands/match/command.ts
|
|
5628
|
-
import { z as
|
|
5721
|
+
import { z as z17 } from "zod";
|
|
5629
5722
|
|
|
5630
5723
|
// src/commands/match/errors.ts
|
|
5631
5724
|
var KbMatchInputError = class extends BaseError {
|
|
@@ -5645,21 +5738,21 @@ var KbMatchInputError = class extends BaseError {
|
|
|
5645
5738
|
};
|
|
5646
5739
|
|
|
5647
5740
|
// src/commands/match/model.ts
|
|
5648
|
-
import { z as
|
|
5649
|
-
var diffHunkSchema =
|
|
5650
|
-
startLine:
|
|
5651
|
-
endLine:
|
|
5652
|
-
side:
|
|
5741
|
+
import { z as z16 } from "zod";
|
|
5742
|
+
var diffHunkSchema = z16.object({
|
|
5743
|
+
startLine: z16.number().int().positive(),
|
|
5744
|
+
endLine: z16.number().int().positive(),
|
|
5745
|
+
side: z16.enum(["old", "new"]).optional()
|
|
5653
5746
|
}).passthrough();
|
|
5654
|
-
var diffFileSchema =
|
|
5655
|
-
filePath:
|
|
5656
|
-
hunks:
|
|
5747
|
+
var diffFileSchema = z16.object({
|
|
5748
|
+
filePath: z16.string().min(1).describe("Repo-relative, spelled the way anchors are."),
|
|
5749
|
+
hunks: z16.array(diffHunkSchema)
|
|
5657
5750
|
});
|
|
5658
|
-
var symbolRangeSchema =
|
|
5659
|
-
file:
|
|
5660
|
-
symbol:
|
|
5661
|
-
startLine:
|
|
5662
|
-
endLine:
|
|
5751
|
+
var symbolRangeSchema = z16.object({
|
|
5752
|
+
file: z16.string().min(1),
|
|
5753
|
+
symbol: z16.string().min(1),
|
|
5754
|
+
startLine: z16.number().int().positive(),
|
|
5755
|
+
endLine: z16.number().int().positive()
|
|
5663
5756
|
});
|
|
5664
5757
|
|
|
5665
5758
|
// src/commands/match/parse-unified-diff.ts
|
|
@@ -5908,17 +6001,17 @@ var matchCommand = define({
|
|
|
5908
6001
|
tool: "kb_match",
|
|
5909
6002
|
usage: "match --git <base>..<head> | --stdin [--repo-root <path>] [--offline] [--include-non-current]",
|
|
5910
6003
|
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.",
|
|
5911
|
-
input:
|
|
6004
|
+
input: z17.object({
|
|
5912
6005
|
bundlePath,
|
|
5913
|
-
files:
|
|
5914
|
-
symbolRanges:
|
|
6006
|
+
files: z17.array(diffFileSchema).describe("The changed files, each with its post-change line ranges."),
|
|
6007
|
+
symbolRanges: z17.array(symbolRangeSchema).optional().describe(
|
|
5915
6008
|
"Symbol spans the caller already has. Resolved from repoRoot when omitted."
|
|
5916
6009
|
),
|
|
5917
6010
|
repoRoot: REPO_ROOT,
|
|
5918
|
-
offline:
|
|
6011
|
+
offline: z17.boolean().optional().describe(
|
|
5919
6012
|
"Resolve symbol ranges from what is already on disk, never fetching a grammar."
|
|
5920
6013
|
),
|
|
5921
|
-
includeNonCurrent:
|
|
6014
|
+
includeNonCurrent: z17.boolean().optional().describe(
|
|
5922
6015
|
"Return superseded, rejected and unsettled records too, each carrying its standing."
|
|
5923
6016
|
)
|
|
5924
6017
|
}),
|
|
@@ -6022,22 +6115,22 @@ function project(match, ranges, all) {
|
|
|
6022
6115
|
|
|
6023
6116
|
// src/commands/classify.ts
|
|
6024
6117
|
var classifyFileSchema = diffFileSchema.extend({
|
|
6025
|
-
hunks:
|
|
6026
|
-
diffHunkSchema.extend({ lines:
|
|
6118
|
+
hunks: z18.array(
|
|
6119
|
+
diffHunkSchema.extend({ lines: z18.array(z18.string()).optional() })
|
|
6027
6120
|
),
|
|
6028
|
-
renamedFrom:
|
|
6029
|
-
similarity:
|
|
6121
|
+
renamedFrom: z18.string().min(1).optional().describe("Where `git diff -M` says the path came from."),
|
|
6122
|
+
similarity: z18.number().min(0).max(100).optional()
|
|
6030
6123
|
});
|
|
6031
6124
|
var classifyCommand = define({
|
|
6032
6125
|
name: "classify",
|
|
6033
6126
|
tool: "kb_classify",
|
|
6034
6127
|
usage: "classify --git <base>..<head> | --stdin [--repo-root <path>] [--offline]",
|
|
6035
6128
|
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.",
|
|
6036
|
-
input:
|
|
6129
|
+
input: z18.object({
|
|
6037
6130
|
bundlePath,
|
|
6038
|
-
files:
|
|
6131
|
+
files: z18.array(classifyFileSchema).describe("The changed files, each with its line ranges."),
|
|
6039
6132
|
repoRoot: REPO_ROOT,
|
|
6040
|
-
offline:
|
|
6133
|
+
offline: z18.boolean().optional().describe(
|
|
6041
6134
|
"Resolve symbol ranges from what is already on disk, never fetching a grammar."
|
|
6042
6135
|
)
|
|
6043
6136
|
}),
|
|
@@ -6148,29 +6241,29 @@ function renderClassify(result) {
|
|
|
6148
6241
|
}
|
|
6149
6242
|
|
|
6150
6243
|
// src/commands/context.ts
|
|
6151
|
-
import { z as
|
|
6244
|
+
import { z as z19 } from "zod";
|
|
6152
6245
|
var contextCommand = define({
|
|
6153
6246
|
name: "context",
|
|
6154
6247
|
tool: "kb_context",
|
|
6155
6248
|
usage: "context [--profile NAME] [--budget N] [--full-under N] [--exclude-tag T]... [--format json] [--event NAME]",
|
|
6156
6249
|
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.",
|
|
6157
|
-
input:
|
|
6158
|
-
budgetTokens:
|
|
6250
|
+
input: z19.object({
|
|
6251
|
+
budgetTokens: z19.number().int().positive().optional().describe(
|
|
6159
6252
|
"Ceiling on the whole emitted block; past it the command refuses with a list of bases rather than truncating. Defaults to 4000."
|
|
6160
6253
|
),
|
|
6161
|
-
fullUnderTokens:
|
|
6254
|
+
fullUnderTokens: z19.number().int().positive().optional().describe(
|
|
6162
6255
|
"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."
|
|
6163
6256
|
),
|
|
6164
|
-
profile:
|
|
6257
|
+
profile: z19.string().optional().describe(
|
|
6165
6258
|
"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."
|
|
6166
6259
|
),
|
|
6167
|
-
excludeTags:
|
|
6260
|
+
excludeTags: z19.array(z19.string().min(1)).optional().describe(
|
|
6168
6261
|
"Frontmatter tags whose records stay out of the block. The base stays pinned and stays readable by tool; resolved like the budgets."
|
|
6169
6262
|
),
|
|
6170
|
-
format:
|
|
6263
|
+
format: z19.enum(["markdown", "json"]).optional().describe(
|
|
6171
6264
|
"CLI envelope for hook protocols that require strict JSON on stdout. MCP callers omit this \u2014 the block itself is identical."
|
|
6172
6265
|
),
|
|
6173
|
-
event:
|
|
6266
|
+
event: z19.string().optional().describe(
|
|
6174
6267
|
"hookEventName stamped into the JSON envelope. Only meaningful with format=json."
|
|
6175
6268
|
)
|
|
6176
6269
|
}),
|
|
@@ -6209,20 +6302,20 @@ var contextCommand = define({
|
|
|
6209
6302
|
});
|
|
6210
6303
|
|
|
6211
6304
|
// src/commands/doctor.ts
|
|
6212
|
-
import { z as
|
|
6305
|
+
import { z as z21 } from "zod";
|
|
6213
6306
|
|
|
6214
6307
|
// src/commands/reassess.ts
|
|
6215
|
-
import { z as
|
|
6308
|
+
import { z as z20 } from "zod";
|
|
6216
6309
|
var reassessCommand = define({
|
|
6217
6310
|
name: "reassess",
|
|
6218
6311
|
tool: "kb_reassess",
|
|
6219
6312
|
usage: "reassess <concept-id> [--repo-root <path>] [--with-diff]",
|
|
6220
6313
|
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.",
|
|
6221
|
-
input:
|
|
6314
|
+
input: z20.object({
|
|
6222
6315
|
bundlePath,
|
|
6223
6316
|
conceptId,
|
|
6224
6317
|
repoRoot: REPO_ROOT,
|
|
6225
|
-
withDiff:
|
|
6318
|
+
withDiff: z20.boolean().optional().describe(
|
|
6226
6319
|
"Recover each anchor's committed span and render the diff. Reads git history."
|
|
6227
6320
|
)
|
|
6228
6321
|
}),
|
|
@@ -6367,13 +6460,13 @@ function at(file, symbol) {
|
|
|
6367
6460
|
}
|
|
6368
6461
|
|
|
6369
6462
|
// src/commands/doctor.ts
|
|
6370
|
-
var days = (what, fallback) =>
|
|
6463
|
+
var days = (what, fallback) => z21.number().int().positive().optional().describe(`${what} Defaults to ${fallback}.`);
|
|
6371
6464
|
var doctorCommand = define({
|
|
6372
6465
|
name: "doctor",
|
|
6373
6466
|
tool: "kb_doctor",
|
|
6374
6467
|
usage: "doctor [--expiring-days N] [--unverified-days N] [--aging-days N] [--repo-root PATH] [--offline] [--strict] [--drifted [--with-diff]]",
|
|
6375
6468
|
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.",
|
|
6376
|
-
input:
|
|
6469
|
+
input: z21.object({
|
|
6377
6470
|
bundlePath,
|
|
6378
6471
|
repoRoot: REPO_ROOT,
|
|
6379
6472
|
expiringDays: days(
|
|
@@ -6388,16 +6481,16 @@ var doctorCommand = define({
|
|
|
6388
6481
|
"How long a record may stay `open` or `proposed` before `aging` reports it, in days.",
|
|
6389
6482
|
DEFAULT_AGING_DAYS
|
|
6390
6483
|
),
|
|
6391
|
-
offline:
|
|
6484
|
+
offline: z21.boolean().optional().describe(
|
|
6392
6485
|
"Read foreign anchors from the local repo cache only, never fetching."
|
|
6393
6486
|
),
|
|
6394
|
-
strict:
|
|
6487
|
+
strict: z21.boolean().optional().describe(
|
|
6395
6488
|
"Turn an expired record into a non-zero exit for the CLI. No effect on the report itself."
|
|
6396
6489
|
),
|
|
6397
|
-
drifted:
|
|
6490
|
+
drifted: z21.boolean().optional().describe(
|
|
6398
6491
|
"Report only drift, as a reassessment packet per record: claim, per-anchor class, and what depends on it."
|
|
6399
6492
|
),
|
|
6400
|
-
withDiff:
|
|
6493
|
+
withDiff: z21.boolean().optional().describe(
|
|
6401
6494
|
"With `drifted`: recover each anchor's committed span and render the old-vs-new diff. Reads git history."
|
|
6402
6495
|
)
|
|
6403
6496
|
}),
|
|
@@ -6581,7 +6674,7 @@ import {
|
|
|
6581
6674
|
writeFile as writeFile4
|
|
6582
6675
|
} from "fs/promises";
|
|
6583
6676
|
import { join as join7 } from "path";
|
|
6584
|
-
import { z as
|
|
6677
|
+
import { z as z22 } from "zod";
|
|
6585
6678
|
var NUMBERED = /^(\d{4})-(.+)\.md$/;
|
|
6586
6679
|
var MARKER = "<!-- strauss-kb export: ";
|
|
6587
6680
|
var exportCommand = define({
|
|
@@ -6589,10 +6682,10 @@ var exportCommand = define({
|
|
|
6589
6682
|
tool: "kb_export",
|
|
6590
6683
|
usage: "export --format madr --to <dir>",
|
|
6591
6684
|
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.",
|
|
6592
|
-
input:
|
|
6685
|
+
input: z22.object({
|
|
6593
6686
|
bundlePath,
|
|
6594
|
-
format:
|
|
6595
|
-
to:
|
|
6687
|
+
format: z22.enum(["madr"]).describe("Output layout. `madr` is the only one so far."),
|
|
6688
|
+
to: z22.string().min(1).describe("Directory the ADR files are written into.")
|
|
6596
6689
|
}),
|
|
6597
6690
|
fromArgv: (argv, path) => ({
|
|
6598
6691
|
bundlePath: path,
|
|
@@ -6714,19 +6807,19 @@ function bodySections(body) {
|
|
|
6714
6807
|
}
|
|
6715
6808
|
|
|
6716
6809
|
// src/commands/impact.ts
|
|
6717
|
-
import { z as
|
|
6810
|
+
import { z as z23 } from "zod";
|
|
6718
6811
|
var impactCommand = define({
|
|
6719
6812
|
name: "impact",
|
|
6720
6813
|
tool: "kb_impact",
|
|
6721
6814
|
usage: "impact <concept-id> [--depth N] [--rels a,b]",
|
|
6722
6815
|
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.",
|
|
6723
|
-
input:
|
|
6816
|
+
input: z23.object({
|
|
6724
6817
|
bundlePath,
|
|
6725
6818
|
conceptId,
|
|
6726
|
-
depth:
|
|
6819
|
+
depth: z23.number().int().positive().optional().describe(
|
|
6727
6820
|
"Hops out from the record. Unbounded when omitted; a walk this cuts reports truncated: true."
|
|
6728
6821
|
),
|
|
6729
|
-
rels:
|
|
6822
|
+
rels: z23.array(z23.enum(KB_CAUSAL_LINK_RELS)).optional().describe(
|
|
6730
6823
|
"Narrow which rels the walk follows. Defaults to every rel that carries a dependence \u2014 all but related_to."
|
|
6731
6824
|
)
|
|
6732
6825
|
}),
|
|
@@ -6747,15 +6840,15 @@ var impactCommand = define({
|
|
|
6747
6840
|
});
|
|
6748
6841
|
|
|
6749
6842
|
// src/commands/list.ts
|
|
6750
|
-
import { z as
|
|
6843
|
+
import { z as z24 } from "zod";
|
|
6751
6844
|
var listCommand = define({
|
|
6752
6845
|
name: "list",
|
|
6753
6846
|
tool: "kb_list",
|
|
6754
6847
|
usage: "list [type] [--tag T]...",
|
|
6755
6848
|
description: "Every record, optionally one type or tag. For enumerating; use kb_query for a question.",
|
|
6756
|
-
input:
|
|
6849
|
+
input: z24.object({
|
|
6757
6850
|
bundlePath,
|
|
6758
|
-
type:
|
|
6851
|
+
type: z24.enum(KB_RECORD_TYPES).optional(),
|
|
6759
6852
|
tags: TAGS
|
|
6760
6853
|
}),
|
|
6761
6854
|
fromArgv: (argv, path) => {
|
|
@@ -6779,17 +6872,17 @@ var listCommand = define({
|
|
|
6779
6872
|
});
|
|
6780
6873
|
|
|
6781
6874
|
// src/commands/load.ts
|
|
6782
|
-
import { z as
|
|
6875
|
+
import { z as z25 } from "zod";
|
|
6783
6876
|
var loadCommand = define({
|
|
6784
6877
|
name: "load",
|
|
6785
6878
|
tool: "kb_load",
|
|
6786
6879
|
usage: "load [type] [--budget N | --all] [--repo-root PATH]",
|
|
6787
6880
|
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.",
|
|
6788
|
-
input:
|
|
6881
|
+
input: z25.object({
|
|
6789
6882
|
bundlePath,
|
|
6790
|
-
type:
|
|
6791
|
-
budgetTokens:
|
|
6792
|
-
all:
|
|
6883
|
+
type: z25.enum(KB_RECORD_TYPES).optional(),
|
|
6884
|
+
budgetTokens: z25.number().int().positive().optional().describe("Approximate token ceiling. Defaults to 25000."),
|
|
6885
|
+
all: z25.boolean().optional().describe(
|
|
6793
6886
|
"Loads the entire base regardless of size, bypassing the token budget; mutually exclusive with budgetTokens."
|
|
6794
6887
|
),
|
|
6795
6888
|
repoRoot: REPO_ROOT
|
|
@@ -6831,25 +6924,25 @@ var loadCommand = define({
|
|
|
6831
6924
|
});
|
|
6832
6925
|
|
|
6833
6926
|
// src/commands/log.ts
|
|
6834
|
-
import { z as
|
|
6927
|
+
import { z as z26 } from "zod";
|
|
6835
6928
|
var logCommand = define({
|
|
6836
6929
|
name: "log",
|
|
6837
6930
|
tool: "kb_log",
|
|
6838
6931
|
usage: "log",
|
|
6839
6932
|
description: "Who touched what, and when. Append-only; malformed lines are reported, never repaired.",
|
|
6840
|
-
input:
|
|
6933
|
+
input: z26.object({ bundlePath }),
|
|
6841
6934
|
fromArgv: (_argv, path) => ({ bundlePath: path }),
|
|
6842
6935
|
run: ({ store }, { bundlePath: path }) => store.readLog(path)
|
|
6843
6936
|
});
|
|
6844
6937
|
|
|
6845
6938
|
// src/commands/no-decision.ts
|
|
6846
|
-
import { z as
|
|
6939
|
+
import { z as z27 } from "zod";
|
|
6847
6940
|
var noDecisionCommand = define({
|
|
6848
6941
|
name: "no-decision",
|
|
6849
6942
|
tool: "kb_no_decision",
|
|
6850
6943
|
usage: "no-decision <reason...>",
|
|
6851
6944
|
description: "Record in one sentence that a piece of work had nothing to decide. Idempotent.",
|
|
6852
|
-
input:
|
|
6945
|
+
input: z27.object({ bundlePath, reason: z27.string().min(1) }),
|
|
6853
6946
|
fromArgv: (argv, path) => ({
|
|
6854
6947
|
bundlePath: path,
|
|
6855
6948
|
reason: argv.slice(1).join(" ").trim()
|
|
@@ -6866,20 +6959,20 @@ var noDecisionCommand = define({
|
|
|
6866
6959
|
});
|
|
6867
6960
|
|
|
6868
6961
|
// src/commands/pack.ts
|
|
6869
|
-
import { z as
|
|
6962
|
+
import { z as z28 } from "zod";
|
|
6870
6963
|
var packCommand = define({
|
|
6871
6964
|
name: "pack",
|
|
6872
6965
|
tool: "kb_pack",
|
|
6873
6966
|
usage: "pack <conceptId> [--hops N] [--max-nodes N] [--budget N]",
|
|
6874
6967
|
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.",
|
|
6875
|
-
input:
|
|
6968
|
+
input: z28.object({
|
|
6876
6969
|
bundlePath,
|
|
6877
6970
|
conceptId,
|
|
6878
|
-
hops:
|
|
6879
|
-
maxNodes:
|
|
6971
|
+
hops: z28.number().int().positive().optional().describe("How far from the root the walk may reach. Defaults to 2."),
|
|
6972
|
+
maxNodes: z28.number().int().positive().optional().describe(
|
|
6880
6973
|
"How many records the pack may hold, root included. Defaults to 20."
|
|
6881
6974
|
),
|
|
6882
|
-
budgetTokens:
|
|
6975
|
+
budgetTokens: z28.number().int().positive().optional().describe(
|
|
6883
6976
|
"Approximate token ceiling over what is actually emitted. Defaults to 25000."
|
|
6884
6977
|
)
|
|
6885
6978
|
}),
|
|
@@ -6966,22 +7059,22 @@ function warningLabel(warning) {
|
|
|
6966
7059
|
}
|
|
6967
7060
|
|
|
6968
7061
|
// src/commands/pin.ts
|
|
6969
|
-
import { z as
|
|
7062
|
+
import { z as z29 } from "zod";
|
|
6970
7063
|
var pinCommand = define({
|
|
6971
7064
|
name: "pin",
|
|
6972
7065
|
tool: "kb_pin",
|
|
6973
7066
|
usage: "pin [bundle-path] [--mode full|index] [--profiles a,b] [--local|--user] [--frozen|--unfreeze]",
|
|
6974
7067
|
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.",
|
|
6975
|
-
input:
|
|
7068
|
+
input: z29.object({
|
|
6976
7069
|
bundlePath,
|
|
6977
|
-
mode:
|
|
7070
|
+
mode: z29.enum(["full", "index"]).optional().describe(
|
|
6978
7071
|
"full: always emit this base's records whole (still under the block budget); index: never upgrade. Absent: the profile's full-under threshold decides."
|
|
6979
7072
|
),
|
|
6980
|
-
profiles:
|
|
6981
|
-
layer:
|
|
7073
|
+
profiles: z29.array(z29.string()).optional().describe("Context profiles this pin surfaces in. Absent: all of them."),
|
|
7074
|
+
layer: z29.enum(["project", "local", "user"]).optional().describe(
|
|
6982
7075
|
"Which manifest to write: project (committed, default), local (personal, gitignored), user (~/.strauss, every workspace)."
|
|
6983
7076
|
),
|
|
6984
|
-
frozen:
|
|
7077
|
+
frozen: z29.boolean().optional().describe(
|
|
6985
7078
|
"true: the base is concluded \u2014 writes against it refuse while pinned. false: lift a freeze."
|
|
6986
7079
|
)
|
|
6987
7080
|
}),
|
|
@@ -7010,29 +7103,29 @@ var pinCommand = define({
|
|
|
7010
7103
|
});
|
|
7011
7104
|
|
|
7012
7105
|
// src/commands/pins.ts
|
|
7013
|
-
import { z as
|
|
7106
|
+
import { z as z30 } from "zod";
|
|
7014
7107
|
var pinsCommand = define({
|
|
7015
7108
|
name: "pins",
|
|
7016
7109
|
tool: "kb_pins",
|
|
7017
7110
|
usage: "pins",
|
|
7018
7111
|
description: "Every pinned base across the manifest layers, with its layer and whether it resolves to records. Takes no bundlePath.",
|
|
7019
|
-
input:
|
|
7112
|
+
input: z30.object({}),
|
|
7020
7113
|
fromArgv: () => ({}),
|
|
7021
7114
|
run: ({ store }) => listPins(store, process.cwd())
|
|
7022
7115
|
});
|
|
7023
7116
|
|
|
7024
7117
|
// src/commands/query.ts
|
|
7025
|
-
import { z as
|
|
7118
|
+
import { z as z31 } from "zod";
|
|
7026
7119
|
var queryCommand = define({
|
|
7027
7120
|
name: "query",
|
|
7028
7121
|
tool: "kb_query",
|
|
7029
7122
|
usage: "query <text...> [--tag T]... [--repo-root PATH]",
|
|
7030
7123
|
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.",
|
|
7031
|
-
input:
|
|
7124
|
+
input: z31.object({
|
|
7032
7125
|
bundlePath,
|
|
7033
|
-
text:
|
|
7034
|
-
type:
|
|
7035
|
-
includeNonCurrent:
|
|
7126
|
+
text: z31.string().optional(),
|
|
7127
|
+
type: z31.enum(KB_RECORD_TYPES).optional(),
|
|
7128
|
+
includeNonCurrent: z31.boolean().optional(),
|
|
7036
7129
|
tags: TAGS,
|
|
7037
7130
|
repoRoot: REPO_ROOT
|
|
7038
7131
|
}),
|
|
@@ -7066,43 +7159,43 @@ var queryCommand = define({
|
|
|
7066
7159
|
});
|
|
7067
7160
|
|
|
7068
7161
|
// src/commands/read-index.ts
|
|
7069
|
-
import { z as
|
|
7162
|
+
import { z as z32 } from "zod";
|
|
7070
7163
|
var readIndexCommand = define({
|
|
7071
7164
|
name: "index",
|
|
7072
7165
|
tool: "kb_index",
|
|
7073
7166
|
usage: "index",
|
|
7074
7167
|
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.",
|
|
7075
|
-
input:
|
|
7168
|
+
input: z32.object({ bundlePath }),
|
|
7076
7169
|
fromArgv: (_argv, path) => ({ bundlePath: path }),
|
|
7077
7170
|
run: ({ store }, { bundlePath: path }) => store.readIndex(path)
|
|
7078
7171
|
});
|
|
7079
7172
|
|
|
7080
7173
|
// src/commands/schema.ts
|
|
7081
|
-
import { z as
|
|
7174
|
+
import { z as z33 } from "zod";
|
|
7082
7175
|
var schemaCommand = define({
|
|
7083
7176
|
name: "schema",
|
|
7084
7177
|
tool: "kb_schema",
|
|
7085
7178
|
usage: "schema",
|
|
7086
7179
|
description: "JSON Schema for frontmatter, write input, and log entries, generated from the enforcing code.",
|
|
7087
|
-
input:
|
|
7180
|
+
input: z33.object({}),
|
|
7088
7181
|
fromArgv: () => ({}),
|
|
7089
7182
|
run: () => Promise.resolve(kbJsonSchemas())
|
|
7090
7183
|
});
|
|
7091
7184
|
|
|
7092
7185
|
// src/commands/stamp.ts
|
|
7093
7186
|
import { readFile as readFile7 } from "fs/promises";
|
|
7094
|
-
import { z as
|
|
7187
|
+
import { z as z34 } from "zod";
|
|
7095
7188
|
var DIGEST = /^[0-9a-f]{64}$/;
|
|
7096
7189
|
var stampCommand = define({
|
|
7097
7190
|
name: "stamp",
|
|
7098
7191
|
tool: "kb_stamp",
|
|
7099
7192
|
usage: "stamp [--bundle PATH] [--since DIGEST|FILE]",
|
|
7100
7193
|
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.",
|
|
7101
|
-
input:
|
|
7102
|
-
bundlePath:
|
|
7194
|
+
input: z34.object({
|
|
7195
|
+
bundlePath: z34.string().min(1).optional().describe(
|
|
7103
7196
|
"Absolute path to one knowledge base. Omit to stamp every pinned base."
|
|
7104
7197
|
),
|
|
7105
|
-
since:
|
|
7198
|
+
since: z34.string().min(1).optional().describe(
|
|
7106
7199
|
"Prior digest, or path to a prior `stamp --json`; only moved bases return, with changed ids when the baseline is a file."
|
|
7107
7200
|
)
|
|
7108
7201
|
}),
|
|
@@ -7188,16 +7281,16 @@ async function readBaseline(since) {
|
|
|
7188
7281
|
}
|
|
7189
7282
|
|
|
7190
7283
|
// src/commands/status.ts
|
|
7191
|
-
import { z as
|
|
7284
|
+
import { z as z35 } from "zod";
|
|
7192
7285
|
var statusCommand = define({
|
|
7193
7286
|
name: "status",
|
|
7194
7287
|
tool: "kb_status",
|
|
7195
7288
|
usage: "status <concept-id> <status>",
|
|
7196
7289
|
description: "Move a record's status. Compare-and-swap: a concurrent change fails instead of being overwritten.",
|
|
7197
|
-
input:
|
|
7290
|
+
input: z35.object({
|
|
7198
7291
|
bundlePath,
|
|
7199
7292
|
conceptId,
|
|
7200
|
-
status:
|
|
7293
|
+
status: z35.enum(KB_RECORD_STATUSES)
|
|
7201
7294
|
}),
|
|
7202
7295
|
fromArgv: (argv, path) => ({
|
|
7203
7296
|
bundlePath: path,
|
|
@@ -7212,13 +7305,13 @@ var statusCommand = define({
|
|
|
7212
7305
|
});
|
|
7213
7306
|
|
|
7214
7307
|
// src/commands/supersede.ts
|
|
7215
|
-
import { z as
|
|
7308
|
+
import { z as z36 } from "zod";
|
|
7216
7309
|
var supersedeCommand = define({
|
|
7217
7310
|
name: "supersede",
|
|
7218
7311
|
tool: "kb_supersede",
|
|
7219
7312
|
usage: "supersede <concept-id> <replacement-id>",
|
|
7220
7313
|
description: "Mark a record superseded by another, linked in both directions. Use instead of editing a record whose meaning changed.",
|
|
7221
|
-
input:
|
|
7314
|
+
input: z36.object({ bundlePath, conceptId, replacementId: conceptId }),
|
|
7222
7315
|
fromArgv: (argv, path) => ({
|
|
7223
7316
|
bundlePath: path,
|
|
7224
7317
|
conceptId: argv[1],
|
|
@@ -7232,7 +7325,7 @@ var supersedeCommand = define({
|
|
|
7232
7325
|
});
|
|
7233
7326
|
|
|
7234
7327
|
// src/commands/sweep.ts
|
|
7235
|
-
import { z as
|
|
7328
|
+
import { z as z37 } from "zod";
|
|
7236
7329
|
var TERMINAL = [
|
|
7237
7330
|
"resolved",
|
|
7238
7331
|
"rejected",
|
|
@@ -7243,15 +7336,15 @@ var sweepCommand = define({
|
|
|
7243
7336
|
tool: "kb_sweep",
|
|
7244
7337
|
usage: "sweep --tag <tag> --terminal [--dry-run]",
|
|
7245
7338
|
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.",
|
|
7246
|
-
input:
|
|
7339
|
+
input: z37.object({
|
|
7247
7340
|
bundlePath,
|
|
7248
|
-
tag:
|
|
7249
|
-
terminal:
|
|
7341
|
+
tag: z37.string({ error: "sweep needs --tag: it never sweeps a whole base" }).min(1).describe("Only records carrying this tag are considered."),
|
|
7342
|
+
terminal: z37.literal(true, {
|
|
7250
7343
|
error: "sweep needs --terminal: it deletes only settled records"
|
|
7251
7344
|
}).describe(
|
|
7252
7345
|
"Required. Names the only scope sweep deletes: resolved, rejected and superseded records."
|
|
7253
7346
|
),
|
|
7254
|
-
dryRun:
|
|
7347
|
+
dryRun: z37.boolean().optional().describe("Report what would go, and delete nothing.")
|
|
7255
7348
|
}),
|
|
7256
7349
|
fromArgv: (argv, path) => ({
|
|
7257
7350
|
bundlePath: path,
|
|
@@ -7368,16 +7461,16 @@ function renderSweep(result) {
|
|
|
7368
7461
|
}
|
|
7369
7462
|
|
|
7370
7463
|
// src/commands/sync-instructions.ts
|
|
7371
|
-
import { z as
|
|
7464
|
+
import { z as z38 } from "zod";
|
|
7372
7465
|
var syncInstructionsCommand = define({
|
|
7373
7466
|
name: "sync-instructions",
|
|
7374
7467
|
usage: "sync-instructions <file> [--profile NAME] [--budget N] [--full-under N]",
|
|
7375
7468
|
description: "CLI-only: plant the kb_context block between sentinel comments in AGENTS.md or CLAUDE.md, idempotently.",
|
|
7376
|
-
input:
|
|
7377
|
-
file:
|
|
7378
|
-
budgetTokens:
|
|
7379
|
-
fullUnderTokens:
|
|
7380
|
-
profile:
|
|
7469
|
+
input: z38.object({
|
|
7470
|
+
file: z38.string().min(1).describe("The instruction file to edit in place."),
|
|
7471
|
+
budgetTokens: z38.number().int().positive().optional(),
|
|
7472
|
+
fullUnderTokens: z38.number().int().positive().optional(),
|
|
7473
|
+
profile: z38.string().optional()
|
|
7381
7474
|
}),
|
|
7382
7475
|
fromArgv: (argv) => {
|
|
7383
7476
|
const budget = argvFlag(argv, "--budget");
|
|
@@ -7403,17 +7496,17 @@ var syncInstructionsCommand = define({
|
|
|
7403
7496
|
});
|
|
7404
7497
|
|
|
7405
7498
|
// src/commands/trace.ts
|
|
7406
|
-
import { z as
|
|
7499
|
+
import { z as z39 } from "zod";
|
|
7407
7500
|
var traceCommand = define({
|
|
7408
7501
|
name: "trace",
|
|
7409
7502
|
tool: "kb_trace",
|
|
7410
7503
|
usage: "trace <concept-id> [edges...]",
|
|
7411
7504
|
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".',
|
|
7412
|
-
input:
|
|
7505
|
+
input: z39.object({
|
|
7413
7506
|
bundlePath,
|
|
7414
7507
|
conceptId,
|
|
7415
|
-
edges:
|
|
7416
|
-
depth:
|
|
7508
|
+
edges: z39.array(z39.enum(TRACE_EDGES)).optional(),
|
|
7509
|
+
depth: z39.number().int().positive().optional()
|
|
7417
7510
|
}),
|
|
7418
7511
|
fromArgv: (argv, path) => ({
|
|
7419
7512
|
bundlePath: path,
|
|
@@ -7435,37 +7528,37 @@ var traceCommand = define({
|
|
|
7435
7528
|
});
|
|
7436
7529
|
|
|
7437
7530
|
// src/commands/types.ts
|
|
7438
|
-
import { z as
|
|
7531
|
+
import { z as z40 } from "zod";
|
|
7439
7532
|
var typesCommand = define({
|
|
7440
7533
|
name: "types",
|
|
7441
7534
|
tool: "kb_types",
|
|
7442
7535
|
usage: "types",
|
|
7443
7536
|
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.",
|
|
7444
|
-
input:
|
|
7537
|
+
input: z40.object({}),
|
|
7445
7538
|
fromArgv: () => ({}),
|
|
7446
7539
|
run: () => Promise.resolve(RECORD_TYPES)
|
|
7447
7540
|
});
|
|
7448
7541
|
|
|
7449
7542
|
// src/commands/unpin.ts
|
|
7450
|
-
import { z as
|
|
7543
|
+
import { z as z41 } from "zod";
|
|
7451
7544
|
var unpinCommand = define({
|
|
7452
7545
|
name: "unpin",
|
|
7453
7546
|
tool: "kb_unpin",
|
|
7454
7547
|
usage: "unpin [bundle-path]",
|
|
7455
7548
|
description: "Remove a base from every manifest layer that holds it. Reports the layers touched.",
|
|
7456
|
-
input:
|
|
7549
|
+
input: z41.object({ bundlePath }),
|
|
7457
7550
|
fromArgv: (argv, path) => ({ bundlePath: argv[1] ?? path }),
|
|
7458
7551
|
run: (_ctx, { bundlePath: path }) => unpinBase(process.cwd(), path)
|
|
7459
7552
|
});
|
|
7460
7553
|
|
|
7461
7554
|
// src/commands/validate.ts
|
|
7462
|
-
import { z as
|
|
7555
|
+
import { z as z42 } from "zod";
|
|
7463
7556
|
var validateCommand = define({
|
|
7464
7557
|
name: "validate",
|
|
7465
7558
|
tool: "kb_validate",
|
|
7466
7559
|
usage: "validate",
|
|
7467
7560
|
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.",
|
|
7468
|
-
input:
|
|
7561
|
+
input: z42.object({ bundlePath }),
|
|
7469
7562
|
fromArgv: (_argv, path) => ({ bundlePath: path }),
|
|
7470
7563
|
run: async ({ store }, { bundlePath: path }) => validateBundle(await store.list(path)),
|
|
7471
7564
|
// Warnings never fail the exit code; every other severity does.
|
|
@@ -7475,16 +7568,16 @@ var validateCommand = define({
|
|
|
7475
7568
|
});
|
|
7476
7569
|
|
|
7477
7570
|
// src/commands/verify.ts
|
|
7478
|
-
import { z as
|
|
7571
|
+
import { z as z43 } from "zod";
|
|
7479
7572
|
var verifyCommand = define({
|
|
7480
7573
|
name: "verify",
|
|
7481
7574
|
tool: "kb_verify",
|
|
7482
7575
|
usage: "verify <concept-id> --note <text>",
|
|
7483
7576
|
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.",
|
|
7484
|
-
input:
|
|
7577
|
+
input: z43.object({
|
|
7485
7578
|
bundlePath,
|
|
7486
7579
|
conceptId,
|
|
7487
|
-
note:
|
|
7580
|
+
note: z43.string().refine((s) => s.trim().length > 0, {
|
|
7488
7581
|
message: "note must say what the check found"
|
|
7489
7582
|
})
|
|
7490
7583
|
}),
|
|
@@ -7504,15 +7597,15 @@ var verifyCommand = define({
|
|
|
7504
7597
|
});
|
|
7505
7598
|
|
|
7506
7599
|
// src/commands/write.ts
|
|
7507
|
-
import { z as
|
|
7600
|
+
import { z as z44 } from "zod";
|
|
7508
7601
|
var writeCommand = define({
|
|
7509
7602
|
name: "write",
|
|
7510
7603
|
tool: "kb_write",
|
|
7511
7604
|
usage: "write <type> < record.json",
|
|
7512
7605
|
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.",
|
|
7513
|
-
input:
|
|
7606
|
+
input: z44.object({
|
|
7514
7607
|
bundlePath,
|
|
7515
|
-
type:
|
|
7608
|
+
type: z44.enum(KB_RECORD_TYPES),
|
|
7516
7609
|
input: composeInputSchema
|
|
7517
7610
|
}),
|
|
7518
7611
|
fromArgv: async (argv, path, stdin) => ({
|
|
@@ -7536,13 +7629,13 @@ var writeCommand = define({
|
|
|
7536
7629
|
});
|
|
7537
7630
|
|
|
7538
7631
|
// src/commands/write-decision.ts
|
|
7539
|
-
import { z as
|
|
7632
|
+
import { z as z45 } from "zod";
|
|
7540
7633
|
var writeDecisionCommand = define({
|
|
7541
7634
|
name: "write-decision",
|
|
7542
7635
|
tool: "kb_write_decision",
|
|
7543
7636
|
usage: "write-decision < decision.json",
|
|
7544
7637
|
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.",
|
|
7545
|
-
input:
|
|
7638
|
+
input: z45.object({ bundlePath, input: decisionInputSchema }),
|
|
7546
7639
|
fromArgv: async (_argv, path, stdin) => ({
|
|
7547
7640
|
bundlePath: path,
|
|
7548
7641
|
input: JSON.parse(await stdin())
|
|
@@ -8714,7 +8807,7 @@ function typeRank(record) {
|
|
|
8714
8807
|
}
|
|
8715
8808
|
|
|
8716
8809
|
// src/version.ts
|
|
8717
|
-
var VERSION = true ? "0.1.
|
|
8810
|
+
var VERSION = true ? "0.1.23" : "0.0.0-dev";
|
|
8718
8811
|
|
|
8719
8812
|
export {
|
|
8720
8813
|
isCanonicalRepoUrl,
|
|
@@ -8869,4 +8962,4 @@ export {
|
|
|
8869
8962
|
KbStore,
|
|
8870
8963
|
VERSION
|
|
8871
8964
|
};
|
|
8872
|
-
//# sourceMappingURL=chunk-
|
|
8965
|
+
//# sourceMappingURL=chunk-XENLCPL5.js.map
|