@anthropologies/claudestory 0.1.40 → 0.1.42

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.
Files changed (3) hide show
  1. package/dist/cli.js +114 -67
  2. package/dist/mcp.js +76 -33
  3. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -5855,7 +5855,8 @@ var init_state_machine = __esm({
5855
5855
  // start does INIT + LOAD_CONTEXT internally
5856
5856
  LOAD_CONTEXT: ["PICK_TICKET"],
5857
5857
  // internal (never seen by Claude)
5858
- PICK_TICKET: ["PLAN", "ISSUE_FIX", "SESSION_END"],
5858
+ PICK_TICKET: ["PLAN", "ISSUE_FIX", "COMPLETE", "SESSION_END"],
5859
+ // COMPLETE for ISS-075 (nothing left to do)
5859
5860
  PLAN: ["PLAN_REVIEW"],
5860
5861
  PLAN_REVIEW: ["IMPLEMENT", "WRITE_TESTS", "PLAN", "PLAN_REVIEW", "SESSION_END"],
5861
5862
  // approve → IMPLEMENT/WRITE_TESTS, reject → PLAN, stay for next round; SESSION_END for tiered exit
@@ -6444,6 +6445,9 @@ var init_pick_ticket = __esm({
6444
6445
  }
6445
6446
  const topCandidate = candidates.kind === "found" ? candidates.candidates[0] : null;
6446
6447
  const hasIssues = highIssues.length > 0;
6448
+ if (!topCandidate && candidates.kind !== "found" && !hasIssues) {
6449
+ return { action: "goto", target: "COMPLETE" };
6450
+ }
6447
6451
  return {
6448
6452
  instruction: [
6449
6453
  "# Pick a Ticket or Issue",
@@ -6730,7 +6734,7 @@ var init_plan_review = __esm({
6730
6734
  const risk = ctx.state.ticket?.risk ?? "low";
6731
6735
  const minRounds = requiredRounds(risk);
6732
6736
  const hasCriticalOrMajor = findings.some(
6733
- (f) => f.severity === "critical" || f.severity === "major"
6737
+ (f) => (f.severity === "critical" || f.severity === "major") && f.disposition !== "addressed" && f.disposition !== "deferred"
6734
6738
  );
6735
6739
  if (verdict === "approve" && hasCriticalOrMajor) {
6736
6740
  return { action: "retry", instruction: "Contradictory review payload: verdict is 'approve' but critical/major findings are present. Re-run the review or correct the verdict." };
@@ -7178,7 +7182,7 @@ var init_code_review = __esm({
7178
7182
  const risk = ctx.state.ticket?.realizedRisk ?? ctx.state.ticket?.risk ?? "low";
7179
7183
  const minRounds = requiredRounds(risk);
7180
7184
  const hasCriticalOrMajor = findings.some(
7181
- (f) => f.severity === "critical" || f.severity === "major"
7185
+ (f) => (f.severity === "critical" || f.severity === "major") && f.disposition !== "addressed" && f.disposition !== "deferred"
7182
7186
  );
7183
7187
  const planRedirect = findings.some((f) => f.recommendedNextState === "PLAN");
7184
7188
  if (verdict === "approve" && hasCriticalOrMajor) {
@@ -8323,24 +8327,64 @@ var init_stages = __esm({
8323
8327
  }
8324
8328
  });
8325
8329
 
8330
+ // src/autonomous/version-check.ts
8331
+ import { readFileSync as readFileSync6 } from "fs";
8332
+ import { join as join13, dirname as dirname4 } from "path";
8333
+ import { fileURLToPath as fileURLToPath3 } from "url";
8334
+ function checkVersionMismatch(runningVersion, installedVersion) {
8335
+ if (!installedVersion) return null;
8336
+ if (runningVersion === "0.0.0-dev") return null;
8337
+ if (runningVersion === installedVersion) return null;
8338
+ return `claudestory MCP server is running v${runningVersion} but v${installedVersion} is installed. Restart Claude Code to load the updated version.`;
8339
+ }
8340
+ function getInstalledVersion() {
8341
+ try {
8342
+ const thisFile = fileURLToPath3(import.meta.url);
8343
+ const candidates = [
8344
+ join13(dirname4(thisFile), "..", "..", "package.json"),
8345
+ join13(dirname4(thisFile), "..", "package.json")
8346
+ ];
8347
+ for (const candidate of candidates) {
8348
+ try {
8349
+ const raw = readFileSync6(candidate, "utf-8");
8350
+ const pkg = JSON.parse(raw);
8351
+ if (pkg.version) return pkg.version;
8352
+ } catch {
8353
+ }
8354
+ }
8355
+ return null;
8356
+ } catch {
8357
+ return null;
8358
+ }
8359
+ }
8360
+ function getRunningVersion() {
8361
+ return "0.1.42";
8362
+ }
8363
+ var init_version_check = __esm({
8364
+ "src/autonomous/version-check.ts"() {
8365
+ "use strict";
8366
+ init_esm_shims();
8367
+ }
8368
+ });
8369
+
8326
8370
  // src/autonomous/guide.ts
8327
- import { readFileSync as readFileSync6, writeFileSync as writeFileSync3, readdirSync as readdirSync4 } from "fs";
8328
- import { join as join13 } from "path";
8371
+ import { readFileSync as readFileSync7, writeFileSync as writeFileSync3, readdirSync as readdirSync4 } from "fs";
8372
+ import { join as join14 } from "path";
8329
8373
  function buildGuideRecommendOptions(root) {
8330
8374
  const opts = {};
8331
8375
  try {
8332
- const handoversDir = join13(root, ".story", "handovers");
8376
+ const handoversDir = join14(root, ".story", "handovers");
8333
8377
  const files = readdirSync4(handoversDir, "utf-8").filter((f) => f.endsWith(".md")).sort();
8334
8378
  if (files.length > 0) {
8335
- opts.latestHandoverContent = readFileSync6(join13(handoversDir, files[files.length - 1]), "utf-8");
8379
+ opts.latestHandoverContent = readFileSync7(join14(handoversDir, files[files.length - 1]), "utf-8");
8336
8380
  }
8337
8381
  } catch {
8338
8382
  }
8339
8383
  try {
8340
- const snapshotsDir = join13(root, ".story", "snapshots");
8384
+ const snapshotsDir = join14(root, ".story", "snapshots");
8341
8385
  const snapFiles = readdirSync4(snapshotsDir, "utf-8").filter((f) => f.endsWith(".json")).sort();
8342
8386
  if (snapFiles.length > 0) {
8343
- const raw = readFileSync6(join13(snapshotsDir, snapFiles[snapFiles.length - 1]), "utf-8");
8387
+ const raw = readFileSync7(join14(snapshotsDir, snapFiles[snapFiles.length - 1]), "utf-8");
8344
8388
  const snap = JSON.parse(raw);
8345
8389
  if (snap.issues) {
8346
8390
  opts.previousOpenIssueCount = snap.issues.filter((i) => i.status !== "resolved").length;
@@ -8527,6 +8571,7 @@ async function handleStart(root, args) {
8527
8571
  for (const stale of staleSessions) {
8528
8572
  writeSessionSync(stale.dir, { ...stale.state, status: "superseded" });
8529
8573
  }
8574
+ const versionWarning = checkVersionMismatch(getRunningVersion(), getInstalledVersion());
8530
8575
  const wsId = deriveWorkspaceId(root);
8531
8576
  const mode = args.mode ?? "auto";
8532
8577
  if (mode !== "auto" && !args.ticketId) {
@@ -8721,7 +8766,7 @@ Staged: ${stagedResult.data.join(", ")}`
8721
8766
  }
8722
8767
  }
8723
8768
  const { state: projectState, warnings } = await loadProject(root);
8724
- const handoversDir = join13(root, ".story", "handovers");
8769
+ const handoversDir = join14(root, ".story", "handovers");
8725
8770
  const ctx = { state: projectState, warnings, root, handoversDir, format: "md" };
8726
8771
  let handoverText = "";
8727
8772
  try {
@@ -8738,7 +8783,7 @@ Staged: ${stagedResult.data.join(", ")}`
8738
8783
  }
8739
8784
  } catch {
8740
8785
  }
8741
- const rulesText = readFileSafe2(join13(root, "RULES.md"));
8786
+ const rulesText = readFileSafe2(join14(root, "RULES.md"));
8742
8787
  const lessonDigest = buildLessonDigest(projectState.lessons);
8743
8788
  const digestParts = [
8744
8789
  handoverText ? `## Recent Handovers
@@ -8754,7 +8799,7 @@ ${rulesText}` : "",
8754
8799
  ].filter(Boolean);
8755
8800
  const digest = digestParts.join("\n\n---\n\n");
8756
8801
  try {
8757
- writeFileSync3(join13(dir, "context-digest.md"), digest, "utf-8");
8802
+ writeFileSync3(join14(dir, "context-digest.md"), digest, "utf-8");
8758
8803
  } catch {
8759
8804
  }
8760
8805
  if (mode !== "auto" && args.ticketId) {
@@ -8946,7 +8991,8 @@ ${ticket.description}` : "",
8946
8991
  "Do NOT use Claude Code's plan mode \u2014 write plans as markdown files.",
8947
8992
  "Do NOT ask the user for confirmation or approval.",
8948
8993
  "Do NOT stop or summarize between tickets \u2014 call autonomous_guide IMMEDIATELY.",
8949
- "You are in autonomous mode \u2014 continue working until done."
8994
+ "You are in autonomous mode \u2014 continue working until done.",
8995
+ ...versionWarning ? [`**Warning:** ${versionWarning}`] : []
8950
8996
  ],
8951
8997
  transitionedFrom: "INIT"
8952
8998
  });
@@ -9472,7 +9518,7 @@ function guideError(err) {
9472
9518
  }
9473
9519
  function readFileSafe2(path2) {
9474
9520
  try {
9475
- return readFileSync6(path2, "utf-8");
9521
+ return readFileSync7(path2, "utf-8");
9476
9522
  } catch {
9477
9523
  return "";
9478
9524
  }
@@ -9498,6 +9544,7 @@ var init_guide = __esm({
9498
9544
  init_snapshot();
9499
9545
  init_queries();
9500
9546
  init_recommend();
9547
+ init_version_check();
9501
9548
  init_handover();
9502
9549
  RECOVERY_MAPPING = {
9503
9550
  PICK_TICKET: { state: "PICK_TICKET", resetPlan: false, resetCode: false },
@@ -9724,8 +9771,8 @@ var init_session_report_formatter = __esm({
9724
9771
  });
9725
9772
 
9726
9773
  // src/cli/commands/session-report.ts
9727
- import { readFileSync as readFileSync7, existsSync as existsSync10 } from "fs";
9728
- import { join as join14 } from "path";
9774
+ import { readFileSync as readFileSync8, existsSync as existsSync10 } from "fs";
9775
+ import { join as join15 } from "path";
9729
9776
  async function handleSessionReport(sessionId, root, format = "md") {
9730
9777
  if (!UUID_REGEX.test(sessionId)) {
9731
9778
  return {
@@ -9744,7 +9791,7 @@ async function handleSessionReport(sessionId, root, format = "md") {
9744
9791
  isError: true
9745
9792
  };
9746
9793
  }
9747
- const statePath2 = join14(dir, "state.json");
9794
+ const statePath2 = join15(dir, "state.json");
9748
9795
  if (!existsSync10(statePath2)) {
9749
9796
  return {
9750
9797
  output: `Error: Session ${sessionId} corrupt \u2014 state.json missing.`,
@@ -9754,7 +9801,7 @@ async function handleSessionReport(sessionId, root, format = "md") {
9754
9801
  };
9755
9802
  }
9756
9803
  try {
9757
- const rawJson = JSON.parse(readFileSync7(statePath2, "utf-8"));
9804
+ const rawJson = JSON.parse(readFileSync8(statePath2, "utf-8"));
9758
9805
  if (rawJson && typeof rawJson === "object" && "schemaVersion" in rawJson && rawJson.schemaVersion !== CURRENT_SESSION_SCHEMA_VERSION) {
9759
9806
  return {
9760
9807
  output: `Error: Session ${sessionId} \u2014 unsupported session schema version ${rawJson.schemaVersion}.`,
@@ -9783,7 +9830,7 @@ async function handleSessionReport(sessionId, root, format = "md") {
9783
9830
  const events = readEvents(dir);
9784
9831
  let planContent = null;
9785
9832
  try {
9786
- planContent = readFileSync7(join14(dir, "plan.md"), "utf-8");
9833
+ planContent = readFileSync8(join15(dir, "plan.md"), "utf-8");
9787
9834
  } catch {
9788
9835
  }
9789
9836
  let gitLog = null;
@@ -9812,7 +9859,7 @@ var init_session_report = __esm({
9812
9859
  });
9813
9860
 
9814
9861
  // src/cli/commands/phase.ts
9815
- import { join as join15, resolve as resolve6 } from "path";
9862
+ import { join as join16, resolve as resolve6 } from "path";
9816
9863
  function validatePhaseId(id) {
9817
9864
  if (id.length > PHASE_ID_MAX_LENGTH) {
9818
9865
  throw new CliValidationError("invalid_input", `Phase ID "${id}" exceeds ${PHASE_ID_MAX_LENGTH} characters`);
@@ -10001,21 +10048,21 @@ async function handlePhaseDelete(id, reassign, format, root) {
10001
10048
  const updated = { ...ticket, phase: reassign, order: maxOrder };
10002
10049
  const parsed = TicketSchema.parse(updated);
10003
10050
  const content = serializeJSON(parsed);
10004
- const target = join15(wrapDir, "tickets", `${parsed.id}.json`);
10051
+ const target = join16(wrapDir, "tickets", `${parsed.id}.json`);
10005
10052
  operations.push({ op: "write", target, content });
10006
10053
  }
10007
10054
  for (const issue of affectedIssues) {
10008
10055
  const updated = { ...issue, phase: reassign };
10009
10056
  const parsed = IssueSchema.parse(updated);
10010
10057
  const content = serializeJSON(parsed);
10011
- const target = join15(wrapDir, "issues", `${parsed.id}.json`);
10058
+ const target = join16(wrapDir, "issues", `${parsed.id}.json`);
10012
10059
  operations.push({ op: "write", target, content });
10013
10060
  }
10014
10061
  const newPhases = state.roadmap.phases.filter((p) => p.id !== id);
10015
10062
  const newRoadmap = { ...state.roadmap, phases: newPhases };
10016
10063
  const parsedRoadmap = RoadmapSchema.parse(newRoadmap);
10017
10064
  const roadmapContent = serializeJSON(parsedRoadmap);
10018
- const roadmapTarget = join15(wrapDir, "roadmap.json");
10065
+ const roadmapTarget = join16(wrapDir, "roadmap.json");
10019
10066
  operations.push({ op: "write", target: roadmapTarget, content: roadmapContent });
10020
10067
  await runTransactionUnlocked(root, operations);
10021
10068
  } else {
@@ -10048,14 +10095,14 @@ var init_phase = __esm({
10048
10095
 
10049
10096
  // src/mcp/tools.ts
10050
10097
  import { z as z10 } from "zod";
10051
- import { join as join16 } from "path";
10098
+ import { join as join17 } from "path";
10052
10099
  function formatMcpError(code, message) {
10053
10100
  return `[${code}] ${message}`;
10054
10101
  }
10055
10102
  async function runMcpReadTool(pinnedRoot, handler) {
10056
10103
  try {
10057
10104
  const { state, warnings } = await loadProject(pinnedRoot);
10058
- const handoversDir = join16(pinnedRoot, ".story", "handovers");
10105
+ const handoversDir = join17(pinnedRoot, ".story", "handovers");
10059
10106
  const ctx = { state, warnings, root: pinnedRoot, handoversDir, format: "md" };
10060
10107
  const result = await handler(ctx);
10061
10108
  if (result.errorCode && INFRASTRUCTURE_ERROR_CODES.includes(result.errorCode)) {
@@ -10643,10 +10690,10 @@ var init_tools = __esm({
10643
10690
 
10644
10691
  // src/core/init.ts
10645
10692
  import { mkdir as mkdir4, stat as stat2, readFile as readFile4, writeFile as writeFile2 } from "fs/promises";
10646
- import { join as join17, resolve as resolve7 } from "path";
10693
+ import { join as join18, resolve as resolve7 } from "path";
10647
10694
  async function initProject(root, options) {
10648
10695
  const absRoot = resolve7(root);
10649
- const wrapDir = join17(absRoot, ".story");
10696
+ const wrapDir = join18(absRoot, ".story");
10650
10697
  let exists = false;
10651
10698
  try {
10652
10699
  const s = await stat2(wrapDir);
@@ -10666,11 +10713,11 @@ async function initProject(root, options) {
10666
10713
  ".story/ already exists. Use --force to overwrite config and roadmap."
10667
10714
  );
10668
10715
  }
10669
- await mkdir4(join17(wrapDir, "tickets"), { recursive: true });
10670
- await mkdir4(join17(wrapDir, "issues"), { recursive: true });
10671
- await mkdir4(join17(wrapDir, "handovers"), { recursive: true });
10672
- await mkdir4(join17(wrapDir, "notes"), { recursive: true });
10673
- await mkdir4(join17(wrapDir, "lessons"), { recursive: true });
10716
+ await mkdir4(join18(wrapDir, "tickets"), { recursive: true });
10717
+ await mkdir4(join18(wrapDir, "issues"), { recursive: true });
10718
+ await mkdir4(join18(wrapDir, "handovers"), { recursive: true });
10719
+ await mkdir4(join18(wrapDir, "notes"), { recursive: true });
10720
+ await mkdir4(join18(wrapDir, "lessons"), { recursive: true });
10674
10721
  const created = [
10675
10722
  ".story/config.json",
10676
10723
  ".story/roadmap.json",
@@ -10710,7 +10757,7 @@ async function initProject(root, options) {
10710
10757
  };
10711
10758
  await writeConfig(config, absRoot);
10712
10759
  await writeRoadmap(roadmap, absRoot);
10713
- const gitignorePath = join17(wrapDir, ".gitignore");
10760
+ const gitignorePath = join18(wrapDir, ".gitignore");
10714
10761
  await ensureGitignoreEntries(gitignorePath, STORY_GITIGNORE_ENTRIES);
10715
10762
  const warnings = [];
10716
10763
  if (options.force && exists) {
@@ -10758,7 +10805,7 @@ var init_init = __esm({
10758
10805
  // src/mcp/index.ts
10759
10806
  var mcp_exports = {};
10760
10807
  import { realpathSync as realpathSync2, existsSync as existsSync11 } from "fs";
10761
- import { resolve as resolve8, join as join18, isAbsolute } from "path";
10808
+ import { resolve as resolve8, join as join19, isAbsolute } from "path";
10762
10809
  import { z as z11 } from "zod";
10763
10810
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
10764
10811
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
@@ -10773,7 +10820,7 @@ function tryDiscoverRoot() {
10773
10820
  const resolved = resolve8(envRoot);
10774
10821
  try {
10775
10822
  const canonical = realpathSync2(resolved);
10776
- if (existsSync11(join18(canonical, CONFIG_PATH2))) {
10823
+ if (existsSync11(join19(canonical, CONFIG_PATH2))) {
10777
10824
  return canonical;
10778
10825
  }
10779
10826
  process.stderr.write(`Warning: No .story/config.json at ${canonical}
@@ -10876,7 +10923,7 @@ var init_mcp = __esm({
10876
10923
  init_init();
10877
10924
  ENV_VAR2 = "CLAUDESTORY_PROJECT_ROOT";
10878
10925
  CONFIG_PATH2 = ".story/config.json";
10879
- version = "0.1.40";
10926
+ version = "0.1.42";
10880
10927
  main().catch((err) => {
10881
10928
  process.stderr.write(`Fatal: ${err instanceof Error ? err.message : String(err)}
10882
10929
  `);
@@ -10912,7 +10959,7 @@ __export(run_exports, {
10912
10959
  runReadCommand: () => runReadCommand,
10913
10960
  writeOutput: () => writeOutput
10914
10961
  });
10915
- import { join as join19 } from "path";
10962
+ import { join as join20 } from "path";
10916
10963
  function writeOutput(text) {
10917
10964
  try {
10918
10965
  process.stdout.write(text + "\n");
@@ -10940,7 +10987,7 @@ async function runReadCommand(format, handler) {
10940
10987
  return;
10941
10988
  }
10942
10989
  const { state, warnings } = await loadProject(root);
10943
- const handoversDir = join19(root, ".story", "handovers");
10990
+ const handoversDir = join20(root, ".story", "handovers");
10944
10991
  const result = await handler({ state, warnings, root, handoversDir, format });
10945
10992
  writeOutput(result.output);
10946
10993
  let exitCode = result.exitCode ?? ExitCode.OK;
@@ -10975,7 +11022,7 @@ async function runDeleteCommand(format, force, handler) {
10975
11022
  return;
10976
11023
  }
10977
11024
  const { state, warnings } = await loadProject(root);
10978
- const handoversDir = join19(root, ".story", "handovers");
11025
+ const handoversDir = join20(root, ".story", "handovers");
10979
11026
  if (!force && hasIntegrityWarnings(warnings)) {
10980
11027
  writeOutput(
10981
11028
  formatError(
@@ -11489,19 +11536,19 @@ __export(setup_skill_exports, {
11489
11536
  });
11490
11537
  import { mkdir as mkdir5, writeFile as writeFile3, readFile as readFile5, rm, rename as rename2, unlink as unlink3 } from "fs/promises";
11491
11538
  import { existsSync as existsSync12 } from "fs";
11492
- import { join as join20, dirname as dirname4 } from "path";
11539
+ import { join as join21, dirname as dirname5 } from "path";
11493
11540
  import { homedir } from "os";
11494
11541
  import { execFileSync } from "child_process";
11495
- import { fileURLToPath as fileURLToPath3 } from "url";
11542
+ import { fileURLToPath as fileURLToPath4 } from "url";
11496
11543
  function log(msg) {
11497
11544
  process.stdout.write(msg + "\n");
11498
11545
  }
11499
11546
  function resolveSkillSourceDir() {
11500
- const thisDir = dirname4(fileURLToPath3(import.meta.url));
11501
- const bundledPath = join20(thisDir, "..", "src", "skill");
11502
- if (existsSync12(join20(bundledPath, "SKILL.md"))) return bundledPath;
11503
- const sourcePath = join20(thisDir, "..", "..", "skill");
11504
- if (existsSync12(join20(sourcePath, "SKILL.md"))) return sourcePath;
11547
+ const thisDir = dirname5(fileURLToPath4(import.meta.url));
11548
+ const bundledPath = join21(thisDir, "..", "src", "skill");
11549
+ if (existsSync12(join21(bundledPath, "SKILL.md"))) return bundledPath;
11550
+ const sourcePath = join21(thisDir, "..", "..", "skill");
11551
+ if (existsSync12(join21(sourcePath, "SKILL.md"))) return sourcePath;
11505
11552
  throw new Error(
11506
11553
  `Cannot find bundled skill files. Checked:
11507
11554
  ${bundledPath}
@@ -11514,7 +11561,7 @@ function isHookWithCommand(entry, command) {
11514
11561
  return e.type === "command" && typeof e.command === "string" && e.command.trim() === command;
11515
11562
  }
11516
11563
  async function registerHook(hookType, hookEntry, settingsPath, matcher) {
11517
- const path2 = settingsPath ?? join20(homedir(), ".claude", "settings.json");
11564
+ const path2 = settingsPath ?? join21(homedir(), ".claude", "settings.json");
11518
11565
  let raw = "{}";
11519
11566
  if (existsSync12(path2)) {
11520
11567
  try {
@@ -11586,7 +11633,7 @@ async function registerHook(hookType, hookEntry, settingsPath, matcher) {
11586
11633
  }
11587
11634
  const tmpPath = `${path2}.${process.pid}.tmp`;
11588
11635
  try {
11589
- const dir = dirname4(path2);
11636
+ const dir = dirname5(path2);
11590
11637
  await mkdir5(dir, { recursive: true });
11591
11638
  await writeFile3(tmpPath, JSON.stringify(settings, null, 2) + "\n", "utf-8");
11592
11639
  await rename2(tmpPath, path2);
@@ -11612,7 +11659,7 @@ async function registerStopHook(settingsPath) {
11612
11659
  return registerHook("Stop", { type: "command", command: STOP_HOOK_COMMAND, async: true }, settingsPath);
11613
11660
  }
11614
11661
  async function removeHook(hookType, command, settingsPath) {
11615
- const path2 = settingsPath ?? join20(homedir(), ".claude", "settings.json");
11662
+ const path2 = settingsPath ?? join21(homedir(), ".claude", "settings.json");
11616
11663
  let raw = "{}";
11617
11664
  if (existsSync12(path2)) {
11618
11665
  try {
@@ -11644,7 +11691,7 @@ async function removeHook(hookType, command, settingsPath) {
11644
11691
  if (!removed) return "not_found";
11645
11692
  const tmpPath = `${path2}.${process.pid}.tmp`;
11646
11693
  try {
11647
- const dir = dirname4(path2);
11694
+ const dir = dirname5(path2);
11648
11695
  await mkdir5(dir, { recursive: true });
11649
11696
  await writeFile3(tmpPath, JSON.stringify(settings, null, 2) + "\n", "utf-8");
11650
11697
  await rename2(tmpPath, path2);
@@ -11659,7 +11706,7 @@ async function removeHook(hookType, command, settingsPath) {
11659
11706
  }
11660
11707
  async function handleSetupSkill(options = {}) {
11661
11708
  const { skipHooks = false } = options;
11662
- const skillDir = join20(homedir(), ".claude", "skills", "story");
11709
+ const skillDir = join21(homedir(), ".claude", "skills", "story");
11663
11710
  await mkdir5(skillDir, { recursive: true });
11664
11711
  let srcSkillDir;
11665
11712
  try {
@@ -11672,19 +11719,19 @@ async function handleSetupSkill(options = {}) {
11672
11719
  process.exitCode = 1;
11673
11720
  return;
11674
11721
  }
11675
- const oldPrimeDir = join20(homedir(), ".claude", "skills", "prime");
11722
+ const oldPrimeDir = join21(homedir(), ".claude", "skills", "prime");
11676
11723
  if (existsSync12(oldPrimeDir)) {
11677
11724
  await rm(oldPrimeDir, { recursive: true, force: true });
11678
11725
  log("Removed old /prime skill (migrated to /story)");
11679
11726
  }
11680
- const existed = existsSync12(join20(skillDir, "SKILL.md"));
11681
- const skillContent = await readFile5(join20(srcSkillDir, "SKILL.md"), "utf-8");
11682
- await writeFile3(join20(skillDir, "SKILL.md"), skillContent, "utf-8");
11727
+ const existed = existsSync12(join21(skillDir, "SKILL.md"));
11728
+ const skillContent = await readFile5(join21(srcSkillDir, "SKILL.md"), "utf-8");
11729
+ await writeFile3(join21(skillDir, "SKILL.md"), skillContent, "utf-8");
11683
11730
  let referenceWritten = false;
11684
- const refSrcPath = join20(srcSkillDir, "reference.md");
11731
+ const refSrcPath = join21(srcSkillDir, "reference.md");
11685
11732
  if (existsSync12(refSrcPath)) {
11686
11733
  const refContent = await readFile5(refSrcPath, "utf-8");
11687
- await writeFile3(join20(skillDir, "reference.md"), refContent, "utf-8");
11734
+ await writeFile3(join21(skillDir, "reference.md"), refContent, "utf-8");
11688
11735
  referenceWritten = true;
11689
11736
  }
11690
11737
  log(`${existed ? "Updated" : "Installed"} /story skill at ${skillDir}/`);
@@ -11798,8 +11845,8 @@ var hook_status_exports = {};
11798
11845
  __export(hook_status_exports, {
11799
11846
  handleHookStatus: () => handleHookStatus
11800
11847
  });
11801
- import { readFileSync as readFileSync8, writeFileSync as writeFileSync4, renameSync as renameSync2, unlinkSync as unlinkSync4 } from "fs";
11802
- import { join as join21 } from "path";
11848
+ import { readFileSync as readFileSync9, writeFileSync as writeFileSync4, renameSync as renameSync2, unlinkSync as unlinkSync4 } from "fs";
11849
+ import { join as join22 } from "path";
11803
11850
  async function readStdinSilent() {
11804
11851
  try {
11805
11852
  const chunks = [];
@@ -11849,10 +11896,10 @@ function activePayload(session) {
11849
11896
  };
11850
11897
  }
11851
11898
  function ensureGitignore(root) {
11852
- const gitignorePath = join21(root, ".story", ".gitignore");
11899
+ const gitignorePath = join22(root, ".story", ".gitignore");
11853
11900
  let existing = "";
11854
11901
  try {
11855
- existing = readFileSync8(gitignorePath, "utf-8");
11902
+ existing = readFileSync9(gitignorePath, "utf-8");
11856
11903
  } catch {
11857
11904
  }
11858
11905
  const lines = existing.split("\n").map((l) => l.trim());
@@ -11868,7 +11915,7 @@ function ensureGitignore(root) {
11868
11915
  }
11869
11916
  function writeStatus(root, payload) {
11870
11917
  ensureGitignore(root);
11871
- const statusPath = join21(root, ".story", "status.json");
11918
+ const statusPath = join22(root, ".story", "status.json");
11872
11919
  const content = JSON.stringify(payload, null, 2) + "\n";
11873
11920
  atomicWriteSync(statusPath, content);
11874
11921
  }
@@ -11927,8 +11974,8 @@ var config_update_exports = {};
11927
11974
  __export(config_update_exports, {
11928
11975
  handleConfigSetOverrides: () => handleConfigSetOverrides
11929
11976
  });
11930
- import { readFileSync as readFileSync9 } from "fs";
11931
- import { join as join22 } from "path";
11977
+ import { readFileSync as readFileSync10 } from "fs";
11978
+ import { join as join23 } from "path";
11932
11979
  async function handleConfigSetOverrides(root, format, options) {
11933
11980
  const { json: jsonArg, clear } = options;
11934
11981
  if (!clear && !jsonArg) {
@@ -11956,8 +12003,8 @@ async function handleConfigSetOverrides(root, format, options) {
11956
12003
  }
11957
12004
  let resultOverrides = null;
11958
12005
  await withProjectLock(root, { strict: false }, async () => {
11959
- const configPath = join22(root, ".story", "config.json");
11960
- const rawContent = readFileSync9(configPath, "utf-8");
12006
+ const configPath = join23(root, ".story", "config.json");
12007
+ const rawContent = readFileSync10(configPath, "utf-8");
11961
12008
  const raw = JSON.parse(rawContent);
11962
12009
  if (clear) {
11963
12010
  delete raw.recipeOverrides;
@@ -14300,7 +14347,7 @@ async function runCli() {
14300
14347
  registerSessionCommand: registerSessionCommand2,
14301
14348
  registerRepairCommand: registerRepairCommand2
14302
14349
  } = await Promise.resolve().then(() => (init_register(), register_exports));
14303
- const version2 = "0.1.40";
14350
+ const version2 = "0.1.42";
14304
14351
  class HandledError extends Error {
14305
14352
  constructor() {
14306
14353
  super("HANDLED_ERROR");
package/dist/mcp.js CHANGED
@@ -4096,7 +4096,7 @@ var init_session = __esm({
4096
4096
  // src/mcp/index.ts
4097
4097
  init_esm_shims();
4098
4098
  import { realpathSync as realpathSync2, existsSync as existsSync11 } from "fs";
4099
- import { resolve as resolve8, join as join18, isAbsolute } from "path";
4099
+ import { resolve as resolve8, join as join19, isAbsolute } from "path";
4100
4100
  import { z as z11 } from "zod";
4101
4101
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
4102
4102
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
@@ -4149,7 +4149,7 @@ init_errors();
4149
4149
  init_helpers();
4150
4150
  init_types();
4151
4151
  import { z as z10 } from "zod";
4152
- import { join as join16 } from "path";
4152
+ import { join as join17 } from "path";
4153
4153
 
4154
4154
  // src/cli/commands/status.ts
4155
4155
  init_esm_shims();
@@ -5443,8 +5443,8 @@ init_handover();
5443
5443
  init_esm_shims();
5444
5444
  init_session_types();
5445
5445
  init_session();
5446
- import { readFileSync as readFileSync6, writeFileSync as writeFileSync3, readdirSync as readdirSync4 } from "fs";
5447
- import { join as join13 } from "path";
5446
+ import { readFileSync as readFileSync7, writeFileSync as writeFileSync3, readdirSync as readdirSync4 } from "fs";
5447
+ import { join as join14 } from "path";
5448
5448
 
5449
5449
  // src/autonomous/state-machine.ts
5450
5450
  init_esm_shims();
@@ -5453,7 +5453,8 @@ var TRANSITIONS = {
5453
5453
  // start does INIT + LOAD_CONTEXT internally
5454
5454
  LOAD_CONTEXT: ["PICK_TICKET"],
5455
5455
  // internal (never seen by Claude)
5456
- PICK_TICKET: ["PLAN", "ISSUE_FIX", "SESSION_END"],
5456
+ PICK_TICKET: ["PLAN", "ISSUE_FIX", "COMPLETE", "SESSION_END"],
5457
+ // COMPLETE for ISS-075 (nothing left to do)
5457
5458
  PLAN: ["PLAN_REVIEW"],
5458
5459
  PLAN_REVIEW: ["IMPLEMENT", "WRITE_TESTS", "PLAN", "PLAN_REVIEW", "SESSION_END"],
5459
5460
  // approve → IMPLEMENT/WRITE_TESTS, reject → PLAN, stay for next round; SESSION_END for tiered exit
@@ -6013,6 +6014,9 @@ var PickTicketStage = class {
6013
6014
  }
6014
6015
  const topCandidate = candidates.kind === "found" ? candidates.candidates[0] : null;
6015
6016
  const hasIssues = highIssues.length > 0;
6017
+ if (!topCandidate && candidates.kind !== "found" && !hasIssues) {
6018
+ return { action: "goto", target: "COMPLETE" };
6019
+ }
6016
6020
  return {
6017
6021
  instruction: [
6018
6022
  "# Pick a Ticket or Issue",
@@ -6285,7 +6289,7 @@ var PlanReviewStage = class {
6285
6289
  const risk = ctx.state.ticket?.risk ?? "low";
6286
6290
  const minRounds = requiredRounds(risk);
6287
6291
  const hasCriticalOrMajor = findings.some(
6288
- (f) => f.severity === "critical" || f.severity === "major"
6292
+ (f) => (f.severity === "critical" || f.severity === "major") && f.disposition !== "addressed" && f.disposition !== "deferred"
6289
6293
  );
6290
6294
  if (verdict === "approve" && hasCriticalOrMajor) {
6291
6295
  return { action: "retry", instruction: "Contradictory review payload: verdict is 'approve' but critical/major findings are present. Re-run the review or correct the verdict." };
@@ -6706,7 +6710,7 @@ var CodeReviewStage = class {
6706
6710
  const risk = ctx.state.ticket?.realizedRisk ?? ctx.state.ticket?.risk ?? "low";
6707
6711
  const minRounds = requiredRounds(risk);
6708
6712
  const hasCriticalOrMajor = findings.some(
6709
- (f) => f.severity === "critical" || f.severity === "major"
6713
+ (f) => (f.severity === "critical" || f.severity === "major") && f.disposition !== "addressed" && f.disposition !== "deferred"
6710
6714
  );
6711
6715
  const planRedirect = findings.some((f) => f.recommendedNextState === "PLAN");
6712
6716
  if (verdict === "approve" && hasCriticalOrMajor) {
@@ -7779,6 +7783,43 @@ init_project_loader();
7779
7783
  init_snapshot();
7780
7784
  init_snapshot();
7781
7785
  init_queries();
7786
+
7787
+ // src/autonomous/version-check.ts
7788
+ init_esm_shims();
7789
+ import { readFileSync as readFileSync6 } from "fs";
7790
+ import { join as join13, dirname as dirname4 } from "path";
7791
+ import { fileURLToPath as fileURLToPath3 } from "url";
7792
+ function checkVersionMismatch(runningVersion, installedVersion) {
7793
+ if (!installedVersion) return null;
7794
+ if (runningVersion === "0.0.0-dev") return null;
7795
+ if (runningVersion === installedVersion) return null;
7796
+ return `claudestory MCP server is running v${runningVersion} but v${installedVersion} is installed. Restart Claude Code to load the updated version.`;
7797
+ }
7798
+ function getInstalledVersion() {
7799
+ try {
7800
+ const thisFile = fileURLToPath3(import.meta.url);
7801
+ const candidates = [
7802
+ join13(dirname4(thisFile), "..", "..", "package.json"),
7803
+ join13(dirname4(thisFile), "..", "package.json")
7804
+ ];
7805
+ for (const candidate of candidates) {
7806
+ try {
7807
+ const raw = readFileSync6(candidate, "utf-8");
7808
+ const pkg = JSON.parse(raw);
7809
+ if (pkg.version) return pkg.version;
7810
+ } catch {
7811
+ }
7812
+ }
7813
+ return null;
7814
+ } catch {
7815
+ return null;
7816
+ }
7817
+ }
7818
+ function getRunningVersion() {
7819
+ return "0.1.42";
7820
+ }
7821
+
7822
+ // src/autonomous/guide.ts
7782
7823
  init_handover();
7783
7824
  var RECOVERY_MAPPING = {
7784
7825
  PICK_TICKET: { state: "PICK_TICKET", resetPlan: false, resetCode: false },
@@ -7800,18 +7841,18 @@ var RECOVERY_MAPPING = {
7800
7841
  function buildGuideRecommendOptions(root) {
7801
7842
  const opts = {};
7802
7843
  try {
7803
- const handoversDir = join13(root, ".story", "handovers");
7844
+ const handoversDir = join14(root, ".story", "handovers");
7804
7845
  const files = readdirSync4(handoversDir, "utf-8").filter((f) => f.endsWith(".md")).sort();
7805
7846
  if (files.length > 0) {
7806
- opts.latestHandoverContent = readFileSync6(join13(handoversDir, files[files.length - 1]), "utf-8");
7847
+ opts.latestHandoverContent = readFileSync7(join14(handoversDir, files[files.length - 1]), "utf-8");
7807
7848
  }
7808
7849
  } catch {
7809
7850
  }
7810
7851
  try {
7811
- const snapshotsDir = join13(root, ".story", "snapshots");
7852
+ const snapshotsDir = join14(root, ".story", "snapshots");
7812
7853
  const snapFiles = readdirSync4(snapshotsDir, "utf-8").filter((f) => f.endsWith(".json")).sort();
7813
7854
  if (snapFiles.length > 0) {
7814
- const raw = readFileSync6(join13(snapshotsDir, snapFiles[snapFiles.length - 1]), "utf-8");
7855
+ const raw = readFileSync7(join14(snapshotsDir, snapFiles[snapFiles.length - 1]), "utf-8");
7815
7856
  const snap = JSON.parse(raw);
7816
7857
  if (snap.issues) {
7817
7858
  opts.previousOpenIssueCount = snap.issues.filter((i) => i.status !== "resolved").length;
@@ -8004,6 +8045,7 @@ async function handleStart(root, args) {
8004
8045
  for (const stale of staleSessions) {
8005
8046
  writeSessionSync(stale.dir, { ...stale.state, status: "superseded" });
8006
8047
  }
8048
+ const versionWarning = checkVersionMismatch(getRunningVersion(), getInstalledVersion());
8007
8049
  const wsId = deriveWorkspaceId(root);
8008
8050
  const mode = args.mode ?? "auto";
8009
8051
  if (mode !== "auto" && !args.ticketId) {
@@ -8198,7 +8240,7 @@ Staged: ${stagedResult.data.join(", ")}`
8198
8240
  }
8199
8241
  }
8200
8242
  const { state: projectState, warnings } = await loadProject(root);
8201
- const handoversDir = join13(root, ".story", "handovers");
8243
+ const handoversDir = join14(root, ".story", "handovers");
8202
8244
  const ctx = { state: projectState, warnings, root, handoversDir, format: "md" };
8203
8245
  let handoverText = "";
8204
8246
  try {
@@ -8215,7 +8257,7 @@ Staged: ${stagedResult.data.join(", ")}`
8215
8257
  }
8216
8258
  } catch {
8217
8259
  }
8218
- const rulesText = readFileSafe2(join13(root, "RULES.md"));
8260
+ const rulesText = readFileSafe2(join14(root, "RULES.md"));
8219
8261
  const lessonDigest = buildLessonDigest(projectState.lessons);
8220
8262
  const digestParts = [
8221
8263
  handoverText ? `## Recent Handovers
@@ -8231,7 +8273,7 @@ ${rulesText}` : "",
8231
8273
  ].filter(Boolean);
8232
8274
  const digest = digestParts.join("\n\n---\n\n");
8233
8275
  try {
8234
- writeFileSync3(join13(dir, "context-digest.md"), digest, "utf-8");
8276
+ writeFileSync3(join14(dir, "context-digest.md"), digest, "utf-8");
8235
8277
  } catch {
8236
8278
  }
8237
8279
  if (mode !== "auto" && args.ticketId) {
@@ -8423,7 +8465,8 @@ ${ticket.description}` : "",
8423
8465
  "Do NOT use Claude Code's plan mode \u2014 write plans as markdown files.",
8424
8466
  "Do NOT ask the user for confirmation or approval.",
8425
8467
  "Do NOT stop or summarize between tickets \u2014 call autonomous_guide IMMEDIATELY.",
8426
- "You are in autonomous mode \u2014 continue working until done."
8468
+ "You are in autonomous mode \u2014 continue working until done.",
8469
+ ...versionWarning ? [`**Warning:** ${versionWarning}`] : []
8427
8470
  ],
8428
8471
  transitionedFrom: "INIT"
8429
8472
  });
@@ -8950,7 +8993,7 @@ function guideError(err) {
8950
8993
  }
8951
8994
  function readFileSafe2(path2) {
8952
8995
  try {
8953
- return readFileSync6(path2, "utf-8");
8996
+ return readFileSync7(path2, "utf-8");
8954
8997
  } catch {
8955
8998
  return "";
8956
8999
  }
@@ -8960,8 +9003,8 @@ function readFileSafe2(path2) {
8960
9003
  init_esm_shims();
8961
9004
  init_session();
8962
9005
  init_session_types();
8963
- import { readFileSync as readFileSync7, existsSync as existsSync10 } from "fs";
8964
- import { join as join14 } from "path";
9006
+ import { readFileSync as readFileSync8, existsSync as existsSync10 } from "fs";
9007
+ import { join as join15 } from "path";
8965
9008
 
8966
9009
  // src/core/session-report-formatter.ts
8967
9010
  init_esm_shims();
@@ -9175,7 +9218,7 @@ async function handleSessionReport(sessionId, root, format = "md") {
9175
9218
  isError: true
9176
9219
  };
9177
9220
  }
9178
- const statePath2 = join14(dir, "state.json");
9221
+ const statePath2 = join15(dir, "state.json");
9179
9222
  if (!existsSync10(statePath2)) {
9180
9223
  return {
9181
9224
  output: `Error: Session ${sessionId} corrupt \u2014 state.json missing.`,
@@ -9185,7 +9228,7 @@ async function handleSessionReport(sessionId, root, format = "md") {
9185
9228
  };
9186
9229
  }
9187
9230
  try {
9188
- const rawJson = JSON.parse(readFileSync7(statePath2, "utf-8"));
9231
+ const rawJson = JSON.parse(readFileSync8(statePath2, "utf-8"));
9189
9232
  if (rawJson && typeof rawJson === "object" && "schemaVersion" in rawJson && rawJson.schemaVersion !== CURRENT_SESSION_SCHEMA_VERSION) {
9190
9233
  return {
9191
9234
  output: `Error: Session ${sessionId} \u2014 unsupported session schema version ${rawJson.schemaVersion}.`,
@@ -9214,7 +9257,7 @@ async function handleSessionReport(sessionId, root, format = "md") {
9214
9257
  const events = readEvents(dir);
9215
9258
  let planContent = null;
9216
9259
  try {
9217
- planContent = readFileSync7(join14(dir, "plan.md"), "utf-8");
9260
+ planContent = readFileSync8(join15(dir, "plan.md"), "utf-8");
9218
9261
  } catch {
9219
9262
  }
9220
9263
  let gitLog = null;
@@ -9239,7 +9282,7 @@ init_issue();
9239
9282
  init_roadmap();
9240
9283
  init_output_formatter();
9241
9284
  init_helpers();
9242
- import { join as join15, resolve as resolve6 } from "path";
9285
+ import { join as join16, resolve as resolve6 } from "path";
9243
9286
  var PHASE_ID_REGEX = /^[a-z0-9]+(-[a-z0-9]+)*$/;
9244
9287
  var PHASE_ID_MAX_LENGTH = 40;
9245
9288
  function validatePhaseId(id) {
@@ -9348,7 +9391,7 @@ function formatMcpError(code, message) {
9348
9391
  async function runMcpReadTool(pinnedRoot, handler) {
9349
9392
  try {
9350
9393
  const { state, warnings } = await loadProject(pinnedRoot);
9351
- const handoversDir = join16(pinnedRoot, ".story", "handovers");
9394
+ const handoversDir = join17(pinnedRoot, ".story", "handovers");
9352
9395
  const ctx = { state, warnings, root: pinnedRoot, handoversDir, format: "md" };
9353
9396
  const result = await handler(ctx);
9354
9397
  if (result.errorCode && INFRASTRUCTURE_ERROR_CODES.includes(result.errorCode)) {
@@ -9906,10 +9949,10 @@ init_esm_shims();
9906
9949
  init_project_loader();
9907
9950
  init_errors();
9908
9951
  import { mkdir as mkdir4, stat as stat2, readFile as readFile4, writeFile as writeFile2 } from "fs/promises";
9909
- import { join as join17, resolve as resolve7 } from "path";
9952
+ import { join as join18, resolve as resolve7 } from "path";
9910
9953
  async function initProject(root, options) {
9911
9954
  const absRoot = resolve7(root);
9912
- const wrapDir = join17(absRoot, ".story");
9955
+ const wrapDir = join18(absRoot, ".story");
9913
9956
  let exists = false;
9914
9957
  try {
9915
9958
  const s = await stat2(wrapDir);
@@ -9929,11 +9972,11 @@ async function initProject(root, options) {
9929
9972
  ".story/ already exists. Use --force to overwrite config and roadmap."
9930
9973
  );
9931
9974
  }
9932
- await mkdir4(join17(wrapDir, "tickets"), { recursive: true });
9933
- await mkdir4(join17(wrapDir, "issues"), { recursive: true });
9934
- await mkdir4(join17(wrapDir, "handovers"), { recursive: true });
9935
- await mkdir4(join17(wrapDir, "notes"), { recursive: true });
9936
- await mkdir4(join17(wrapDir, "lessons"), { recursive: true });
9975
+ await mkdir4(join18(wrapDir, "tickets"), { recursive: true });
9976
+ await mkdir4(join18(wrapDir, "issues"), { recursive: true });
9977
+ await mkdir4(join18(wrapDir, "handovers"), { recursive: true });
9978
+ await mkdir4(join18(wrapDir, "notes"), { recursive: true });
9979
+ await mkdir4(join18(wrapDir, "lessons"), { recursive: true });
9937
9980
  const created = [
9938
9981
  ".story/config.json",
9939
9982
  ".story/roadmap.json",
@@ -9973,7 +10016,7 @@ async function initProject(root, options) {
9973
10016
  };
9974
10017
  await writeConfig(config, absRoot);
9975
10018
  await writeRoadmap(roadmap, absRoot);
9976
- const gitignorePath = join17(wrapDir, ".gitignore");
10019
+ const gitignorePath = join18(wrapDir, ".gitignore");
9977
10020
  await ensureGitignoreEntries(gitignorePath, STORY_GITIGNORE_ENTRIES);
9978
10021
  const warnings = [];
9979
10022
  if (options.force && exists) {
@@ -10012,7 +10055,7 @@ async function ensureGitignoreEntries(gitignorePath, entries) {
10012
10055
  // src/mcp/index.ts
10013
10056
  var ENV_VAR2 = "CLAUDESTORY_PROJECT_ROOT";
10014
10057
  var CONFIG_PATH2 = ".story/config.json";
10015
- var version = "0.1.40";
10058
+ var version = "0.1.42";
10016
10059
  function tryDiscoverRoot() {
10017
10060
  const envRoot = process.env[ENV_VAR2];
10018
10061
  if (envRoot) {
@@ -10024,7 +10067,7 @@ function tryDiscoverRoot() {
10024
10067
  const resolved = resolve8(envRoot);
10025
10068
  try {
10026
10069
  const canonical = realpathSync2(resolved);
10027
- if (existsSync11(join18(canonical, CONFIG_PATH2))) {
10070
+ if (existsSync11(join19(canonical, CONFIG_PATH2))) {
10028
10071
  return canonical;
10029
10072
  }
10030
10073
  process.stderr.write(`Warning: No .story/config.json at ${canonical}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@anthropologies/claudestory",
3
- "version": "0.1.40",
3
+ "version": "0.1.42",
4
4
  "license": "UNLICENSED",
5
5
  "description": "Cross-session context persistence for AI coding projects. Tracks tickets, issues, roadmap, and handovers so every session builds on the last.",
6
6
  "keywords": [