@anthropologies/claudestory 0.1.41 → 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 +107 -64
  2. package/dist/mcp.js +69 -30
  3. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -8327,24 +8327,64 @@ var init_stages = __esm({
8327
8327
  }
8328
8328
  });
8329
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
+
8330
8370
  // src/autonomous/guide.ts
8331
- import { readFileSync as readFileSync6, writeFileSync as writeFileSync3, readdirSync as readdirSync4 } from "fs";
8332
- 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";
8333
8373
  function buildGuideRecommendOptions(root) {
8334
8374
  const opts = {};
8335
8375
  try {
8336
- const handoversDir = join13(root, ".story", "handovers");
8376
+ const handoversDir = join14(root, ".story", "handovers");
8337
8377
  const files = readdirSync4(handoversDir, "utf-8").filter((f) => f.endsWith(".md")).sort();
8338
8378
  if (files.length > 0) {
8339
- opts.latestHandoverContent = readFileSync6(join13(handoversDir, files[files.length - 1]), "utf-8");
8379
+ opts.latestHandoverContent = readFileSync7(join14(handoversDir, files[files.length - 1]), "utf-8");
8340
8380
  }
8341
8381
  } catch {
8342
8382
  }
8343
8383
  try {
8344
- const snapshotsDir = join13(root, ".story", "snapshots");
8384
+ const snapshotsDir = join14(root, ".story", "snapshots");
8345
8385
  const snapFiles = readdirSync4(snapshotsDir, "utf-8").filter((f) => f.endsWith(".json")).sort();
8346
8386
  if (snapFiles.length > 0) {
8347
- const raw = readFileSync6(join13(snapshotsDir, snapFiles[snapFiles.length - 1]), "utf-8");
8387
+ const raw = readFileSync7(join14(snapshotsDir, snapFiles[snapFiles.length - 1]), "utf-8");
8348
8388
  const snap = JSON.parse(raw);
8349
8389
  if (snap.issues) {
8350
8390
  opts.previousOpenIssueCount = snap.issues.filter((i) => i.status !== "resolved").length;
@@ -8531,6 +8571,7 @@ async function handleStart(root, args) {
8531
8571
  for (const stale of staleSessions) {
8532
8572
  writeSessionSync(stale.dir, { ...stale.state, status: "superseded" });
8533
8573
  }
8574
+ const versionWarning = checkVersionMismatch(getRunningVersion(), getInstalledVersion());
8534
8575
  const wsId = deriveWorkspaceId(root);
8535
8576
  const mode = args.mode ?? "auto";
8536
8577
  if (mode !== "auto" && !args.ticketId) {
@@ -8725,7 +8766,7 @@ Staged: ${stagedResult.data.join(", ")}`
8725
8766
  }
8726
8767
  }
8727
8768
  const { state: projectState, warnings } = await loadProject(root);
8728
- const handoversDir = join13(root, ".story", "handovers");
8769
+ const handoversDir = join14(root, ".story", "handovers");
8729
8770
  const ctx = { state: projectState, warnings, root, handoversDir, format: "md" };
8730
8771
  let handoverText = "";
8731
8772
  try {
@@ -8742,7 +8783,7 @@ Staged: ${stagedResult.data.join(", ")}`
8742
8783
  }
8743
8784
  } catch {
8744
8785
  }
8745
- const rulesText = readFileSafe2(join13(root, "RULES.md"));
8786
+ const rulesText = readFileSafe2(join14(root, "RULES.md"));
8746
8787
  const lessonDigest = buildLessonDigest(projectState.lessons);
8747
8788
  const digestParts = [
8748
8789
  handoverText ? `## Recent Handovers
@@ -8758,7 +8799,7 @@ ${rulesText}` : "",
8758
8799
  ].filter(Boolean);
8759
8800
  const digest = digestParts.join("\n\n---\n\n");
8760
8801
  try {
8761
- writeFileSync3(join13(dir, "context-digest.md"), digest, "utf-8");
8802
+ writeFileSync3(join14(dir, "context-digest.md"), digest, "utf-8");
8762
8803
  } catch {
8763
8804
  }
8764
8805
  if (mode !== "auto" && args.ticketId) {
@@ -8950,7 +8991,8 @@ ${ticket.description}` : "",
8950
8991
  "Do NOT use Claude Code's plan mode \u2014 write plans as markdown files.",
8951
8992
  "Do NOT ask the user for confirmation or approval.",
8952
8993
  "Do NOT stop or summarize between tickets \u2014 call autonomous_guide IMMEDIATELY.",
8953
- "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}`] : []
8954
8996
  ],
8955
8997
  transitionedFrom: "INIT"
8956
8998
  });
@@ -9476,7 +9518,7 @@ function guideError(err) {
9476
9518
  }
9477
9519
  function readFileSafe2(path2) {
9478
9520
  try {
9479
- return readFileSync6(path2, "utf-8");
9521
+ return readFileSync7(path2, "utf-8");
9480
9522
  } catch {
9481
9523
  return "";
9482
9524
  }
@@ -9502,6 +9544,7 @@ var init_guide = __esm({
9502
9544
  init_snapshot();
9503
9545
  init_queries();
9504
9546
  init_recommend();
9547
+ init_version_check();
9505
9548
  init_handover();
9506
9549
  RECOVERY_MAPPING = {
9507
9550
  PICK_TICKET: { state: "PICK_TICKET", resetPlan: false, resetCode: false },
@@ -9728,8 +9771,8 @@ var init_session_report_formatter = __esm({
9728
9771
  });
9729
9772
 
9730
9773
  // src/cli/commands/session-report.ts
9731
- import { readFileSync as readFileSync7, existsSync as existsSync10 } from "fs";
9732
- import { join as join14 } from "path";
9774
+ import { readFileSync as readFileSync8, existsSync as existsSync10 } from "fs";
9775
+ import { join as join15 } from "path";
9733
9776
  async function handleSessionReport(sessionId, root, format = "md") {
9734
9777
  if (!UUID_REGEX.test(sessionId)) {
9735
9778
  return {
@@ -9748,7 +9791,7 @@ async function handleSessionReport(sessionId, root, format = "md") {
9748
9791
  isError: true
9749
9792
  };
9750
9793
  }
9751
- const statePath2 = join14(dir, "state.json");
9794
+ const statePath2 = join15(dir, "state.json");
9752
9795
  if (!existsSync10(statePath2)) {
9753
9796
  return {
9754
9797
  output: `Error: Session ${sessionId} corrupt \u2014 state.json missing.`,
@@ -9758,7 +9801,7 @@ async function handleSessionReport(sessionId, root, format = "md") {
9758
9801
  };
9759
9802
  }
9760
9803
  try {
9761
- const rawJson = JSON.parse(readFileSync7(statePath2, "utf-8"));
9804
+ const rawJson = JSON.parse(readFileSync8(statePath2, "utf-8"));
9762
9805
  if (rawJson && typeof rawJson === "object" && "schemaVersion" in rawJson && rawJson.schemaVersion !== CURRENT_SESSION_SCHEMA_VERSION) {
9763
9806
  return {
9764
9807
  output: `Error: Session ${sessionId} \u2014 unsupported session schema version ${rawJson.schemaVersion}.`,
@@ -9787,7 +9830,7 @@ async function handleSessionReport(sessionId, root, format = "md") {
9787
9830
  const events = readEvents(dir);
9788
9831
  let planContent = null;
9789
9832
  try {
9790
- planContent = readFileSync7(join14(dir, "plan.md"), "utf-8");
9833
+ planContent = readFileSync8(join15(dir, "plan.md"), "utf-8");
9791
9834
  } catch {
9792
9835
  }
9793
9836
  let gitLog = null;
@@ -9816,7 +9859,7 @@ var init_session_report = __esm({
9816
9859
  });
9817
9860
 
9818
9861
  // src/cli/commands/phase.ts
9819
- import { join as join15, resolve as resolve6 } from "path";
9862
+ import { join as join16, resolve as resolve6 } from "path";
9820
9863
  function validatePhaseId(id) {
9821
9864
  if (id.length > PHASE_ID_MAX_LENGTH) {
9822
9865
  throw new CliValidationError("invalid_input", `Phase ID "${id}" exceeds ${PHASE_ID_MAX_LENGTH} characters`);
@@ -10005,21 +10048,21 @@ async function handlePhaseDelete(id, reassign, format, root) {
10005
10048
  const updated = { ...ticket, phase: reassign, order: maxOrder };
10006
10049
  const parsed = TicketSchema.parse(updated);
10007
10050
  const content = serializeJSON(parsed);
10008
- const target = join15(wrapDir, "tickets", `${parsed.id}.json`);
10051
+ const target = join16(wrapDir, "tickets", `${parsed.id}.json`);
10009
10052
  operations.push({ op: "write", target, content });
10010
10053
  }
10011
10054
  for (const issue of affectedIssues) {
10012
10055
  const updated = { ...issue, phase: reassign };
10013
10056
  const parsed = IssueSchema.parse(updated);
10014
10057
  const content = serializeJSON(parsed);
10015
- const target = join15(wrapDir, "issues", `${parsed.id}.json`);
10058
+ const target = join16(wrapDir, "issues", `${parsed.id}.json`);
10016
10059
  operations.push({ op: "write", target, content });
10017
10060
  }
10018
10061
  const newPhases = state.roadmap.phases.filter((p) => p.id !== id);
10019
10062
  const newRoadmap = { ...state.roadmap, phases: newPhases };
10020
10063
  const parsedRoadmap = RoadmapSchema.parse(newRoadmap);
10021
10064
  const roadmapContent = serializeJSON(parsedRoadmap);
10022
- const roadmapTarget = join15(wrapDir, "roadmap.json");
10065
+ const roadmapTarget = join16(wrapDir, "roadmap.json");
10023
10066
  operations.push({ op: "write", target: roadmapTarget, content: roadmapContent });
10024
10067
  await runTransactionUnlocked(root, operations);
10025
10068
  } else {
@@ -10052,14 +10095,14 @@ var init_phase = __esm({
10052
10095
 
10053
10096
  // src/mcp/tools.ts
10054
10097
  import { z as z10 } from "zod";
10055
- import { join as join16 } from "path";
10098
+ import { join as join17 } from "path";
10056
10099
  function formatMcpError(code, message) {
10057
10100
  return `[${code}] ${message}`;
10058
10101
  }
10059
10102
  async function runMcpReadTool(pinnedRoot, handler) {
10060
10103
  try {
10061
10104
  const { state, warnings } = await loadProject(pinnedRoot);
10062
- const handoversDir = join16(pinnedRoot, ".story", "handovers");
10105
+ const handoversDir = join17(pinnedRoot, ".story", "handovers");
10063
10106
  const ctx = { state, warnings, root: pinnedRoot, handoversDir, format: "md" };
10064
10107
  const result = await handler(ctx);
10065
10108
  if (result.errorCode && INFRASTRUCTURE_ERROR_CODES.includes(result.errorCode)) {
@@ -10647,10 +10690,10 @@ var init_tools = __esm({
10647
10690
 
10648
10691
  // src/core/init.ts
10649
10692
  import { mkdir as mkdir4, stat as stat2, readFile as readFile4, writeFile as writeFile2 } from "fs/promises";
10650
- import { join as join17, resolve as resolve7 } from "path";
10693
+ import { join as join18, resolve as resolve7 } from "path";
10651
10694
  async function initProject(root, options) {
10652
10695
  const absRoot = resolve7(root);
10653
- const wrapDir = join17(absRoot, ".story");
10696
+ const wrapDir = join18(absRoot, ".story");
10654
10697
  let exists = false;
10655
10698
  try {
10656
10699
  const s = await stat2(wrapDir);
@@ -10670,11 +10713,11 @@ async function initProject(root, options) {
10670
10713
  ".story/ already exists. Use --force to overwrite config and roadmap."
10671
10714
  );
10672
10715
  }
10673
- await mkdir4(join17(wrapDir, "tickets"), { recursive: true });
10674
- await mkdir4(join17(wrapDir, "issues"), { recursive: true });
10675
- await mkdir4(join17(wrapDir, "handovers"), { recursive: true });
10676
- await mkdir4(join17(wrapDir, "notes"), { recursive: true });
10677
- 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 });
10678
10721
  const created = [
10679
10722
  ".story/config.json",
10680
10723
  ".story/roadmap.json",
@@ -10714,7 +10757,7 @@ async function initProject(root, options) {
10714
10757
  };
10715
10758
  await writeConfig(config, absRoot);
10716
10759
  await writeRoadmap(roadmap, absRoot);
10717
- const gitignorePath = join17(wrapDir, ".gitignore");
10760
+ const gitignorePath = join18(wrapDir, ".gitignore");
10718
10761
  await ensureGitignoreEntries(gitignorePath, STORY_GITIGNORE_ENTRIES);
10719
10762
  const warnings = [];
10720
10763
  if (options.force && exists) {
@@ -10762,7 +10805,7 @@ var init_init = __esm({
10762
10805
  // src/mcp/index.ts
10763
10806
  var mcp_exports = {};
10764
10807
  import { realpathSync as realpathSync2, existsSync as existsSync11 } from "fs";
10765
- import { resolve as resolve8, join as join18, isAbsolute } from "path";
10808
+ import { resolve as resolve8, join as join19, isAbsolute } from "path";
10766
10809
  import { z as z11 } from "zod";
10767
10810
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
10768
10811
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
@@ -10777,7 +10820,7 @@ function tryDiscoverRoot() {
10777
10820
  const resolved = resolve8(envRoot);
10778
10821
  try {
10779
10822
  const canonical = realpathSync2(resolved);
10780
- if (existsSync11(join18(canonical, CONFIG_PATH2))) {
10823
+ if (existsSync11(join19(canonical, CONFIG_PATH2))) {
10781
10824
  return canonical;
10782
10825
  }
10783
10826
  process.stderr.write(`Warning: No .story/config.json at ${canonical}
@@ -10880,7 +10923,7 @@ var init_mcp = __esm({
10880
10923
  init_init();
10881
10924
  ENV_VAR2 = "CLAUDESTORY_PROJECT_ROOT";
10882
10925
  CONFIG_PATH2 = ".story/config.json";
10883
- version = "0.1.41";
10926
+ version = "0.1.42";
10884
10927
  main().catch((err) => {
10885
10928
  process.stderr.write(`Fatal: ${err instanceof Error ? err.message : String(err)}
10886
10929
  `);
@@ -10916,7 +10959,7 @@ __export(run_exports, {
10916
10959
  runReadCommand: () => runReadCommand,
10917
10960
  writeOutput: () => writeOutput
10918
10961
  });
10919
- import { join as join19 } from "path";
10962
+ import { join as join20 } from "path";
10920
10963
  function writeOutput(text) {
10921
10964
  try {
10922
10965
  process.stdout.write(text + "\n");
@@ -10944,7 +10987,7 @@ async function runReadCommand(format, handler) {
10944
10987
  return;
10945
10988
  }
10946
10989
  const { state, warnings } = await loadProject(root);
10947
- const handoversDir = join19(root, ".story", "handovers");
10990
+ const handoversDir = join20(root, ".story", "handovers");
10948
10991
  const result = await handler({ state, warnings, root, handoversDir, format });
10949
10992
  writeOutput(result.output);
10950
10993
  let exitCode = result.exitCode ?? ExitCode.OK;
@@ -10979,7 +11022,7 @@ async function runDeleteCommand(format, force, handler) {
10979
11022
  return;
10980
11023
  }
10981
11024
  const { state, warnings } = await loadProject(root);
10982
- const handoversDir = join19(root, ".story", "handovers");
11025
+ const handoversDir = join20(root, ".story", "handovers");
10983
11026
  if (!force && hasIntegrityWarnings(warnings)) {
10984
11027
  writeOutput(
10985
11028
  formatError(
@@ -11493,19 +11536,19 @@ __export(setup_skill_exports, {
11493
11536
  });
11494
11537
  import { mkdir as mkdir5, writeFile as writeFile3, readFile as readFile5, rm, rename as rename2, unlink as unlink3 } from "fs/promises";
11495
11538
  import { existsSync as existsSync12 } from "fs";
11496
- import { join as join20, dirname as dirname4 } from "path";
11539
+ import { join as join21, dirname as dirname5 } from "path";
11497
11540
  import { homedir } from "os";
11498
11541
  import { execFileSync } from "child_process";
11499
- import { fileURLToPath as fileURLToPath3 } from "url";
11542
+ import { fileURLToPath as fileURLToPath4 } from "url";
11500
11543
  function log(msg) {
11501
11544
  process.stdout.write(msg + "\n");
11502
11545
  }
11503
11546
  function resolveSkillSourceDir() {
11504
- const thisDir = dirname4(fileURLToPath3(import.meta.url));
11505
- const bundledPath = join20(thisDir, "..", "src", "skill");
11506
- if (existsSync12(join20(bundledPath, "SKILL.md"))) return bundledPath;
11507
- const sourcePath = join20(thisDir, "..", "..", "skill");
11508
- 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;
11509
11552
  throw new Error(
11510
11553
  `Cannot find bundled skill files. Checked:
11511
11554
  ${bundledPath}
@@ -11518,7 +11561,7 @@ function isHookWithCommand(entry, command) {
11518
11561
  return e.type === "command" && typeof e.command === "string" && e.command.trim() === command;
11519
11562
  }
11520
11563
  async function registerHook(hookType, hookEntry, settingsPath, matcher) {
11521
- const path2 = settingsPath ?? join20(homedir(), ".claude", "settings.json");
11564
+ const path2 = settingsPath ?? join21(homedir(), ".claude", "settings.json");
11522
11565
  let raw = "{}";
11523
11566
  if (existsSync12(path2)) {
11524
11567
  try {
@@ -11590,7 +11633,7 @@ async function registerHook(hookType, hookEntry, settingsPath, matcher) {
11590
11633
  }
11591
11634
  const tmpPath = `${path2}.${process.pid}.tmp`;
11592
11635
  try {
11593
- const dir = dirname4(path2);
11636
+ const dir = dirname5(path2);
11594
11637
  await mkdir5(dir, { recursive: true });
11595
11638
  await writeFile3(tmpPath, JSON.stringify(settings, null, 2) + "\n", "utf-8");
11596
11639
  await rename2(tmpPath, path2);
@@ -11616,7 +11659,7 @@ async function registerStopHook(settingsPath) {
11616
11659
  return registerHook("Stop", { type: "command", command: STOP_HOOK_COMMAND, async: true }, settingsPath);
11617
11660
  }
11618
11661
  async function removeHook(hookType, command, settingsPath) {
11619
- const path2 = settingsPath ?? join20(homedir(), ".claude", "settings.json");
11662
+ const path2 = settingsPath ?? join21(homedir(), ".claude", "settings.json");
11620
11663
  let raw = "{}";
11621
11664
  if (existsSync12(path2)) {
11622
11665
  try {
@@ -11648,7 +11691,7 @@ async function removeHook(hookType, command, settingsPath) {
11648
11691
  if (!removed) return "not_found";
11649
11692
  const tmpPath = `${path2}.${process.pid}.tmp`;
11650
11693
  try {
11651
- const dir = dirname4(path2);
11694
+ const dir = dirname5(path2);
11652
11695
  await mkdir5(dir, { recursive: true });
11653
11696
  await writeFile3(tmpPath, JSON.stringify(settings, null, 2) + "\n", "utf-8");
11654
11697
  await rename2(tmpPath, path2);
@@ -11663,7 +11706,7 @@ async function removeHook(hookType, command, settingsPath) {
11663
11706
  }
11664
11707
  async function handleSetupSkill(options = {}) {
11665
11708
  const { skipHooks = false } = options;
11666
- const skillDir = join20(homedir(), ".claude", "skills", "story");
11709
+ const skillDir = join21(homedir(), ".claude", "skills", "story");
11667
11710
  await mkdir5(skillDir, { recursive: true });
11668
11711
  let srcSkillDir;
11669
11712
  try {
@@ -11676,19 +11719,19 @@ async function handleSetupSkill(options = {}) {
11676
11719
  process.exitCode = 1;
11677
11720
  return;
11678
11721
  }
11679
- const oldPrimeDir = join20(homedir(), ".claude", "skills", "prime");
11722
+ const oldPrimeDir = join21(homedir(), ".claude", "skills", "prime");
11680
11723
  if (existsSync12(oldPrimeDir)) {
11681
11724
  await rm(oldPrimeDir, { recursive: true, force: true });
11682
11725
  log("Removed old /prime skill (migrated to /story)");
11683
11726
  }
11684
- const existed = existsSync12(join20(skillDir, "SKILL.md"));
11685
- const skillContent = await readFile5(join20(srcSkillDir, "SKILL.md"), "utf-8");
11686
- 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");
11687
11730
  let referenceWritten = false;
11688
- const refSrcPath = join20(srcSkillDir, "reference.md");
11731
+ const refSrcPath = join21(srcSkillDir, "reference.md");
11689
11732
  if (existsSync12(refSrcPath)) {
11690
11733
  const refContent = await readFile5(refSrcPath, "utf-8");
11691
- await writeFile3(join20(skillDir, "reference.md"), refContent, "utf-8");
11734
+ await writeFile3(join21(skillDir, "reference.md"), refContent, "utf-8");
11692
11735
  referenceWritten = true;
11693
11736
  }
11694
11737
  log(`${existed ? "Updated" : "Installed"} /story skill at ${skillDir}/`);
@@ -11802,8 +11845,8 @@ var hook_status_exports = {};
11802
11845
  __export(hook_status_exports, {
11803
11846
  handleHookStatus: () => handleHookStatus
11804
11847
  });
11805
- import { readFileSync as readFileSync8, writeFileSync as writeFileSync4, renameSync as renameSync2, unlinkSync as unlinkSync4 } from "fs";
11806
- 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";
11807
11850
  async function readStdinSilent() {
11808
11851
  try {
11809
11852
  const chunks = [];
@@ -11853,10 +11896,10 @@ function activePayload(session) {
11853
11896
  };
11854
11897
  }
11855
11898
  function ensureGitignore(root) {
11856
- const gitignorePath = join21(root, ".story", ".gitignore");
11899
+ const gitignorePath = join22(root, ".story", ".gitignore");
11857
11900
  let existing = "";
11858
11901
  try {
11859
- existing = readFileSync8(gitignorePath, "utf-8");
11902
+ existing = readFileSync9(gitignorePath, "utf-8");
11860
11903
  } catch {
11861
11904
  }
11862
11905
  const lines = existing.split("\n").map((l) => l.trim());
@@ -11872,7 +11915,7 @@ function ensureGitignore(root) {
11872
11915
  }
11873
11916
  function writeStatus(root, payload) {
11874
11917
  ensureGitignore(root);
11875
- const statusPath = join21(root, ".story", "status.json");
11918
+ const statusPath = join22(root, ".story", "status.json");
11876
11919
  const content = JSON.stringify(payload, null, 2) + "\n";
11877
11920
  atomicWriteSync(statusPath, content);
11878
11921
  }
@@ -11931,8 +11974,8 @@ var config_update_exports = {};
11931
11974
  __export(config_update_exports, {
11932
11975
  handleConfigSetOverrides: () => handleConfigSetOverrides
11933
11976
  });
11934
- import { readFileSync as readFileSync9 } from "fs";
11935
- import { join as join22 } from "path";
11977
+ import { readFileSync as readFileSync10 } from "fs";
11978
+ import { join as join23 } from "path";
11936
11979
  async function handleConfigSetOverrides(root, format, options) {
11937
11980
  const { json: jsonArg, clear } = options;
11938
11981
  if (!clear && !jsonArg) {
@@ -11960,8 +12003,8 @@ async function handleConfigSetOverrides(root, format, options) {
11960
12003
  }
11961
12004
  let resultOverrides = null;
11962
12005
  await withProjectLock(root, { strict: false }, async () => {
11963
- const configPath = join22(root, ".story", "config.json");
11964
- const rawContent = readFileSync9(configPath, "utf-8");
12006
+ const configPath = join23(root, ".story", "config.json");
12007
+ const rawContent = readFileSync10(configPath, "utf-8");
11965
12008
  const raw = JSON.parse(rawContent);
11966
12009
  if (clear) {
11967
12010
  delete raw.recipeOverrides;
@@ -14304,7 +14347,7 @@ async function runCli() {
14304
14347
  registerSessionCommand: registerSessionCommand2,
14305
14348
  registerRepairCommand: registerRepairCommand2
14306
14349
  } = await Promise.resolve().then(() => (init_register(), register_exports));
14307
- const version2 = "0.1.41";
14350
+ const version2 = "0.1.42";
14308
14351
  class HandledError extends Error {
14309
14352
  constructor() {
14310
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();
@@ -7783,6 +7783,43 @@ init_project_loader();
7783
7783
  init_snapshot();
7784
7784
  init_snapshot();
7785
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
7786
7823
  init_handover();
7787
7824
  var RECOVERY_MAPPING = {
7788
7825
  PICK_TICKET: { state: "PICK_TICKET", resetPlan: false, resetCode: false },
@@ -7804,18 +7841,18 @@ var RECOVERY_MAPPING = {
7804
7841
  function buildGuideRecommendOptions(root) {
7805
7842
  const opts = {};
7806
7843
  try {
7807
- const handoversDir = join13(root, ".story", "handovers");
7844
+ const handoversDir = join14(root, ".story", "handovers");
7808
7845
  const files = readdirSync4(handoversDir, "utf-8").filter((f) => f.endsWith(".md")).sort();
7809
7846
  if (files.length > 0) {
7810
- opts.latestHandoverContent = readFileSync6(join13(handoversDir, files[files.length - 1]), "utf-8");
7847
+ opts.latestHandoverContent = readFileSync7(join14(handoversDir, files[files.length - 1]), "utf-8");
7811
7848
  }
7812
7849
  } catch {
7813
7850
  }
7814
7851
  try {
7815
- const snapshotsDir = join13(root, ".story", "snapshots");
7852
+ const snapshotsDir = join14(root, ".story", "snapshots");
7816
7853
  const snapFiles = readdirSync4(snapshotsDir, "utf-8").filter((f) => f.endsWith(".json")).sort();
7817
7854
  if (snapFiles.length > 0) {
7818
- const raw = readFileSync6(join13(snapshotsDir, snapFiles[snapFiles.length - 1]), "utf-8");
7855
+ const raw = readFileSync7(join14(snapshotsDir, snapFiles[snapFiles.length - 1]), "utf-8");
7819
7856
  const snap = JSON.parse(raw);
7820
7857
  if (snap.issues) {
7821
7858
  opts.previousOpenIssueCount = snap.issues.filter((i) => i.status !== "resolved").length;
@@ -8008,6 +8045,7 @@ async function handleStart(root, args) {
8008
8045
  for (const stale of staleSessions) {
8009
8046
  writeSessionSync(stale.dir, { ...stale.state, status: "superseded" });
8010
8047
  }
8048
+ const versionWarning = checkVersionMismatch(getRunningVersion(), getInstalledVersion());
8011
8049
  const wsId = deriveWorkspaceId(root);
8012
8050
  const mode = args.mode ?? "auto";
8013
8051
  if (mode !== "auto" && !args.ticketId) {
@@ -8202,7 +8240,7 @@ Staged: ${stagedResult.data.join(", ")}`
8202
8240
  }
8203
8241
  }
8204
8242
  const { state: projectState, warnings } = await loadProject(root);
8205
- const handoversDir = join13(root, ".story", "handovers");
8243
+ const handoversDir = join14(root, ".story", "handovers");
8206
8244
  const ctx = { state: projectState, warnings, root, handoversDir, format: "md" };
8207
8245
  let handoverText = "";
8208
8246
  try {
@@ -8219,7 +8257,7 @@ Staged: ${stagedResult.data.join(", ")}`
8219
8257
  }
8220
8258
  } catch {
8221
8259
  }
8222
- const rulesText = readFileSafe2(join13(root, "RULES.md"));
8260
+ const rulesText = readFileSafe2(join14(root, "RULES.md"));
8223
8261
  const lessonDigest = buildLessonDigest(projectState.lessons);
8224
8262
  const digestParts = [
8225
8263
  handoverText ? `## Recent Handovers
@@ -8235,7 +8273,7 @@ ${rulesText}` : "",
8235
8273
  ].filter(Boolean);
8236
8274
  const digest = digestParts.join("\n\n---\n\n");
8237
8275
  try {
8238
- writeFileSync3(join13(dir, "context-digest.md"), digest, "utf-8");
8276
+ writeFileSync3(join14(dir, "context-digest.md"), digest, "utf-8");
8239
8277
  } catch {
8240
8278
  }
8241
8279
  if (mode !== "auto" && args.ticketId) {
@@ -8427,7 +8465,8 @@ ${ticket.description}` : "",
8427
8465
  "Do NOT use Claude Code's plan mode \u2014 write plans as markdown files.",
8428
8466
  "Do NOT ask the user for confirmation or approval.",
8429
8467
  "Do NOT stop or summarize between tickets \u2014 call autonomous_guide IMMEDIATELY.",
8430
- "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}`] : []
8431
8470
  ],
8432
8471
  transitionedFrom: "INIT"
8433
8472
  });
@@ -8954,7 +8993,7 @@ function guideError(err) {
8954
8993
  }
8955
8994
  function readFileSafe2(path2) {
8956
8995
  try {
8957
- return readFileSync6(path2, "utf-8");
8996
+ return readFileSync7(path2, "utf-8");
8958
8997
  } catch {
8959
8998
  return "";
8960
8999
  }
@@ -8964,8 +9003,8 @@ function readFileSafe2(path2) {
8964
9003
  init_esm_shims();
8965
9004
  init_session();
8966
9005
  init_session_types();
8967
- import { readFileSync as readFileSync7, existsSync as existsSync10 } from "fs";
8968
- import { join as join14 } from "path";
9006
+ import { readFileSync as readFileSync8, existsSync as existsSync10 } from "fs";
9007
+ import { join as join15 } from "path";
8969
9008
 
8970
9009
  // src/core/session-report-formatter.ts
8971
9010
  init_esm_shims();
@@ -9179,7 +9218,7 @@ async function handleSessionReport(sessionId, root, format = "md") {
9179
9218
  isError: true
9180
9219
  };
9181
9220
  }
9182
- const statePath2 = join14(dir, "state.json");
9221
+ const statePath2 = join15(dir, "state.json");
9183
9222
  if (!existsSync10(statePath2)) {
9184
9223
  return {
9185
9224
  output: `Error: Session ${sessionId} corrupt \u2014 state.json missing.`,
@@ -9189,7 +9228,7 @@ async function handleSessionReport(sessionId, root, format = "md") {
9189
9228
  };
9190
9229
  }
9191
9230
  try {
9192
- const rawJson = JSON.parse(readFileSync7(statePath2, "utf-8"));
9231
+ const rawJson = JSON.parse(readFileSync8(statePath2, "utf-8"));
9193
9232
  if (rawJson && typeof rawJson === "object" && "schemaVersion" in rawJson && rawJson.schemaVersion !== CURRENT_SESSION_SCHEMA_VERSION) {
9194
9233
  return {
9195
9234
  output: `Error: Session ${sessionId} \u2014 unsupported session schema version ${rawJson.schemaVersion}.`,
@@ -9218,7 +9257,7 @@ async function handleSessionReport(sessionId, root, format = "md") {
9218
9257
  const events = readEvents(dir);
9219
9258
  let planContent = null;
9220
9259
  try {
9221
- planContent = readFileSync7(join14(dir, "plan.md"), "utf-8");
9260
+ planContent = readFileSync8(join15(dir, "plan.md"), "utf-8");
9222
9261
  } catch {
9223
9262
  }
9224
9263
  let gitLog = null;
@@ -9243,7 +9282,7 @@ init_issue();
9243
9282
  init_roadmap();
9244
9283
  init_output_formatter();
9245
9284
  init_helpers();
9246
- import { join as join15, resolve as resolve6 } from "path";
9285
+ import { join as join16, resolve as resolve6 } from "path";
9247
9286
  var PHASE_ID_REGEX = /^[a-z0-9]+(-[a-z0-9]+)*$/;
9248
9287
  var PHASE_ID_MAX_LENGTH = 40;
9249
9288
  function validatePhaseId(id) {
@@ -9352,7 +9391,7 @@ function formatMcpError(code, message) {
9352
9391
  async function runMcpReadTool(pinnedRoot, handler) {
9353
9392
  try {
9354
9393
  const { state, warnings } = await loadProject(pinnedRoot);
9355
- const handoversDir = join16(pinnedRoot, ".story", "handovers");
9394
+ const handoversDir = join17(pinnedRoot, ".story", "handovers");
9356
9395
  const ctx = { state, warnings, root: pinnedRoot, handoversDir, format: "md" };
9357
9396
  const result = await handler(ctx);
9358
9397
  if (result.errorCode && INFRASTRUCTURE_ERROR_CODES.includes(result.errorCode)) {
@@ -9910,10 +9949,10 @@ init_esm_shims();
9910
9949
  init_project_loader();
9911
9950
  init_errors();
9912
9951
  import { mkdir as mkdir4, stat as stat2, readFile as readFile4, writeFile as writeFile2 } from "fs/promises";
9913
- import { join as join17, resolve as resolve7 } from "path";
9952
+ import { join as join18, resolve as resolve7 } from "path";
9914
9953
  async function initProject(root, options) {
9915
9954
  const absRoot = resolve7(root);
9916
- const wrapDir = join17(absRoot, ".story");
9955
+ const wrapDir = join18(absRoot, ".story");
9917
9956
  let exists = false;
9918
9957
  try {
9919
9958
  const s = await stat2(wrapDir);
@@ -9933,11 +9972,11 @@ async function initProject(root, options) {
9933
9972
  ".story/ already exists. Use --force to overwrite config and roadmap."
9934
9973
  );
9935
9974
  }
9936
- await mkdir4(join17(wrapDir, "tickets"), { recursive: true });
9937
- await mkdir4(join17(wrapDir, "issues"), { recursive: true });
9938
- await mkdir4(join17(wrapDir, "handovers"), { recursive: true });
9939
- await mkdir4(join17(wrapDir, "notes"), { recursive: true });
9940
- 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 });
9941
9980
  const created = [
9942
9981
  ".story/config.json",
9943
9982
  ".story/roadmap.json",
@@ -9977,7 +10016,7 @@ async function initProject(root, options) {
9977
10016
  };
9978
10017
  await writeConfig(config, absRoot);
9979
10018
  await writeRoadmap(roadmap, absRoot);
9980
- const gitignorePath = join17(wrapDir, ".gitignore");
10019
+ const gitignorePath = join18(wrapDir, ".gitignore");
9981
10020
  await ensureGitignoreEntries(gitignorePath, STORY_GITIGNORE_ENTRIES);
9982
10021
  const warnings = [];
9983
10022
  if (options.force && exists) {
@@ -10016,7 +10055,7 @@ async function ensureGitignoreEntries(gitignorePath, entries) {
10016
10055
  // src/mcp/index.ts
10017
10056
  var ENV_VAR2 = "CLAUDESTORY_PROJECT_ROOT";
10018
10057
  var CONFIG_PATH2 = ".story/config.json";
10019
- var version = "0.1.41";
10058
+ var version = "0.1.42";
10020
10059
  function tryDiscoverRoot() {
10021
10060
  const envRoot = process.env[ENV_VAR2];
10022
10061
  if (envRoot) {
@@ -10028,7 +10067,7 @@ function tryDiscoverRoot() {
10028
10067
  const resolved = resolve8(envRoot);
10029
10068
  try {
10030
10069
  const canonical = realpathSync2(resolved);
10031
- if (existsSync11(join18(canonical, CONFIG_PATH2))) {
10070
+ if (existsSync11(join19(canonical, CONFIG_PATH2))) {
10032
10071
  return canonical;
10033
10072
  }
10034
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.41",
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": [