@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.
@@ -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. Exits non-zero on drift.",
3054
- input: z8.object({
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: z8.string().min(1).optional(),
3058
- offline: z8.boolean().optional().describe(
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: z8.boolean().optional().describe(
3307
+ rebaseline: z9.boolean().optional().describe(
3062
3308
  "Accept the current code as the new baseline for anchors that drifted."
3063
3309
  ),
3064
- restamp: z8.boolean().optional().describe(
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: z8.boolean().optional().describe(
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 results = [];
3107
- const updated = [];
3108
- let dirty = false;
3109
- const sources = await readSources(anchors, root, offline === true);
3110
- const resolvers = defaultAnchorResolvers({ offline: offline === true });
3111
- await prepareResolvers(
3112
- resolvers,
3113
- anchors.map((anchor) => anchor.file)
3114
- );
3115
- for (const anchor of anchors) {
3116
- const base2 = {
3117
- file: anchor.file,
3118
- ...anchor.symbol ? { symbol: anchor.symbol } : {},
3119
- ...anchor.side === "old" ? { side: "old" } : {},
3120
- // Carried onto unresolved findings too: an anchor that once hashed
3121
- // and now resolves to nothing is a broken anchor, and the exit code
3122
- // has to be able to tell it from one nobody ever stamped.
3123
- ...anchor.hash ? { storedHash: anchor.hash } : {}
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 = `${matches3}/${results.length - unreachable} anchors match, ${unreachable} unreachable`;
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
- ...unreachable ? { note } : {},
3233
- ...frozenNote,
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, and exiting zero on it would
3239
- // let the one edit that destroys an anchor pass the gate that exists to
3240
- // catch it. An anchor nobody ever stamped is still just unstamped, and one
3241
- // whose remote nothing could reach was never checked — failing CI on either
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. A remote nothing could reach was never checked, so
3389
- // it does not fail the same line anchor-resolve draws.
3390
- failsWhen: (result) => (result.resolved ?? []).some((entry) => {
3391
- const { state, reason } = entry;
3392
- return state === "unresolved" && !isUncheckedReason(reason);
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 z9 } from "zod";
5231
- var promoteInputSchema = z9.object({
5323
+ import { z as z10 } from "zod";
5324
+ var promoteInputSchema = z10.object({
5232
5325
  bundlePath,
5233
- conceptIds: z9.array(conceptId).max(64).optional().describe("Records to copy into the target base. Omit with `list`."),
5234
- to: z9.string().min(1).optional().describe("Absolute path to the base being promoted into."),
5235
- source: z9.string().min(1).optional().describe(
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: z9.boolean().optional().describe("Overwrite a record the target base already holds."),
5239
- list: z9.boolean().optional().describe("List the source base's candidates instead of promoting.")
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 z10 } from "zod";
5470
+ import { z as z11 } from "zod";
5378
5471
  var LOG_FILE = "log.jsonl";
5379
- var kbLogAnchorChangeSchema = z10.object({
5380
- op: z10.enum(["move", "add", "drop"]),
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 = z10.object({
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: z10.iso.datetime(),
5394
- by: z10.string().min(1),
5395
- operation: z10.string().min(1),
5396
- conceptId: z10.string().min(1),
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: z10.string().min(1).optional(),
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: z10.string().min(1).optional(),
5500
+ reason: z11.string().min(1).optional(),
5408
5501
  /** What `anchor-set` changed, derived from the record before and after. */
5409
- anchors: z10.array(kbLogAnchorChangeSchema).optional()
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 z11 } from "zod";
5546
+ import { z as z12 } from "zod";
5454
5547
  function kbJsonSchemas() {
5455
5548
  return {
5456
- recordFrontmatter: z11.toJSONSchema(kbRecordFrontmatterSchema, {
5549
+ recordFrontmatter: z12.toJSONSchema(kbRecordFrontmatterSchema, {
5457
5550
  io: "input"
5458
5551
  }),
5459
- composeInput: z11.toJSONSchema(composeInputSchema, { io: "input" }),
5460
- logEntry: z11.toJSONSchema(kbLogEntrySchema, { io: "input" })
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 z12 } from "zod";
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: z12.object({ bundlePath, conceptId, answer: z12.string().min(1) }),
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 z13 } from "zod";
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: z13.object({ bundlePath, conceptId }),
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 z14 } from "zod";
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: z14.object({
5644
+ input: z15.object({
5552
5645
  bundlePath,
5553
- type: z14.enum(KB_RECORD_TYPES).optional(),
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 z17 } from "zod";
5718
+ import { z as z18 } from "zod";
5626
5719
 
5627
5720
  // src/commands/match/command.ts
5628
- import { z as z16 } from "zod";
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 z15 } from "zod";
5649
- var diffHunkSchema = z15.object({
5650
- startLine: z15.number().int().positive(),
5651
- endLine: z15.number().int().positive(),
5652
- side: z15.enum(["old", "new"]).optional()
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 = z15.object({
5655
- filePath: z15.string().min(1).describe("Repo-relative, spelled the way anchors are."),
5656
- hunks: z15.array(diffHunkSchema)
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 = z15.object({
5659
- file: z15.string().min(1),
5660
- symbol: z15.string().min(1),
5661
- startLine: z15.number().int().positive(),
5662
- endLine: z15.number().int().positive()
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: z16.object({
6004
+ input: z17.object({
5912
6005
  bundlePath,
5913
- files: z16.array(diffFileSchema).describe("The changed files, each with its post-change line ranges."),
5914
- symbolRanges: z16.array(symbolRangeSchema).optional().describe(
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: z16.boolean().optional().describe(
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: z16.boolean().optional().describe(
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: z17.array(
6026
- diffHunkSchema.extend({ lines: z17.array(z17.string()).optional() })
6118
+ hunks: z18.array(
6119
+ diffHunkSchema.extend({ lines: z18.array(z18.string()).optional() })
6027
6120
  ),
6028
- renamedFrom: z17.string().min(1).optional().describe("Where `git diff -M` says the path came from."),
6029
- similarity: z17.number().min(0).max(100).optional()
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: z17.object({
6129
+ input: z18.object({
6037
6130
  bundlePath,
6038
- files: z17.array(classifyFileSchema).describe("The changed files, each with its line ranges."),
6131
+ files: z18.array(classifyFileSchema).describe("The changed files, each with its line ranges."),
6039
6132
  repoRoot: REPO_ROOT,
6040
- offline: z17.boolean().optional().describe(
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 z18 } from "zod";
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: z18.object({
6158
- budgetTokens: z18.number().int().positive().optional().describe(
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: z18.number().int().positive().optional().describe(
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: z18.string().optional().describe(
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: z18.array(z18.string().min(1)).optional().describe(
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: z18.enum(["markdown", "json"]).optional().describe(
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: z18.string().optional().describe(
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 z20 } from "zod";
6305
+ import { z as z21 } from "zod";
6213
6306
 
6214
6307
  // src/commands/reassess.ts
6215
- import { z as z19 } from "zod";
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: z19.object({
6314
+ input: z20.object({
6222
6315
  bundlePath,
6223
6316
  conceptId,
6224
6317
  repoRoot: REPO_ROOT,
6225
- withDiff: z19.boolean().optional().describe(
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) => z20.number().int().positive().optional().describe(`${what} Defaults to ${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: z20.object({
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: z20.boolean().optional().describe(
6484
+ offline: z21.boolean().optional().describe(
6392
6485
  "Read foreign anchors from the local repo cache only, never fetching."
6393
6486
  ),
6394
- strict: z20.boolean().optional().describe(
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: z20.boolean().optional().describe(
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: z20.boolean().optional().describe(
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 z21 } from "zod";
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: z21.object({
6685
+ input: z22.object({
6593
6686
  bundlePath,
6594
- format: z21.enum(["madr"]).describe("Output layout. `madr` is the only one so far."),
6595
- to: z21.string().min(1).describe("Directory the ADR files are written into.")
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 z22 } from "zod";
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: z22.object({
6816
+ input: z23.object({
6724
6817
  bundlePath,
6725
6818
  conceptId,
6726
- depth: z22.number().int().positive().optional().describe(
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: z22.array(z22.enum(KB_CAUSAL_LINK_RELS)).optional().describe(
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 z23 } from "zod";
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: z23.object({
6849
+ input: z24.object({
6757
6850
  bundlePath,
6758
- type: z23.enum(KB_RECORD_TYPES).optional(),
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 z24 } from "zod";
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: z24.object({
6881
+ input: z25.object({
6789
6882
  bundlePath,
6790
- type: z24.enum(KB_RECORD_TYPES).optional(),
6791
- budgetTokens: z24.number().int().positive().optional().describe("Approximate token ceiling. Defaults to 25000."),
6792
- all: z24.boolean().optional().describe(
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 z25 } from "zod";
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: z25.object({ bundlePath }),
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 z26 } from "zod";
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: z26.object({ bundlePath, reason: z26.string().min(1) }),
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 z27 } from "zod";
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: z27.object({
6968
+ input: z28.object({
6876
6969
  bundlePath,
6877
6970
  conceptId,
6878
- hops: z27.number().int().positive().optional().describe("How far from the root the walk may reach. Defaults to 2."),
6879
- maxNodes: z27.number().int().positive().optional().describe(
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: z27.number().int().positive().optional().describe(
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 z28 } from "zod";
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: z28.object({
7068
+ input: z29.object({
6976
7069
  bundlePath,
6977
- mode: z28.enum(["full", "index"]).optional().describe(
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: z28.array(z28.string()).optional().describe("Context profiles this pin surfaces in. Absent: all of them."),
6981
- layer: z28.enum(["project", "local", "user"]).optional().describe(
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: z28.boolean().optional().describe(
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 z29 } from "zod";
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: z29.object({}),
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 z30 } from "zod";
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: z30.object({
7124
+ input: z31.object({
7032
7125
  bundlePath,
7033
- text: z30.string().optional(),
7034
- type: z30.enum(KB_RECORD_TYPES).optional(),
7035
- includeNonCurrent: z30.boolean().optional(),
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 z31 } from "zod";
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: z31.object({ bundlePath }),
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 z32 } from "zod";
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: z32.object({}),
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 z33 } from "zod";
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: z33.object({
7102
- bundlePath: z33.string().min(1).optional().describe(
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: z33.string().min(1).optional().describe(
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 z34 } from "zod";
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: z34.object({
7290
+ input: z35.object({
7198
7291
  bundlePath,
7199
7292
  conceptId,
7200
- status: z34.enum(KB_RECORD_STATUSES)
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 z35 } from "zod";
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: z35.object({ bundlePath, conceptId, replacementId: conceptId }),
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 z36 } from "zod";
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: z36.object({
7339
+ input: z37.object({
7247
7340
  bundlePath,
7248
- tag: z36.string({ error: "sweep needs --tag: it never sweeps a whole base" }).min(1).describe("Only records carrying this tag are considered."),
7249
- terminal: z36.literal(true, {
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: z36.boolean().optional().describe("Report what would go, and delete nothing.")
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 z37 } from "zod";
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: z37.object({
7377
- file: z37.string().min(1).describe("The instruction file to edit in place."),
7378
- budgetTokens: z37.number().int().positive().optional(),
7379
- fullUnderTokens: z37.number().int().positive().optional(),
7380
- profile: z37.string().optional()
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 z38 } from "zod";
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: z38.object({
7505
+ input: z39.object({
7413
7506
  bundlePath,
7414
7507
  conceptId,
7415
- edges: z38.array(z38.enum(TRACE_EDGES)).optional(),
7416
- depth: z38.number().int().positive().optional()
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 z39 } from "zod";
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: z39.object({}),
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 z40 } from "zod";
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: z40.object({ bundlePath }),
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 z41 } from "zod";
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: z41.object({ bundlePath }),
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 z42 } from "zod";
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: z42.object({
7577
+ input: z43.object({
7485
7578
  bundlePath,
7486
7579
  conceptId,
7487
- note: z42.string().refine((s) => s.trim().length > 0, {
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 z43 } from "zod";
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: z43.object({
7606
+ input: z44.object({
7514
7607
  bundlePath,
7515
- type: z43.enum(KB_RECORD_TYPES),
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 z44 } from "zod";
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: z44.object({ bundlePath, input: decisionInputSchema }),
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.22" : "0.0.0-dev";
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-AEO5U42S.js.map
8965
+ //# sourceMappingURL=chunk-XENLCPL5.js.map