@anthropologies/claudestory 0.1.58 → 0.1.60

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -5444,8 +5444,48 @@ var init_session_types = __esm({
5444
5444
  maxTicketsPerSession: z9.number().min(0).default(5),
5445
5445
  handoverInterval: z9.number().min(0).default(3),
5446
5446
  compactThreshold: z9.string().default("high"),
5447
- reviewBackends: z9.array(z9.string()).default(["codex", "agent"])
5447
+ reviewBackends: z9.array(z9.string()).default(["codex", "agent"]),
5448
+ // T-181: Multi-lens review config
5449
+ lensConfig: z9.object({
5450
+ lenses: z9.union([z9.literal("auto"), z9.array(z9.string())]).default("auto"),
5451
+ maxLenses: z9.number().min(1).max(8).default(8),
5452
+ lensTimeout: z9.union([
5453
+ z9.number(),
5454
+ z9.object({ default: z9.number(), opus: z9.number() })
5455
+ ]).default({ default: 60, opus: 120 }),
5456
+ findingBudget: z9.number().min(1).default(10),
5457
+ confidenceFloor: z9.number().min(0).max(1).default(0.6),
5458
+ tokenBudgetPerLens: z9.number().min(1e3).default(32e3),
5459
+ hotPaths: z9.array(z9.string()).default([]),
5460
+ lensModels: z9.record(z9.string()).default({ default: "sonnet", security: "opus", concurrency: "opus" })
5461
+ }).optional(),
5462
+ blockingPolicy: z9.object({
5463
+ neverBlock: z9.array(z9.string()).default([]),
5464
+ alwaysBlock: z9.array(z9.string()).default(["injection", "auth-bypass", "hardcoded-secrets"]),
5465
+ planReviewBlockingLenses: z9.array(z9.string()).default(["security", "error-handling"])
5466
+ }).optional(),
5467
+ requireSecretsGate: z9.boolean().default(false),
5468
+ requireAccessibility: z9.boolean().default(false),
5469
+ testMapping: z9.object({
5470
+ strategy: z9.literal("convention"),
5471
+ patterns: z9.array(z9.object({
5472
+ source: z9.string(),
5473
+ test: z9.string()
5474
+ }))
5475
+ }).optional()
5448
5476
  }).default({ maxTicketsPerSession: 5, compactThreshold: "high", reviewBackends: ["codex", "agent"], handoverInterval: 3 }),
5477
+ // T-181: Lens review findings history (for lessons feedback loop)
5478
+ lensReviewHistory: z9.array(z9.object({
5479
+ ticketId: z9.string(),
5480
+ stage: z9.enum(["CODE_REVIEW", "PLAN_REVIEW"]),
5481
+ lens: z9.string(),
5482
+ category: z9.string(),
5483
+ severity: z9.string(),
5484
+ disposition: z9.enum(["open", "addressed", "contested", "deferred"]),
5485
+ description: z9.string(),
5486
+ dismissReason: z9.string().optional(),
5487
+ timestamp: z9.string()
5488
+ })).default([]),
5449
5489
  // T-123: Issue sweep tracking
5450
5490
  issueSweepState: z9.object({
5451
5491
  remaining: z9.array(z9.string()),
@@ -5474,7 +5514,8 @@ var init_session_types = __esm({
5474
5514
  resolvedDefaults: z9.object({
5475
5515
  maxTicketsPerSession: z9.number(),
5476
5516
  compactThreshold: z9.string(),
5477
- reviewBackends: z9.array(z9.string())
5517
+ reviewBackends: z9.array(z9.string()),
5518
+ handoverInterval: z9.number().optional()
5478
5519
  }).optional()
5479
5520
  }).passthrough();
5480
5521
  }
@@ -6315,6 +6356,22 @@ function djb2Hash(content) {
6315
6356
  }
6316
6357
  return hash.toString(36);
6317
6358
  }
6359
+ function buildLensHistoryUpdate(findings, existing, ticketId, stage) {
6360
+ const existingKeys = new Set(
6361
+ existing.map((e) => `${e.ticketId}:${e.stage}:${e.lens}:${e.category}`)
6362
+ );
6363
+ const newEntries = findings.map((f) => ({
6364
+ ticketId,
6365
+ stage,
6366
+ lens: typeof f.lens === "string" && f.lens !== "" ? f.lens : "unknown",
6367
+ category: f.category,
6368
+ severity: f.severity,
6369
+ disposition: f.disposition ?? "open",
6370
+ description: f.description,
6371
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
6372
+ })).filter((e) => !existingKeys.has(`${e.ticketId}:${e.stage}:${e.lens}:${e.category}`));
6373
+ return newEntries.length > 0 ? [...existing, ...newEntries] : null;
6374
+ }
6318
6375
  var StageContext;
6319
6376
  var init_types2 = __esm({
6320
6377
  "src/autonomous/stages/types.ts"() {
@@ -6703,6 +6760,7 @@ var init_plan_review = __esm({
6703
6760
  "src/autonomous/stages/plan-review.ts"() {
6704
6761
  "use strict";
6705
6762
  init_esm_shims();
6763
+ init_types2();
6706
6764
  init_review_depth();
6707
6765
  PlanReviewStage = class {
6708
6766
  id = "PLAN_REVIEW";
@@ -6713,6 +6771,31 @@ var init_plan_review = __esm({
6713
6771
  const reviewer = nextReviewer(existingReviews, backends);
6714
6772
  const risk = ctx.state.ticket?.risk ?? "low";
6715
6773
  const minRounds = requiredRounds(risk);
6774
+ if (reviewer === "lenses") {
6775
+ return {
6776
+ instruction: [
6777
+ `# Multi-Lens Plan Review \u2014 Round ${roundNum} of ${Math.max(minRounds, roundNum)} minimum`,
6778
+ "",
6779
+ "This round uses the **multi-lens review orchestrator** for plan review. It fans out to specialized review agents (Clean Code, Security, Error Handling, and more) in parallel to evaluate the plan from multiple perspectives.",
6780
+ "",
6781
+ "1. Read the plan file",
6782
+ "2. Call `prepareLensReview()` with the plan text (stage: PLAN_REVIEW)",
6783
+ "3. Spawn all lens subagents in parallel",
6784
+ "4. Collect results and pass through the merger and judge pipeline",
6785
+ "5. Report the final SynthesisResult verdict and findings",
6786
+ "",
6787
+ "When done, call `claudestory_autonomous_guide` with:",
6788
+ "```json",
6789
+ `{ "sessionId": "${ctx.state.sessionId}", "action": "report", "report": { "completedAction": "plan_review_round", "verdict": "<approve|revise|reject>", "findings": [...] } }`,
6790
+ "```"
6791
+ ].join("\n"),
6792
+ reminders: [
6793
+ "Report the exact verdict and findings from the synthesizer.",
6794
+ "Lens subagents run in parallel with read-only tools (Read, Grep, Glob)."
6795
+ ],
6796
+ transitionedFrom: ctx.state.previousState ?? void 0
6797
+ };
6798
+ }
6716
6799
  return {
6717
6800
  instruction: [
6718
6801
  `# Plan Review \u2014 Round ${roundNum} of ${Math.max(minRounds, roundNum)} minimum`,
@@ -6774,9 +6857,19 @@ var init_plan_review = __esm({
6774
6857
  nextAction = "PLAN_REVIEW";
6775
6858
  }
6776
6859
  const reviewsForWrite = isReject ? { ...ctx.state.reviews, plan: [] } : { ...ctx.state.reviews, plan: planReviews };
6777
- ctx.writeState({
6860
+ const stateUpdate = {
6778
6861
  reviews: reviewsForWrite
6779
- });
6862
+ };
6863
+ if (reviewerBackend === "lenses" && findings.length > 0) {
6864
+ const updated = buildLensHistoryUpdate(
6865
+ findings,
6866
+ ctx.state.lensReviewHistory ?? [],
6867
+ ctx.state.ticket?.id ?? "unknown",
6868
+ "PLAN_REVIEW"
6869
+ );
6870
+ if (updated) stateUpdate.lensReviewHistory = updated;
6871
+ }
6872
+ ctx.writeState(stateUpdate);
6780
6873
  ctx.appendEvent("plan_review", {
6781
6874
  round: roundNum,
6782
6875
  verdict,
@@ -7140,13 +7233,42 @@ var init_test = __esm({
7140
7233
  }
7141
7234
  });
7142
7235
 
7236
+ // src/autonomous/review-lenses/schema-validator.ts
7237
+ var init_schema_validator = __esm({
7238
+ "src/autonomous/review-lenses/schema-validator.ts"() {
7239
+ "use strict";
7240
+ init_esm_shims();
7241
+ }
7242
+ });
7243
+
7244
+ // src/autonomous/review-lenses/cache.ts
7245
+ import { createHash } from "crypto";
7246
+ import { readFileSync as readFileSync6, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2, existsSync as existsSync9, rmSync as rmSync2, renameSync as renameSync2 } from "fs";
7247
+ import { join as join12 } from "path";
7248
+ function clearCache(sessionDir2) {
7249
+ const dir = join12(sessionDir2, CACHE_DIR);
7250
+ if (!existsSync9(dir)) return;
7251
+ rmSync2(dir, { recursive: true, force: true });
7252
+ }
7253
+ var CACHE_DIR;
7254
+ var init_cache = __esm({
7255
+ "src/autonomous/review-lenses/cache.ts"() {
7256
+ "use strict";
7257
+ init_esm_shims();
7258
+ init_schema_validator();
7259
+ CACHE_DIR = "lens-cache";
7260
+ }
7261
+ });
7262
+
7143
7263
  // src/autonomous/stages/code-review.ts
7144
7264
  var CodeReviewStage;
7145
7265
  var init_code_review = __esm({
7146
7266
  "src/autonomous/stages/code-review.ts"() {
7147
7267
  "use strict";
7148
7268
  init_esm_shims();
7269
+ init_types2();
7149
7270
  init_review_depth();
7271
+ init_cache();
7150
7272
  CodeReviewStage = class {
7151
7273
  id = "CODE_REVIEW";
7152
7274
  async enter(ctx) {
@@ -7159,6 +7281,32 @@ var init_code_review = __esm({
7159
7281
  const mergeBase = ctx.state.git.mergeBase;
7160
7282
  const diffCommand = mergeBase ? `\`git diff ${mergeBase}\`` : `\`git diff HEAD\` AND \`git ls-files --others --exclude-standard\``;
7161
7283
  const diffReminder = mergeBase ? `Run: git diff ${mergeBase} \u2014 pass FULL output to reviewer.` : "Run: git diff HEAD + git ls-files --others --exclude-standard \u2014 pass FULL output to reviewer.";
7284
+ if (reviewer === "lenses") {
7285
+ return {
7286
+ instruction: [
7287
+ `# Multi-Lens Code Review \u2014 Round ${roundNum} of ${rounds} minimum`,
7288
+ "",
7289
+ `Capture the diff with: ${diffCommand}`,
7290
+ "",
7291
+ "This round uses the **multi-lens review orchestrator**. It fans out to specialized review agents (Clean Code, Security, Error Handling, and more) in parallel, then synthesizes findings into a single verdict.",
7292
+ "",
7293
+ "1. Capture the full diff",
7294
+ "2. Call `prepareLensReview()` with the diff and changed file list",
7295
+ "3. Spawn all lens subagents in parallel (each prompt is provided by the orchestrator)",
7296
+ "4. Collect results and pass through the merger and judge pipeline",
7297
+ "5. Report the final SynthesisResult verdict and findings",
7298
+ "",
7299
+ "When done, report verdict and findings."
7300
+ ].join("\n"),
7301
+ reminders: [
7302
+ diffReminder,
7303
+ "Do NOT compress or summarize the diff.",
7304
+ "Lens subagents run in parallel with read-only tools (Read, Grep, Glob).",
7305
+ "If the reviewer flags pre-existing issues unrelated to your changes, file them as issues using claudestory_issue_create with severity and impact. Do not fix them in this ticket."
7306
+ ],
7307
+ transitionedFrom: ctx.state.previousState ?? void 0
7308
+ };
7309
+ }
7162
7310
  return {
7163
7311
  instruction: [
7164
7312
  `# Code Review \u2014 Round ${roundNum} of ${rounds} minimum`,
@@ -7224,8 +7372,10 @@ var init_code_review = __esm({
7224
7372
  nextAction = "CODE_REVIEW";
7225
7373
  }
7226
7374
  if (nextAction === "PLAN") {
7375
+ clearCache(ctx.dir);
7227
7376
  ctx.writeState({
7228
7377
  reviews: { plan: [], code: [] },
7378
+ lensReviewHistory: [],
7229
7379
  ticket: ctx.state.ticket ? { ...ctx.state.ticket, realizedRisk: void 0 } : ctx.state.ticket
7230
7380
  });
7231
7381
  ctx.appendEvent("code_review", {
@@ -7237,9 +7387,19 @@ var init_code_review = __esm({
7237
7387
  await ctx.fileDeferredFindings(findings, "code");
7238
7388
  return { action: "back", target: "PLAN", reason: "plan_redirect" };
7239
7389
  }
7240
- ctx.writeState({
7390
+ const stateUpdate = {
7241
7391
  reviews: { ...ctx.state.reviews, code: codeReviews }
7242
- });
7392
+ };
7393
+ if (reviewerBackend === "lenses" && findings.length > 0) {
7394
+ const updated = buildLensHistoryUpdate(
7395
+ findings,
7396
+ ctx.state.lensReviewHistory ?? [],
7397
+ ctx.state.ticket?.id ?? "unknown",
7398
+ "CODE_REVIEW"
7399
+ );
7400
+ if (updated) stateUpdate.lensReviewHistory = updated;
7401
+ }
7402
+ ctx.writeState(stateUpdate);
7243
7403
  ctx.appendEvent("code_review", {
7244
7404
  round: roundNum,
7245
7405
  verdict,
@@ -8002,6 +8162,44 @@ var init_lesson_capture = __esm({
8002
8162
  planFindings,
8003
8163
  codeFindings
8004
8164
  });
8165
+ const lensHistory = ctx.state.lensReviewHistory ?? [];
8166
+ const dismissed = lensHistory.filter(
8167
+ (f) => f.disposition === "contested"
8168
+ );
8169
+ const tupleCounts = /* @__PURE__ */ new Map();
8170
+ for (const f of lensHistory) {
8171
+ const key = `${f.lens}:${f.category}`;
8172
+ const entry = tupleCounts.get(key) ?? { total: 0, dismissed: 0 };
8173
+ entry.total++;
8174
+ if (f.disposition === "contested") {
8175
+ entry.dismissed++;
8176
+ }
8177
+ tupleCounts.set(key, entry);
8178
+ }
8179
+ const falsePositivePatterns = [];
8180
+ for (const [key, counts] of tupleCounts) {
8181
+ if (counts.total >= 5 && counts.dismissed / counts.total >= 0.6) {
8182
+ falsePositivePatterns.push(
8183
+ `- **${key}**: ${counts.dismissed}/${counts.total} dismissed (${Math.round(counts.dismissed / counts.total * 100)}%)`
8184
+ );
8185
+ }
8186
+ }
8187
+ const lensSection = falsePositivePatterns.length > 0 ? [
8188
+ "",
8189
+ "## Lens False Positive Patterns",
8190
+ "",
8191
+ "These (lens, category) tuples have a >60% dismissal rate over 5+ reviews. Create a lesson for each:",
8192
+ ...falsePositivePatterns,
8193
+ "",
8194
+ 'For each pattern above, create a lesson: "Lens X tends to flag category Y, but this project considers it acceptable because [reason from dismiss history]."',
8195
+ 'Tag with `source: "lens-feedback"` and `tags: ["lens", lens-name]`.'
8196
+ ].join("\n") : "";
8197
+ const dismissedSection = dismissed.length > 0 && falsePositivePatterns.length === 0 ? [
8198
+ "",
8199
+ `## Dismissed Lens Findings (${dismissed.length})`,
8200
+ "",
8201
+ "Some lens findings were dismissed this session. Not enough data for automatic patterns yet (need 5+ reviews per tuple at >60% dismissal rate)."
8202
+ ].join("\n") : "";
8005
8203
  return {
8006
8204
  instruction: [
8007
8205
  "# Capture Lessons from Review Findings",
@@ -8017,15 +8215,18 @@ var init_lesson_capture = __esm({
8017
8215
  " - If it matches an existing lesson \u2192 call `claudestory_lesson_reinforce`",
8018
8216
  ' - If it\'s a new pattern \u2192 call `claudestory_lesson_create` with `source: "review"`',
8019
8217
  "3. Skip patterns that are one-off or already well-covered",
8218
+ lensSection,
8219
+ dismissedSection,
8020
8220
  `4. Call \`claudestory_autonomous_guide\` with completedAction: "lessons_captured"`,
8021
8221
  "",
8022
8222
  "```json",
8023
8223
  `{ "sessionId": "${ctx.state.sessionId}", "action": "report", "report": { "completedAction": "lessons_captured" } }`,
8024
8224
  "```"
8025
- ].join("\n"),
8225
+ ].filter(Boolean).join("\n"),
8026
8226
  reminders: [
8027
8227
  "Check existing lessons first \u2014 reinforce before creating duplicates.",
8028
- "Only capture patterns worth remembering across sessions."
8228
+ "Only capture patterns worth remembering across sessions.",
8229
+ ...falsePositivePatterns.length > 0 ? ["Lens false positive patterns MUST be captured as lessons \u2014 they improve future reviews."] : []
8029
8230
  ]
8030
8231
  };
8031
8232
  }
@@ -8224,8 +8425,8 @@ Impact: ${nextIssue.impact}` : ""}` : `Fix issue ${next}.`,
8224
8425
  });
8225
8426
 
8226
8427
  // src/autonomous/stages/handover.ts
8227
- import { writeFileSync as writeFileSync2 } from "fs";
8228
- import { join as join12 } from "path";
8428
+ import { writeFileSync as writeFileSync3 } from "fs";
8429
+ import { join as join13 } from "path";
8229
8430
  var HandoverStage;
8230
8431
  var init_handover2 = __esm({
8231
8432
  "src/autonomous/stages/handover.ts"() {
@@ -8263,8 +8464,8 @@ var init_handover2 = __esm({
8263
8464
  } catch {
8264
8465
  handoverFailed = true;
8265
8466
  try {
8266
- const fallbackPath = join12(ctx.dir, "handover-fallback.md");
8267
- writeFileSync2(fallbackPath, content, "utf-8");
8467
+ const fallbackPath = join13(ctx.dir, "handover-fallback.md");
8468
+ writeFileSync3(fallbackPath, content, "utf-8");
8268
8469
  } catch {
8269
8470
  }
8270
8471
  }
@@ -8353,8 +8554,8 @@ var init_stages = __esm({
8353
8554
  });
8354
8555
 
8355
8556
  // src/autonomous/version-check.ts
8356
- import { readFileSync as readFileSync6 } from "fs";
8357
- import { join as join13, dirname as dirname4 } from "path";
8557
+ import { readFileSync as readFileSync7 } from "fs";
8558
+ import { join as join14, dirname as dirname4 } from "path";
8358
8559
  import { fileURLToPath as fileURLToPath3 } from "url";
8359
8560
  function checkVersionMismatch(runningVersion, installedVersion) {
8360
8561
  if (!installedVersion) return null;
@@ -8366,12 +8567,12 @@ function getInstalledVersion() {
8366
8567
  try {
8367
8568
  const thisFile = fileURLToPath3(import.meta.url);
8368
8569
  const candidates = [
8369
- join13(dirname4(thisFile), "..", "..", "package.json"),
8370
- join13(dirname4(thisFile), "..", "package.json")
8570
+ join14(dirname4(thisFile), "..", "..", "package.json"),
8571
+ join14(dirname4(thisFile), "..", "package.json")
8371
8572
  ];
8372
8573
  for (const candidate of candidates) {
8373
8574
  try {
8374
- const raw = readFileSync6(candidate, "utf-8");
8575
+ const raw = readFileSync7(candidate, "utf-8");
8375
8576
  const pkg = JSON.parse(raw);
8376
8577
  if (pkg.version) return pkg.version;
8377
8578
  } catch {
@@ -8383,7 +8584,7 @@ function getInstalledVersion() {
8383
8584
  }
8384
8585
  }
8385
8586
  function getRunningVersion() {
8386
- return "0.1.58";
8587
+ return "0.1.60";
8387
8588
  }
8388
8589
  var init_version_check = __esm({
8389
8590
  "src/autonomous/version-check.ts"() {
@@ -8393,23 +8594,23 @@ var init_version_check = __esm({
8393
8594
  });
8394
8595
 
8395
8596
  // src/autonomous/guide.ts
8396
- import { readFileSync as readFileSync7, writeFileSync as writeFileSync3, readdirSync as readdirSync4 } from "fs";
8397
- import { join as join14 } from "path";
8597
+ import { readFileSync as readFileSync8, writeFileSync as writeFileSync4, readdirSync as readdirSync4 } from "fs";
8598
+ import { join as join15 } from "path";
8398
8599
  function buildGuideRecommendOptions(root) {
8399
8600
  const opts = {};
8400
8601
  try {
8401
- const handoversDir = join14(root, ".story", "handovers");
8602
+ const handoversDir = join15(root, ".story", "handovers");
8402
8603
  const files = readdirSync4(handoversDir, "utf-8").filter((f) => f.endsWith(".md")).sort();
8403
8604
  if (files.length > 0) {
8404
- opts.latestHandoverContent = readFileSync7(join14(handoversDir, files[files.length - 1]), "utf-8");
8605
+ opts.latestHandoverContent = readFileSync8(join15(handoversDir, files[files.length - 1]), "utf-8");
8405
8606
  }
8406
8607
  } catch {
8407
8608
  }
8408
8609
  try {
8409
- const snapshotsDir = join14(root, ".story", "snapshots");
8610
+ const snapshotsDir = join15(root, ".story", "snapshots");
8410
8611
  const snapFiles = readdirSync4(snapshotsDir, "utf-8").filter((f) => f.endsWith(".json")).sort();
8411
8612
  if (snapFiles.length > 0) {
8412
- const raw = readFileSync7(join14(snapshotsDir, snapFiles[snapFiles.length - 1]), "utf-8");
8613
+ const raw = readFileSync8(join15(snapshotsDir, snapFiles[snapFiles.length - 1]), "utf-8");
8413
8614
  const snap = JSON.parse(raw);
8414
8615
  if (snap.issues) {
8415
8616
  opts.previousOpenIssueCount = snap.issues.filter((i) => i.status !== "resolved").length;
@@ -8791,7 +8992,7 @@ Staged: ${stagedResult.data.join(", ")}`
8791
8992
  }
8792
8993
  }
8793
8994
  const { state: projectState, warnings } = await loadProject(root);
8794
- const handoversDir = join14(root, ".story", "handovers");
8995
+ const handoversDir = join15(root, ".story", "handovers");
8795
8996
  const ctx = { state: projectState, warnings, root, handoversDir, format: "md" };
8796
8997
  let handoverText = "";
8797
8998
  try {
@@ -8808,7 +9009,7 @@ Staged: ${stagedResult.data.join(", ")}`
8808
9009
  }
8809
9010
  } catch {
8810
9011
  }
8811
- const rulesText = readFileSafe2(join14(root, "RULES.md"));
9012
+ const rulesText = readFileSafe2(join15(root, "RULES.md"));
8812
9013
  const lessonDigest = buildLessonDigest(projectState.lessons);
8813
9014
  const digestParts = [
8814
9015
  handoverText ? `## Recent Handovers
@@ -8824,7 +9025,7 @@ ${rulesText}` : "",
8824
9025
  ].filter(Boolean);
8825
9026
  const digest = digestParts.join("\n\n---\n\n");
8826
9027
  try {
8827
- writeFileSync3(join14(dir, "context-digest.md"), digest, "utf-8");
9028
+ writeFileSync4(join15(dir, "context-digest.md"), digest, "utf-8");
8828
9029
  } catch {
8829
9030
  }
8830
9031
  if (mode !== "auto" && args.ticketId) {
@@ -9576,7 +9777,7 @@ function guideError(err) {
9576
9777
  }
9577
9778
  function readFileSafe2(path2) {
9578
9779
  try {
9579
- return readFileSync7(path2, "utf-8");
9780
+ return readFileSync8(path2, "utf-8");
9580
9781
  } catch {
9581
9782
  return "";
9582
9783
  }
@@ -9829,8 +10030,8 @@ var init_session_report_formatter = __esm({
9829
10030
  });
9830
10031
 
9831
10032
  // src/cli/commands/session-report.ts
9832
- import { readFileSync as readFileSync8, existsSync as existsSync10 } from "fs";
9833
- import { join as join15 } from "path";
10033
+ import { readFileSync as readFileSync9, existsSync as existsSync11 } from "fs";
10034
+ import { join as join16 } from "path";
9834
10035
  async function handleSessionReport(sessionId, root, format = "md") {
9835
10036
  if (!UUID_REGEX.test(sessionId)) {
9836
10037
  return {
@@ -9841,7 +10042,7 @@ async function handleSessionReport(sessionId, root, format = "md") {
9841
10042
  };
9842
10043
  }
9843
10044
  const dir = sessionDir(root, sessionId);
9844
- if (!existsSync10(dir)) {
10045
+ if (!existsSync11(dir)) {
9845
10046
  return {
9846
10047
  output: `Error: Session ${sessionId} not found.`,
9847
10048
  exitCode: 1,
@@ -9849,8 +10050,8 @@ async function handleSessionReport(sessionId, root, format = "md") {
9849
10050
  isError: true
9850
10051
  };
9851
10052
  }
9852
- const statePath2 = join15(dir, "state.json");
9853
- if (!existsSync10(statePath2)) {
10053
+ const statePath2 = join16(dir, "state.json");
10054
+ if (!existsSync11(statePath2)) {
9854
10055
  return {
9855
10056
  output: `Error: Session ${sessionId} corrupt \u2014 state.json missing.`,
9856
10057
  exitCode: 1,
@@ -9859,7 +10060,7 @@ async function handleSessionReport(sessionId, root, format = "md") {
9859
10060
  };
9860
10061
  }
9861
10062
  try {
9862
- const rawJson = JSON.parse(readFileSync8(statePath2, "utf-8"));
10063
+ const rawJson = JSON.parse(readFileSync9(statePath2, "utf-8"));
9863
10064
  if (rawJson && typeof rawJson === "object" && "schemaVersion" in rawJson && rawJson.schemaVersion !== CURRENT_SESSION_SCHEMA_VERSION) {
9864
10065
  return {
9865
10066
  output: `Error: Session ${sessionId} \u2014 unsupported session schema version ${rawJson.schemaVersion}.`,
@@ -9888,7 +10089,7 @@ async function handleSessionReport(sessionId, root, format = "md") {
9888
10089
  const events = readEvents(dir);
9889
10090
  let planContent = null;
9890
10091
  try {
9891
- planContent = readFileSync8(join15(dir, "plan.md"), "utf-8");
10092
+ planContent = readFileSync9(join16(dir, "plan.md"), "utf-8");
9892
10093
  } catch {
9893
10094
  }
9894
10095
  let gitLog = null;
@@ -9917,7 +10118,7 @@ var init_session_report = __esm({
9917
10118
  });
9918
10119
 
9919
10120
  // src/cli/commands/phase.ts
9920
- import { join as join16, resolve as resolve6 } from "path";
10121
+ import { join as join17, resolve as resolve6 } from "path";
9921
10122
  function validatePhaseId(id) {
9922
10123
  if (id.length > PHASE_ID_MAX_LENGTH) {
9923
10124
  throw new CliValidationError("invalid_input", `Phase ID "${id}" exceeds ${PHASE_ID_MAX_LENGTH} characters`);
@@ -10106,21 +10307,21 @@ async function handlePhaseDelete(id, reassign, format, root) {
10106
10307
  const updated = { ...ticket, phase: reassign, order: maxOrder };
10107
10308
  const parsed = TicketSchema.parse(updated);
10108
10309
  const content = serializeJSON(parsed);
10109
- const target = join16(wrapDir, "tickets", `${parsed.id}.json`);
10310
+ const target = join17(wrapDir, "tickets", `${parsed.id}.json`);
10110
10311
  operations.push({ op: "write", target, content });
10111
10312
  }
10112
10313
  for (const issue of affectedIssues) {
10113
10314
  const updated = { ...issue, phase: reassign };
10114
10315
  const parsed = IssueSchema.parse(updated);
10115
10316
  const content = serializeJSON(parsed);
10116
- const target = join16(wrapDir, "issues", `${parsed.id}.json`);
10317
+ const target = join17(wrapDir, "issues", `${parsed.id}.json`);
10117
10318
  operations.push({ op: "write", target, content });
10118
10319
  }
10119
10320
  const newPhases = state.roadmap.phases.filter((p) => p.id !== id);
10120
10321
  const newRoadmap = { ...state.roadmap, phases: newPhases };
10121
10322
  const parsedRoadmap = RoadmapSchema.parse(newRoadmap);
10122
10323
  const roadmapContent = serializeJSON(parsedRoadmap);
10123
- const roadmapTarget = join16(wrapDir, "roadmap.json");
10324
+ const roadmapTarget = join17(wrapDir, "roadmap.json");
10124
10325
  operations.push({ op: "write", target: roadmapTarget, content: roadmapContent });
10125
10326
  await runTransactionUnlocked(root, operations);
10126
10327
  } else {
@@ -10153,14 +10354,14 @@ var init_phase = __esm({
10153
10354
 
10154
10355
  // src/mcp/tools.ts
10155
10356
  import { z as z10 } from "zod";
10156
- import { join as join17 } from "path";
10357
+ import { join as join18 } from "path";
10157
10358
  function formatMcpError(code, message) {
10158
10359
  return `[${code}] ${message}`;
10159
10360
  }
10160
10361
  async function runMcpReadTool(pinnedRoot, handler) {
10161
10362
  try {
10162
10363
  const { state, warnings } = await loadProject(pinnedRoot);
10163
- const handoversDir = join17(pinnedRoot, ".story", "handovers");
10364
+ const handoversDir = join18(pinnedRoot, ".story", "handovers");
10164
10365
  const ctx = { state, warnings, root: pinnedRoot, handoversDir, format: "md" };
10165
10366
  const result = await handler(ctx);
10166
10367
  if (result.errorCode && INFRASTRUCTURE_ERROR_CODES.includes(result.errorCode)) {
@@ -10748,10 +10949,10 @@ var init_tools = __esm({
10748
10949
 
10749
10950
  // src/core/init.ts
10750
10951
  import { mkdir as mkdir4, stat as stat2, readFile as readFile4, writeFile as writeFile2 } from "fs/promises";
10751
- import { join as join18, resolve as resolve7 } from "path";
10952
+ import { join as join19, resolve as resolve7 } from "path";
10752
10953
  async function initProject(root, options) {
10753
10954
  const absRoot = resolve7(root);
10754
- const wrapDir = join18(absRoot, ".story");
10955
+ const wrapDir = join19(absRoot, ".story");
10755
10956
  let exists = false;
10756
10957
  try {
10757
10958
  const s = await stat2(wrapDir);
@@ -10771,11 +10972,11 @@ async function initProject(root, options) {
10771
10972
  ".story/ already exists. Use --force to overwrite config and roadmap."
10772
10973
  );
10773
10974
  }
10774
- await mkdir4(join18(wrapDir, "tickets"), { recursive: true });
10775
- await mkdir4(join18(wrapDir, "issues"), { recursive: true });
10776
- await mkdir4(join18(wrapDir, "handovers"), { recursive: true });
10777
- await mkdir4(join18(wrapDir, "notes"), { recursive: true });
10778
- await mkdir4(join18(wrapDir, "lessons"), { recursive: true });
10975
+ await mkdir4(join19(wrapDir, "tickets"), { recursive: true });
10976
+ await mkdir4(join19(wrapDir, "issues"), { recursive: true });
10977
+ await mkdir4(join19(wrapDir, "handovers"), { recursive: true });
10978
+ await mkdir4(join19(wrapDir, "notes"), { recursive: true });
10979
+ await mkdir4(join19(wrapDir, "lessons"), { recursive: true });
10779
10980
  const created = [
10780
10981
  ".story/config.json",
10781
10982
  ".story/roadmap.json",
@@ -10815,7 +11016,7 @@ async function initProject(root, options) {
10815
11016
  };
10816
11017
  await writeConfig(config, absRoot);
10817
11018
  await writeRoadmap(roadmap, absRoot);
10818
- const gitignorePath = join18(wrapDir, ".gitignore");
11019
+ const gitignorePath = join19(wrapDir, ".gitignore");
10819
11020
  await ensureGitignoreEntries(gitignorePath, STORY_GITIGNORE_ENTRIES);
10820
11021
  const warnings = [];
10821
11022
  if (options.force && exists) {
@@ -10862,8 +11063,8 @@ var init_init = __esm({
10862
11063
 
10863
11064
  // src/mcp/index.ts
10864
11065
  var mcp_exports = {};
10865
- import { realpathSync as realpathSync2, existsSync as existsSync11 } from "fs";
10866
- import { resolve as resolve8, join as join19, isAbsolute } from "path";
11066
+ import { realpathSync as realpathSync2, existsSync as existsSync12 } from "fs";
11067
+ import { resolve as resolve8, join as join20, isAbsolute } from "path";
10867
11068
  import { z as z11 } from "zod";
10868
11069
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
10869
11070
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
@@ -10878,7 +11079,7 @@ function tryDiscoverRoot() {
10878
11079
  const resolved = resolve8(envRoot);
10879
11080
  try {
10880
11081
  const canonical = realpathSync2(resolved);
10881
- if (existsSync11(join19(canonical, CONFIG_PATH2))) {
11082
+ if (existsSync12(join20(canonical, CONFIG_PATH2))) {
10882
11083
  return canonical;
10883
11084
  }
10884
11085
  process.stderr.write(`Warning: No .story/config.json at ${canonical}
@@ -10981,7 +11182,7 @@ var init_mcp = __esm({
10981
11182
  init_init();
10982
11183
  ENV_VAR2 = "CLAUDESTORY_PROJECT_ROOT";
10983
11184
  CONFIG_PATH2 = ".story/config.json";
10984
- version = "0.1.58";
11185
+ version = "0.1.60";
10985
11186
  main().catch((err) => {
10986
11187
  process.stderr.write(`Fatal: ${err instanceof Error ? err.message : String(err)}
10987
11188
  `);
@@ -11017,7 +11218,7 @@ __export(run_exports, {
11017
11218
  runReadCommand: () => runReadCommand,
11018
11219
  writeOutput: () => writeOutput
11019
11220
  });
11020
- import { join as join20 } from "path";
11221
+ import { join as join21 } from "path";
11021
11222
  function writeOutput(text) {
11022
11223
  try {
11023
11224
  process.stdout.write(text + "\n");
@@ -11045,7 +11246,7 @@ async function runReadCommand(format, handler) {
11045
11246
  return;
11046
11247
  }
11047
11248
  const { state, warnings } = await loadProject(root);
11048
- const handoversDir = join20(root, ".story", "handovers");
11249
+ const handoversDir = join21(root, ".story", "handovers");
11049
11250
  const result = await handler({ state, warnings, root, handoversDir, format });
11050
11251
  writeOutput(result.output);
11051
11252
  let exitCode = result.exitCode ?? ExitCode.OK;
@@ -11080,7 +11281,7 @@ async function runDeleteCommand(format, force, handler) {
11080
11281
  return;
11081
11282
  }
11082
11283
  const { state, warnings } = await loadProject(root);
11083
- const handoversDir = join20(root, ".story", "handovers");
11284
+ const handoversDir = join21(root, ".story", "handovers");
11084
11285
  if (!force && hasIntegrityWarnings(warnings)) {
11085
11286
  writeOutput(
11086
11287
  formatError(
@@ -11594,8 +11795,8 @@ __export(setup_skill_exports, {
11594
11795
  resolveSkillSourceDir: () => resolveSkillSourceDir
11595
11796
  });
11596
11797
  import { mkdir as mkdir5, writeFile as writeFile3, readFile as readFile5, readdir as readdir4, copyFile, rm, rename as rename2, unlink as unlink3 } from "fs/promises";
11597
- import { existsSync as existsSync12 } from "fs";
11598
- import { join as join21, dirname as dirname5 } from "path";
11798
+ import { existsSync as existsSync13 } from "fs";
11799
+ import { join as join22, dirname as dirname5 } from "path";
11599
11800
  import { homedir } from "os";
11600
11801
  import { execFileSync } from "child_process";
11601
11802
  import { fileURLToPath as fileURLToPath4 } from "url";
@@ -11604,10 +11805,10 @@ function log(msg) {
11604
11805
  }
11605
11806
  function resolveSkillSourceDir() {
11606
11807
  const thisDir = dirname5(fileURLToPath4(import.meta.url));
11607
- const bundledPath = join21(thisDir, "..", "src", "skill");
11608
- if (existsSync12(join21(bundledPath, "SKILL.md"))) return bundledPath;
11609
- const sourcePath = join21(thisDir, "..", "..", "skill");
11610
- if (existsSync12(join21(sourcePath, "SKILL.md"))) return sourcePath;
11808
+ const bundledPath = join22(thisDir, "..", "src", "skill");
11809
+ if (existsSync13(join22(bundledPath, "SKILL.md"))) return bundledPath;
11810
+ const sourcePath = join22(thisDir, "..", "..", "skill");
11811
+ if (existsSync13(join22(sourcePath, "SKILL.md"))) return sourcePath;
11611
11812
  throw new Error(
11612
11813
  `Cannot find bundled skill files. Checked:
11613
11814
  ${bundledPath}
@@ -11617,31 +11818,31 @@ function resolveSkillSourceDir() {
11617
11818
  async function copyDirRecursive(srcDir, destDir) {
11618
11819
  const tmpDir = destDir + ".tmp";
11619
11820
  const bakDir = destDir + ".bak";
11620
- if (!existsSync12(destDir) && existsSync12(bakDir)) {
11821
+ if (!existsSync13(destDir) && existsSync13(bakDir)) {
11621
11822
  await rename2(bakDir, destDir);
11622
11823
  }
11623
- if (existsSync12(tmpDir)) await rm(tmpDir, { recursive: true, force: true });
11624
- if (existsSync12(bakDir)) await rm(bakDir, { recursive: true, force: true });
11824
+ if (existsSync13(tmpDir)) await rm(tmpDir, { recursive: true, force: true });
11825
+ if (existsSync13(bakDir)) await rm(bakDir, { recursive: true, force: true });
11625
11826
  await mkdir5(tmpDir, { recursive: true });
11626
11827
  const entries = await readdir4(srcDir, { withFileTypes: true, recursive: true });
11627
11828
  const written = [];
11628
11829
  for (const entry of entries) {
11629
11830
  if (!entry.isFile()) continue;
11630
11831
  const parent = entry.parentPath ?? entry.path ?? srcDir;
11631
- const relativePath = join21(parent, entry.name).slice(srcDir.length + 1);
11632
- const srcPath = join21(srcDir, relativePath);
11633
- const destPath = join21(tmpDir, relativePath);
11832
+ const relativePath = join22(parent, entry.name).slice(srcDir.length + 1);
11833
+ const srcPath = join22(srcDir, relativePath);
11834
+ const destPath = join22(tmpDir, relativePath);
11634
11835
  await mkdir5(dirname5(destPath), { recursive: true });
11635
11836
  await copyFile(srcPath, destPath);
11636
11837
  written.push(relativePath);
11637
11838
  }
11638
- if (existsSync12(destDir)) {
11839
+ if (existsSync13(destDir)) {
11639
11840
  await rename2(destDir, bakDir);
11640
11841
  }
11641
11842
  try {
11642
11843
  await rename2(tmpDir, destDir);
11643
11844
  } catch (err) {
11644
- if (existsSync12(bakDir)) await rename2(bakDir, destDir).catch(() => {
11845
+ if (existsSync13(bakDir)) await rename2(bakDir, destDir).catch(() => {
11645
11846
  });
11646
11847
  await rm(tmpDir, { recursive: true, force: true }).catch(() => {
11647
11848
  });
@@ -11657,9 +11858,9 @@ function isHookWithCommand(entry, command) {
11657
11858
  return e.type === "command" && typeof e.command === "string" && e.command.trim() === command;
11658
11859
  }
11659
11860
  async function registerHook(hookType, hookEntry, settingsPath, matcher) {
11660
- const path2 = settingsPath ?? join21(homedir(), ".claude", "settings.json");
11861
+ const path2 = settingsPath ?? join22(homedir(), ".claude", "settings.json");
11661
11862
  let raw = "{}";
11662
- if (existsSync12(path2)) {
11863
+ if (existsSync13(path2)) {
11663
11864
  try {
11664
11865
  raw = await readFile5(path2, "utf-8");
11665
11866
  } catch {
@@ -11755,9 +11956,9 @@ async function registerStopHook(settingsPath) {
11755
11956
  return registerHook("Stop", { type: "command", command: STOP_HOOK_COMMAND, async: true }, settingsPath);
11756
11957
  }
11757
11958
  async function removeHook(hookType, command, settingsPath) {
11758
- const path2 = settingsPath ?? join21(homedir(), ".claude", "settings.json");
11959
+ const path2 = settingsPath ?? join22(homedir(), ".claude", "settings.json");
11759
11960
  let raw = "{}";
11760
- if (existsSync12(path2)) {
11961
+ if (existsSync13(path2)) {
11761
11962
  try {
11762
11963
  raw = await readFile5(path2, "utf-8");
11763
11964
  } catch {
@@ -11802,7 +12003,7 @@ async function removeHook(hookType, command, settingsPath) {
11802
12003
  }
11803
12004
  async function handleSetupSkill(options = {}) {
11804
12005
  const { skipHooks = false } = options;
11805
- const skillDir = join21(homedir(), ".claude", "skills", "story");
12006
+ const skillDir = join22(homedir(), ".claude", "skills", "story");
11806
12007
  await mkdir5(skillDir, { recursive: true });
11807
12008
  let srcSkillDir;
11808
12009
  try {
@@ -11815,38 +12016,40 @@ async function handleSetupSkill(options = {}) {
11815
12016
  process.exitCode = 1;
11816
12017
  return;
11817
12018
  }
11818
- const oldPrimeDir = join21(homedir(), ".claude", "skills", "prime");
11819
- if (existsSync12(oldPrimeDir)) {
12019
+ const oldPrimeDir = join22(homedir(), ".claude", "skills", "prime");
12020
+ if (existsSync13(oldPrimeDir)) {
11820
12021
  await rm(oldPrimeDir, { recursive: true, force: true });
11821
12022
  log("Removed old /prime skill (migrated to /story)");
11822
12023
  }
11823
- const existed = existsSync12(join21(skillDir, "SKILL.md"));
11824
- const skillContent = await readFile5(join21(srcSkillDir, "SKILL.md"), "utf-8");
11825
- await writeFile3(join21(skillDir, "SKILL.md"), skillContent, "utf-8");
12024
+ const existed = existsSync13(join22(skillDir, "SKILL.md"));
12025
+ const skillContent = await readFile5(join22(srcSkillDir, "SKILL.md"), "utf-8");
12026
+ await writeFile3(join22(skillDir, "SKILL.md"), skillContent, "utf-8");
11826
12027
  const supportFiles = ["setup-flow.md", "autonomous-mode.md", "reference.md"];
11827
12028
  const writtenFiles = ["SKILL.md"];
11828
12029
  const missingFiles = [];
11829
12030
  for (const filename of supportFiles) {
11830
- const srcPath = join21(srcSkillDir, filename);
11831
- if (existsSync12(srcPath)) {
12031
+ const srcPath = join22(srcSkillDir, filename);
12032
+ if (existsSync13(srcPath)) {
11832
12033
  const content = await readFile5(srcPath, "utf-8");
11833
- await writeFile3(join21(skillDir, filename), content, "utf-8");
12034
+ await writeFile3(join22(skillDir, filename), content, "utf-8");
11834
12035
  writtenFiles.push(filename);
11835
12036
  } else {
11836
12037
  missingFiles.push(filename);
11837
12038
  }
11838
12039
  }
11839
- const designSrcDir = join21(srcSkillDir, "design");
11840
- if (existsSync12(designSrcDir)) {
11841
- const designDestDir = join21(skillDir, "design");
11842
- try {
11843
- const designFiles = await copyDirRecursive(designSrcDir, designDestDir);
11844
- for (const f of designFiles) writtenFiles.push(`design/${f}`);
11845
- } catch (err) {
11846
- const msg = err instanceof Error ? err.message : String(err);
11847
- process.stderr.write(`Warning: design skill copy failed: ${msg}
12040
+ for (const subdir of ["design", "review-lenses"]) {
12041
+ const srcDir = join22(srcSkillDir, subdir);
12042
+ if (existsSync13(srcDir)) {
12043
+ const destDir = join22(skillDir, subdir);
12044
+ try {
12045
+ const files = await copyDirRecursive(srcDir, destDir);
12046
+ for (const f of files) writtenFiles.push(`${subdir}/${f}`);
12047
+ } catch (err) {
12048
+ const msg = err instanceof Error ? err.message : String(err);
12049
+ process.stderr.write(`Warning: ${subdir} skill copy failed: ${msg}
11848
12050
  `);
11849
- missingFiles.push("design/");
12051
+ missingFiles.push(`${subdir}/`);
12052
+ }
11850
12053
  }
11851
12054
  }
11852
12055
  log(`${existed ? "Updated" : "Installed"} /story skill at ${skillDir}/`);
@@ -11961,8 +12164,8 @@ var hook_status_exports = {};
11961
12164
  __export(hook_status_exports, {
11962
12165
  handleHookStatus: () => handleHookStatus
11963
12166
  });
11964
- import { readFileSync as readFileSync9, writeFileSync as writeFileSync4, renameSync as renameSync2, unlinkSync as unlinkSync4 } from "fs";
11965
- import { join as join22 } from "path";
12167
+ import { readFileSync as readFileSync10, writeFileSync as writeFileSync5, renameSync as renameSync3, unlinkSync as unlinkSync4 } from "fs";
12168
+ import { join as join23 } from "path";
11966
12169
  async function readStdinSilent() {
11967
12170
  try {
11968
12171
  const chunks = [];
@@ -11979,8 +12182,8 @@ async function readStdinSilent() {
11979
12182
  function atomicWriteSync(targetPath, content) {
11980
12183
  const tmp = `${targetPath}.${process.pid}.tmp`;
11981
12184
  try {
11982
- writeFileSync4(tmp, content, "utf-8");
11983
- renameSync2(tmp, targetPath);
12185
+ writeFileSync5(tmp, content, "utf-8");
12186
+ renameSync3(tmp, targetPath);
11984
12187
  return true;
11985
12188
  } catch {
11986
12189
  try {
@@ -12012,10 +12215,10 @@ function activePayload(session) {
12012
12215
  };
12013
12216
  }
12014
12217
  function ensureGitignore(root) {
12015
- const gitignorePath = join22(root, ".story", ".gitignore");
12218
+ const gitignorePath = join23(root, ".story", ".gitignore");
12016
12219
  let existing = "";
12017
12220
  try {
12018
- existing = readFileSync9(gitignorePath, "utf-8");
12221
+ existing = readFileSync10(gitignorePath, "utf-8");
12019
12222
  } catch {
12020
12223
  }
12021
12224
  const lines = existing.split("\n").map((l) => l.trim());
@@ -12025,13 +12228,13 @@ function ensureGitignore(root) {
12025
12228
  if (content.length > 0 && !content.endsWith("\n")) content += "\n";
12026
12229
  content += missing.join("\n") + "\n";
12027
12230
  try {
12028
- writeFileSync4(gitignorePath, content, "utf-8");
12231
+ writeFileSync5(gitignorePath, content, "utf-8");
12029
12232
  } catch {
12030
12233
  }
12031
12234
  }
12032
12235
  function writeStatus(root, payload) {
12033
12236
  ensureGitignore(root);
12034
- const statusPath = join22(root, ".story", "status.json");
12237
+ const statusPath = join23(root, ".story", "status.json");
12035
12238
  const content = JSON.stringify(payload, null, 2) + "\n";
12036
12239
  atomicWriteSync(statusPath, content);
12037
12240
  }
@@ -12090,8 +12293,8 @@ var config_update_exports = {};
12090
12293
  __export(config_update_exports, {
12091
12294
  handleConfigSetOverrides: () => handleConfigSetOverrides
12092
12295
  });
12093
- import { readFileSync as readFileSync10 } from "fs";
12094
- import { join as join23 } from "path";
12296
+ import { readFileSync as readFileSync11 } from "fs";
12297
+ import { join as join24 } from "path";
12095
12298
  async function handleConfigSetOverrides(root, format, options) {
12096
12299
  const { json: jsonArg, clear } = options;
12097
12300
  if (!clear && !jsonArg) {
@@ -12119,8 +12322,8 @@ async function handleConfigSetOverrides(root, format, options) {
12119
12322
  }
12120
12323
  let resultOverrides = null;
12121
12324
  await withProjectLock(root, { strict: false }, async () => {
12122
- const configPath = join23(root, ".story", "config.json");
12123
- const rawContent = readFileSync10(configPath, "utf-8");
12325
+ const configPath = join24(root, ".story", "config.json");
12326
+ const rawContent = readFileSync11(configPath, "utf-8");
12124
12327
  const raw = JSON.parse(rawContent);
12125
12328
  if (clear) {
12126
12329
  delete raw.recipeOverrides;
@@ -14463,7 +14666,7 @@ async function runCli() {
14463
14666
  registerSessionCommand: registerSessionCommand2,
14464
14667
  registerRepairCommand: registerRepairCommand2
14465
14668
  } = await Promise.resolve().then(() => (init_register(), register_exports));
14466
- const version2 = "0.1.58";
14669
+ const version2 = "0.1.60";
14467
14670
  class HandledError extends Error {
14468
14671
  constructor() {
14469
14672
  super("HANDLED_ERROR");