@anthropologies/claudestory 0.1.56 → 0.1.58

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  An agentic development framework. Track tickets, issues, and progress for your project in a `.story/` directory that AI tools read and write natively.
4
4
 
5
+ **[claudestory.com](https://claudestory.com)** | **[Documentation](https://claudestory.com/cli)** | **[Privacy Policy](https://claudestory.com/privacy)**
6
+
5
7
  ## Installation
6
8
 
7
9
  ```bash
@@ -201,4 +203,4 @@ Everything else in `.story/` should be tracked.
201
203
 
202
204
  ## License
203
205
 
204
- MIT
206
+ [PolyForm Noncommercial 1.0.0](https://polyformproject.org/licenses/noncommercial/1.0.0/) -- free for personal and noncommercial use. For commercial licensing, contact shayegh@me.com.
package/dist/cli.js CHANGED
@@ -2634,6 +2634,20 @@ function formatReference(commands, mcpTools, format) {
2634
2634
  lines.push(`- **${tool.name}**${params} \u2014 ${tool.description}`);
2635
2635
  }
2636
2636
  lines.push("");
2637
+ lines.push("## /story design");
2638
+ lines.push("");
2639
+ lines.push("Evaluate frontend code against platform-specific design best practices.");
2640
+ lines.push("");
2641
+ lines.push("```");
2642
+ lines.push("/story design # Auto-detect platform, evaluate frontend");
2643
+ lines.push("/story design web # Evaluate against web best practices");
2644
+ lines.push("/story design ios # Evaluate against iOS HIG");
2645
+ lines.push("/story design macos # Evaluate against macOS HIG");
2646
+ lines.push("/story design android # Evaluate against Material Design");
2647
+ lines.push("```");
2648
+ lines.push("");
2649
+ lines.push("Creates issues automatically when claudestory MCP tools or CLI are available. Checks for existing design issues to avoid duplicates on repeated runs. Outputs markdown checklist as fallback when neither MCP nor CLI is available.");
2650
+ lines.push("");
2637
2651
  lines.push("## Common Workflows");
2638
2652
  lines.push("");
2639
2653
  lines.push("### Session Start");
@@ -5653,7 +5667,8 @@ function refreshLease(state) {
5653
5667
  contextPressure: {
5654
5668
  ...state.contextPressure,
5655
5669
  guideCallCount: newCallCount,
5656
- ticketsCompleted: state.completedTickets?.length ?? 0
5670
+ // ISS-084: Include resolved issues in work count
5671
+ ticketsCompleted: (state.completedTickets?.length ?? 0) + (state.resolvedIssues?.length ?? 0)
5657
5672
  }
5658
5673
  };
5659
5674
  }
@@ -5871,7 +5886,7 @@ var init_state_machine = __esm({
5871
5886
  VERIFY: ["FINALIZE", "IMPLEMENT", "VERIFY"],
5872
5887
  // pass → FINALIZE, fail → IMPLEMENT, retry
5873
5888
  FINALIZE: ["COMPLETE", "PICK_TICKET"],
5874
- // PICK_TICKET for issue-fix flow (bypass COMPLETE)
5889
+ // ISS-084: issues now route through COMPLETE too; PICK_TICKET kept for in-flight session compat
5875
5890
  COMPLETE: ["PICK_TICKET", "HANDOVER", "ISSUE_SWEEP", "SESSION_END"],
5876
5891
  ISSUE_FIX: ["FINALIZE", "PICK_TICKET", "ISSUE_FIX"],
5877
5892
  // T-153: fix done → FINALIZE, cancel → PICK_TICKET, retry self
@@ -5891,7 +5906,7 @@ var init_state_machine = __esm({
5891
5906
  // src/autonomous/context-pressure.ts
5892
5907
  function evaluatePressure(state) {
5893
5908
  const calls = state.contextPressure?.guideCallCount ?? state.guideCallCount ?? 0;
5894
- const tickets = state.contextPressure?.ticketsCompleted ?? state.completedTickets?.length ?? 0;
5909
+ const tickets = (state.completedTickets?.length ?? 0) + (state.resolvedIssues?.length ?? 0);
5895
5910
  const eventsBytes = state.contextPressure?.eventsLogBytes ?? 0;
5896
5911
  const tier = state.config?.compactThreshold ?? "high";
5897
5912
  const t = THRESHOLDS[tier] ?? THRESHOLDS["high"];
@@ -6434,17 +6449,22 @@ var init_pick_ticket = __esm({
6434
6449
  (c, i) => `${i + 1}. **${c.ticket.id}: ${c.ticket.title}** (${c.ticket.type})`
6435
6450
  ).join("\n");
6436
6451
  }
6437
- const highIssues = projectState.issues.filter(
6438
- (i) => i.status === "open" && (i.severity === "critical" || i.severity === "high")
6439
- );
6452
+ const allOpenIssues = projectState.issues.filter((i) => i.status === "open");
6453
+ const highIssues = allOpenIssues.filter((i) => i.severity === "critical" || i.severity === "high");
6454
+ const otherIssues = allOpenIssues.filter((i) => i.severity !== "critical" && i.severity !== "high");
6440
6455
  let issuesText = "";
6441
6456
  if (highIssues.length > 0) {
6442
6457
  issuesText = "\n\n## Open Issues (high+ severity)\n\n" + highIssues.map(
6443
6458
  (i, idx) => `${idx + 1}. **${i.id}: ${i.title}** (${i.severity})`
6444
6459
  ).join("\n");
6445
6460
  }
6461
+ if (otherIssues.length > 0) {
6462
+ issuesText += "\n\n## Open Issues (medium/low)\n\n" + otherIssues.map(
6463
+ (i, idx) => `${idx + 1}. **${i.id}: ${i.title}** (${i.severity})`
6464
+ ).join("\n");
6465
+ }
6446
6466
  const topCandidate = candidates.kind === "found" ? candidates.candidates[0] : null;
6447
- const hasIssues = highIssues.length > 0;
6467
+ const hasIssues = allOpenIssues.length > 0;
6448
6468
  if (!topCandidate && candidates.kind !== "found" && !hasIssues) {
6449
6469
  return { action: "goto", target: "COMPLETE" };
6450
6470
  }
@@ -6465,7 +6485,7 @@ var init_pick_ticket = __esm({
6465
6485
  "",
6466
6486
  "Or to fix an issue:",
6467
6487
  "```json",
6468
- `{ "sessionId": "${ctx.state.sessionId}", "action": "report", "report": { "completedAction": "issue_picked", "issueId": "${highIssues[0].id}" } }`,
6488
+ `{ "sessionId": "${ctx.state.sessionId}", "action": "report", "report": { "completedAction": "issue_picked", "issueId": "${(highIssues[0] ?? allOpenIssues[0]).id}" } }`,
6469
6489
  "```"
6470
6490
  ] : []
6471
6491
  ].join("\n"),
@@ -7784,7 +7804,7 @@ var init_finalize = __esm({
7784
7804
  }
7785
7805
  });
7786
7806
  ctx.appendEvent("commit", { commitHash: normalizedHash, issueId: currentIssue.id });
7787
- return { action: "goto", target: "PICK_TICKET" };
7807
+ return { action: "goto", target: "COMPLETE" };
7788
7808
  }
7789
7809
  const completedTicket = ctx.state.ticket ? { id: ctx.state.ticket.id, title: ctx.state.ticket.title, commitHash: normalizedHash, risk: ctx.state.ticket.risk, realizedRisk: ctx.state.ticket.realizedRisk } : void 0;
7790
7810
  ctx.writeState({
@@ -7822,6 +7842,8 @@ var init_complete = __esm({
7822
7842
  finalizeCheckpoint: null
7823
7843
  });
7824
7844
  const ticketsDone = ctx.state.completedTickets.length;
7845
+ const issuesDone = (ctx.state.resolvedIssues ?? []).length;
7846
+ const totalWorkDone = ticketsDone + issuesDone;
7825
7847
  const maxTickets = ctx.state.config.maxTicketsPerSession;
7826
7848
  const mode = ctx.state.mode ?? "auto";
7827
7849
  if (mode !== "auto") {
@@ -7842,15 +7864,17 @@ var init_complete = __esm({
7842
7864
  };
7843
7865
  }
7844
7866
  const handoverInterval = ctx.state.config.handoverInterval ?? 5;
7845
- if (handoverInterval > 0 && ticketsDone > 0 && ticketsDone % handoverInterval === 0) {
7867
+ if (handoverInterval > 0 && totalWorkDone > 0 && totalWorkDone % handoverInterval === 0) {
7846
7868
  try {
7847
7869
  const { handleHandoverCreate: handleHandoverCreate3 } = await Promise.resolve().then(() => (init_handover(), handover_exports));
7848
7870
  const completedIds = ctx.state.completedTickets.map((t) => t.id).join(", ");
7871
+ const resolvedIds = (ctx.state.resolvedIssues ?? []).join(", ");
7849
7872
  const content = [
7850
- `# Checkpoint \u2014 ${ticketsDone} tickets completed`,
7873
+ `# Checkpoint \u2014 ${totalWorkDone} items completed`,
7851
7874
  "",
7852
7875
  `**Session:** ${ctx.state.sessionId}`,
7853
- `**Tickets:** ${completedIds}`,
7876
+ ...completedIds ? [`**Tickets:** ${completedIds}`] : [],
7877
+ ...resolvedIds ? [`**Issues resolved:** ${resolvedIds}`] : [],
7854
7878
  "",
7855
7879
  "This is an automatic mid-session checkpoint. The session is still active."
7856
7880
  ].join("\n");
@@ -7864,24 +7888,19 @@ var init_complete = __esm({
7864
7888
  await saveSnapshot2(ctx.root, loadResult);
7865
7889
  } catch {
7866
7890
  }
7867
- ctx.appendEvent("checkpoint", { ticketsDone, interval: handoverInterval });
7891
+ ctx.appendEvent("checkpoint", { ticketsDone, issuesDone, totalWorkDone, interval: handoverInterval });
7868
7892
  }
7893
+ const { state: projectState } = await ctx.loadProject();
7869
7894
  let nextTarget;
7870
- if (maxTickets > 0 && ticketsDone >= maxTickets) {
7895
+ if (maxTickets > 0 && totalWorkDone >= maxTickets) {
7871
7896
  nextTarget = "HANDOVER";
7872
7897
  } else {
7873
- nextTarget = "PICK_TICKET";
7874
- }
7875
- const { state: projectState } = await ctx.loadProject();
7876
- const nextResult = nextTickets(projectState, 1);
7877
- if (nextResult.kind !== "found") {
7878
- const highIssues = projectState.issues.filter(
7879
- (i) => i.status === "open" && (i.severity === "critical" || i.severity === "high")
7880
- );
7881
- if (highIssues.length > 0) {
7898
+ const nextResult = nextTickets(projectState, 1);
7899
+ if (nextResult.kind === "found") {
7882
7900
  nextTarget = "PICK_TICKET";
7883
7901
  } else {
7884
- nextTarget = "HANDOVER";
7902
+ const openIssues = projectState.issues.filter((i) => i.status === "open");
7903
+ nextTarget = openIssues.length > 0 ? "PICK_TICKET" : "HANDOVER";
7885
7904
  }
7886
7905
  }
7887
7906
  if (nextTarget === "HANDOVER") {
@@ -7896,7 +7915,7 @@ var init_complete = __esm({
7896
7915
  target: "HANDOVER",
7897
7916
  result: {
7898
7917
  instruction: [
7899
- `# Session Complete \u2014 ${ticketsDone} ticket(s) done`,
7918
+ `# Session Complete \u2014 ${ticketsDone} ticket(s) and ${issuesDone} issue(s) done`,
7900
7919
  "",
7901
7920
  "Write a session handover summarizing what was accomplished, decisions made, and what's next.",
7902
7921
  "",
@@ -7965,6 +7984,7 @@ var init_lesson_capture = __esm({
7965
7984
  const planReviews = ctx.state.reviews.plan ?? [];
7966
7985
  const codeReviews = ctx.state.reviews.code ?? [];
7967
7986
  const ticketsDone = ctx.state.completedTickets.length;
7987
+ const issuesDone = (ctx.state.resolvedIssues ?? []).length;
7968
7988
  const planFindings = planReviews.reduce((sum, r) => sum + (r.findingCount ?? 0), 0);
7969
7989
  const planCritical = planReviews.reduce((sum, r) => sum + (r.criticalCount ?? 0), 0);
7970
7990
  const planMajor = planReviews.reduce((sum, r) => sum + (r.majorCount ?? 0), 0);
@@ -7986,7 +8006,7 @@ var init_lesson_capture = __esm({
7986
8006
  instruction: [
7987
8007
  "# Capture Lessons from Review Findings",
7988
8008
  "",
7989
- `This session completed ${ticketsDone} ticket(s). Review summary:`,
8009
+ `This session completed ${ticketsDone} ticket(s) and ${issuesDone} issue(s). Review summary:`,
7990
8010
  `- **Plan reviews:** ${planReviews.length} round(s), ${planCritical} critical, ${planMajor} major, ${planFindings} total findings`,
7991
8011
  `- **Code reviews:** ${codeReviews.length} round(s), ${codeCritical} critical, ${codeMajor} major, ${codeFindings} total findings`,
7992
8012
  "",
@@ -8217,9 +8237,10 @@ var init_handover2 = __esm({
8217
8237
  id = "HANDOVER";
8218
8238
  async enter(ctx) {
8219
8239
  const ticketsDone = ctx.state.completedTickets.length;
8240
+ const issuesDone = (ctx.state.resolvedIssues ?? []).length;
8220
8241
  return {
8221
8242
  instruction: [
8222
- `# Session Complete \u2014 ${ticketsDone} ticket(s) done`,
8243
+ `# Session Complete \u2014 ${ticketsDone} ticket(s) and ${issuesDone} issue(s) done`,
8223
8244
  "",
8224
8245
  "Write a session handover summarizing what was accomplished, decisions made, and what's next.",
8225
8246
  "",
@@ -8266,18 +8287,22 @@ var init_handover2 = __esm({
8266
8287
  });
8267
8288
  ctx.appendEvent("session_end", {
8268
8289
  ticketsCompleted: ctx.state.completedTickets.length,
8290
+ issuesResolved: (ctx.state.resolvedIssues ?? []).length,
8269
8291
  handoverFailed
8270
8292
  });
8271
8293
  const ticketsDone = ctx.state.completedTickets.length;
8294
+ const issuesDone = (ctx.state.resolvedIssues ?? []).length;
8295
+ const resolvedList = (ctx.state.resolvedIssues ?? []).map((id) => `- ${id} (resolved)`).join("\n");
8272
8296
  return {
8273
8297
  action: "advance",
8274
8298
  result: {
8275
8299
  instruction: [
8276
8300
  "# Session Complete",
8277
8301
  "",
8278
- `${ticketsDone} ticket(s) completed.${handoverFailed ? " Handover creation failed \u2014 fallback saved to session directory." : " Handover written."}${stashPopFailed ? " Auto-stash pop failed \u2014 run `git stash pop` manually." : ""} Session ended.`,
8302
+ `${ticketsDone} ticket(s) and ${issuesDone} issue(s) completed.${handoverFailed ? " Handover creation failed \u2014 fallback saved to session directory." : " Handover written."}${stashPopFailed ? " Auto-stash pop failed \u2014 run `git stash pop` manually." : ""} Session ended.`,
8279
8303
  "",
8280
- ctx.state.completedTickets.map((t) => `- ${t.id}${t.title ? `: ${t.title}` : ""} (${t.commitHash ?? "no commit"})`).join("\n")
8304
+ ctx.state.completedTickets.map((t) => `- ${t.id}${t.title ? `: ${t.title}` : ""} (${t.commitHash ?? "no commit"})`).join("\n"),
8305
+ ...resolvedList ? [resolvedList] : []
8281
8306
  ].join("\n"),
8282
8307
  reminders: [],
8283
8308
  transitionedFrom: "HANDOVER"
@@ -8358,7 +8383,7 @@ function getInstalledVersion() {
8358
8383
  }
8359
8384
  }
8360
8385
  function getRunningVersion() {
8361
- return "0.1.56";
8386
+ return "0.1.58";
8362
8387
  }
8363
8388
  var init_version_check = __esm({
8364
8389
  "src/autonomous/version-check.ts"() {
@@ -9304,7 +9329,7 @@ ${driftPreamble}Recovered to state: **${mapping.state}**. Continue from here.`,
9304
9329
  instruction: [
9305
9330
  "# Resumed After Compact \u2014 Continue Working",
9306
9331
  "",
9307
- `${written.completedTickets.length} ticket(s) done so far. Context compacted. Pick the next ticket immediately.`,
9332
+ `${written.completedTickets.length} ticket(s) and ${(written.resolvedIssues ?? []).length} issue(s) done so far. Context compacted. Pick the next ticket or issue immediately.`,
9308
9333
  "",
9309
9334
  candidatesText,
9310
9335
  "",
@@ -9420,7 +9445,8 @@ async function handleCancel(root, args) {
9420
9445
  return guideError(new Error("Session already ended."));
9421
9446
  }
9422
9447
  const isAutoMode = info.state.mode === "auto" || !info.state.mode;
9423
- const hasTicketsRemaining = info.state.config.maxTicketsPerSession === 0 || info.state.completedTickets.length < info.state.config.maxTicketsPerSession;
9448
+ const totalDone = info.state.completedTickets.length + (info.state.resolvedIssues?.length ?? 0);
9449
+ const hasTicketsRemaining = info.state.config.maxTicketsPerSession === 0 || totalDone < info.state.config.maxTicketsPerSession;
9424
9450
  const isWorkingState = !["SESSION_END", "HANDOVER", "COMPACT"].includes(info.state.state);
9425
9451
  if (isAutoMode && hasTicketsRemaining && isWorkingState) {
9426
9452
  return {
@@ -9429,7 +9455,7 @@ async function handleCancel(root, args) {
9429
9455
  text: [
9430
9456
  "# Cancel Rejected \u2014 Session Still Active",
9431
9457
  "",
9432
- `You have completed ${info.state.completedTickets.length} ticket(s) with more work remaining.`,
9458
+ `You have completed ${info.state.completedTickets.length} ticket(s) and ${(info.state.resolvedIssues ?? []).length} issue(s) with more work remaining.`,
9433
9459
  "Do NOT cancel an autonomous session due to context size.",
9434
9460
  "If you need to manage context, Claude Code handles compaction automatically.",
9435
9461
  "",
@@ -9497,14 +9523,14 @@ async function handleCancel(root, args) {
9497
9523
  });
9498
9524
  const stashNote = stashPopFailed ? " Auto-stash pop failed \u2014 run `git stash pop` manually." : "";
9499
9525
  return {
9500
- content: [{ type: "text", text: `Session ${args.sessionId} cancelled. ${written.completedTickets.length} ticket(s) were completed.${stashNote}` }]
9526
+ content: [{ type: "text", text: `Session ${args.sessionId} cancelled. ${written.completedTickets.length} ticket(s) and ${(written.resolvedIssues ?? []).length} issue(s) were completed.${stashNote}` }]
9501
9527
  };
9502
9528
  }
9503
9529
  function guideResult(state, currentState, opts) {
9504
9530
  const summary = {
9505
9531
  ticket: state.ticket ? `${state.ticket.id}: ${state.ticket.title}` : "none",
9506
9532
  risk: state.ticket?.risk ?? "unknown",
9507
- completed: state.completedTickets.map((t) => t.id),
9533
+ completed: [...state.completedTickets.map((t) => t.id), ...state.resolvedIssues ?? []],
9508
9534
  currentStep: currentState,
9509
9535
  contextPressure: state.contextPressure?.level ?? "low",
9510
9536
  branch: state.git?.branch ?? null
@@ -10955,7 +10981,7 @@ var init_mcp = __esm({
10955
10981
  init_init();
10956
10982
  ENV_VAR2 = "CLAUDESTORY_PROJECT_ROOT";
10957
10983
  CONFIG_PATH2 = ".story/config.json";
10958
- version = "0.1.56";
10984
+ version = "0.1.58";
10959
10985
  main().catch((err) => {
10960
10986
  process.stderr.write(`Fatal: ${err instanceof Error ? err.message : String(err)}
10961
10987
  `);
@@ -11559,6 +11585,7 @@ var init_reference = __esm({
11559
11585
  // src/cli/commands/setup-skill.ts
11560
11586
  var setup_skill_exports = {};
11561
11587
  __export(setup_skill_exports, {
11588
+ copyDirRecursive: () => copyDirRecursive,
11562
11589
  handleSetupSkill: () => handleSetupSkill,
11563
11590
  registerPreCompactHook: () => registerPreCompactHook,
11564
11591
  registerSessionStartHook: () => registerSessionStartHook,
@@ -11566,7 +11593,7 @@ __export(setup_skill_exports, {
11566
11593
  removeHook: () => removeHook,
11567
11594
  resolveSkillSourceDir: () => resolveSkillSourceDir
11568
11595
  });
11569
- import { mkdir as mkdir5, writeFile as writeFile3, readFile as readFile5, rm, rename as rename2, unlink as unlink3 } from "fs/promises";
11596
+ import { mkdir as mkdir5, writeFile as writeFile3, readFile as readFile5, readdir as readdir4, copyFile, rm, rename as rename2, unlink as unlink3 } from "fs/promises";
11570
11597
  import { existsSync as existsSync12 } from "fs";
11571
11598
  import { join as join21, dirname as dirname5 } from "path";
11572
11599
  import { homedir } from "os";
@@ -11587,6 +11614,43 @@ function resolveSkillSourceDir() {
11587
11614
  ${sourcePath}`
11588
11615
  );
11589
11616
  }
11617
+ async function copyDirRecursive(srcDir, destDir) {
11618
+ const tmpDir = destDir + ".tmp";
11619
+ const bakDir = destDir + ".bak";
11620
+ if (!existsSync12(destDir) && existsSync12(bakDir)) {
11621
+ await rename2(bakDir, destDir);
11622
+ }
11623
+ if (existsSync12(tmpDir)) await rm(tmpDir, { recursive: true, force: true });
11624
+ if (existsSync12(bakDir)) await rm(bakDir, { recursive: true, force: true });
11625
+ await mkdir5(tmpDir, { recursive: true });
11626
+ const entries = await readdir4(srcDir, { withFileTypes: true, recursive: true });
11627
+ const written = [];
11628
+ for (const entry of entries) {
11629
+ if (!entry.isFile()) continue;
11630
+ 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);
11634
+ await mkdir5(dirname5(destPath), { recursive: true });
11635
+ await copyFile(srcPath, destPath);
11636
+ written.push(relativePath);
11637
+ }
11638
+ if (existsSync12(destDir)) {
11639
+ await rename2(destDir, bakDir);
11640
+ }
11641
+ try {
11642
+ await rename2(tmpDir, destDir);
11643
+ } catch (err) {
11644
+ if (existsSync12(bakDir)) await rename2(bakDir, destDir).catch(() => {
11645
+ });
11646
+ await rm(tmpDir, { recursive: true, force: true }).catch(() => {
11647
+ });
11648
+ throw err;
11649
+ }
11650
+ await rm(bakDir, { recursive: true, force: true }).catch(() => {
11651
+ });
11652
+ return written;
11653
+ }
11590
11654
  function isHookWithCommand(entry, command) {
11591
11655
  if (typeof entry !== "object" || entry === null) return false;
11592
11656
  const e = entry;
@@ -11772,6 +11836,19 @@ async function handleSetupSkill(options = {}) {
11772
11836
  missingFiles.push(filename);
11773
11837
  }
11774
11838
  }
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}
11848
+ `);
11849
+ missingFiles.push("design/");
11850
+ }
11851
+ }
11775
11852
  log(`${existed ? "Updated" : "Installed"} /story skill at ${skillDir}/`);
11776
11853
  log(` ${writtenFiles.join(" + ")} written`);
11777
11854
  if (missingFiles.length > 0) {
@@ -14386,7 +14463,7 @@ async function runCli() {
14386
14463
  registerSessionCommand: registerSessionCommand2,
14387
14464
  registerRepairCommand: registerRepairCommand2
14388
14465
  } = await Promise.resolve().then(() => (init_register(), register_exports));
14389
- const version2 = "0.1.56";
14466
+ const version2 = "0.1.58";
14390
14467
  class HandledError extends Error {
14391
14468
  constructor() {
14392
14469
  super("HANDLED_ERROR");
package/dist/mcp.js CHANGED
@@ -3912,7 +3912,8 @@ function refreshLease(state) {
3912
3912
  contextPressure: {
3913
3913
  ...state.contextPressure,
3914
3914
  guideCallCount: newCallCount,
3915
- ticketsCompleted: state.completedTickets?.length ?? 0
3915
+ // ISS-084: Include resolved issues in work count
3916
+ ticketsCompleted: (state.completedTickets?.length ?? 0) + (state.resolvedIssues?.length ?? 0)
3916
3917
  }
3917
3918
  };
3918
3919
  }
@@ -5469,7 +5470,7 @@ var TRANSITIONS = {
5469
5470
  VERIFY: ["FINALIZE", "IMPLEMENT", "VERIFY"],
5470
5471
  // pass → FINALIZE, fail → IMPLEMENT, retry
5471
5472
  FINALIZE: ["COMPLETE", "PICK_TICKET"],
5472
- // PICK_TICKET for issue-fix flow (bypass COMPLETE)
5473
+ // ISS-084: issues now route through COMPLETE too; PICK_TICKET kept for in-flight session compat
5473
5474
  COMPLETE: ["PICK_TICKET", "HANDOVER", "ISSUE_SWEEP", "SESSION_END"],
5474
5475
  ISSUE_FIX: ["FINALIZE", "PICK_TICKET", "ISSUE_FIX"],
5475
5476
  // T-153: fix done → FINALIZE, cancel → PICK_TICKET, retry self
@@ -5515,7 +5516,7 @@ var THRESHOLDS = {
5515
5516
  };
5516
5517
  function evaluatePressure(state) {
5517
5518
  const calls = state.contextPressure?.guideCallCount ?? state.guideCallCount ?? 0;
5518
- const tickets = state.contextPressure?.ticketsCompleted ?? state.completedTickets?.length ?? 0;
5519
+ const tickets = (state.completedTickets?.length ?? 0) + (state.resolvedIssues?.length ?? 0);
5519
5520
  const eventsBytes = state.contextPressure?.eventsLogBytes ?? 0;
5520
5521
  const tier = state.config?.compactThreshold ?? "high";
5521
5522
  const t = THRESHOLDS[tier] ?? THRESHOLDS["high"];
@@ -6003,17 +6004,22 @@ var PickTicketStage = class {
6003
6004
  (c, i) => `${i + 1}. **${c.ticket.id}: ${c.ticket.title}** (${c.ticket.type})`
6004
6005
  ).join("\n");
6005
6006
  }
6006
- const highIssues = projectState.issues.filter(
6007
- (i) => i.status === "open" && (i.severity === "critical" || i.severity === "high")
6008
- );
6007
+ const allOpenIssues = projectState.issues.filter((i) => i.status === "open");
6008
+ const highIssues = allOpenIssues.filter((i) => i.severity === "critical" || i.severity === "high");
6009
+ const otherIssues = allOpenIssues.filter((i) => i.severity !== "critical" && i.severity !== "high");
6009
6010
  let issuesText = "";
6010
6011
  if (highIssues.length > 0) {
6011
6012
  issuesText = "\n\n## Open Issues (high+ severity)\n\n" + highIssues.map(
6012
6013
  (i, idx) => `${idx + 1}. **${i.id}: ${i.title}** (${i.severity})`
6013
6014
  ).join("\n");
6014
6015
  }
6016
+ if (otherIssues.length > 0) {
6017
+ issuesText += "\n\n## Open Issues (medium/low)\n\n" + otherIssues.map(
6018
+ (i, idx) => `${idx + 1}. **${i.id}: ${i.title}** (${i.severity})`
6019
+ ).join("\n");
6020
+ }
6015
6021
  const topCandidate = candidates.kind === "found" ? candidates.candidates[0] : null;
6016
- const hasIssues = highIssues.length > 0;
6022
+ const hasIssues = allOpenIssues.length > 0;
6017
6023
  if (!topCandidate && candidates.kind !== "found" && !hasIssues) {
6018
6024
  return { action: "goto", target: "COMPLETE" };
6019
6025
  }
@@ -6034,7 +6040,7 @@ var PickTicketStage = class {
6034
6040
  "",
6035
6041
  "Or to fix an issue:",
6036
6042
  "```json",
6037
- `{ "sessionId": "${ctx.state.sessionId}", "action": "report", "report": { "completedAction": "issue_picked", "issueId": "${highIssues[0].id}" } }`,
6043
+ `{ "sessionId": "${ctx.state.sessionId}", "action": "report", "report": { "completedAction": "issue_picked", "issueId": "${(highIssues[0] ?? allOpenIssues[0]).id}" } }`,
6038
6044
  "```"
6039
6045
  ] : []
6040
6046
  ].join("\n"),
@@ -7292,7 +7298,7 @@ var FinalizeStage = class {
7292
7298
  }
7293
7299
  });
7294
7300
  ctx.appendEvent("commit", { commitHash: normalizedHash, issueId: currentIssue.id });
7295
- return { action: "goto", target: "PICK_TICKET" };
7301
+ return { action: "goto", target: "COMPLETE" };
7296
7302
  }
7297
7303
  const completedTicket = ctx.state.ticket ? { id: ctx.state.ticket.id, title: ctx.state.ticket.title, commitHash: normalizedHash, risk: ctx.state.ticket.risk, realizedRisk: ctx.state.ticket.realizedRisk } : void 0;
7298
7304
  ctx.writeState({
@@ -7322,6 +7328,8 @@ var CompleteStage = class {
7322
7328
  finalizeCheckpoint: null
7323
7329
  });
7324
7330
  const ticketsDone = ctx.state.completedTickets.length;
7331
+ const issuesDone = (ctx.state.resolvedIssues ?? []).length;
7332
+ const totalWorkDone = ticketsDone + issuesDone;
7325
7333
  const maxTickets = ctx.state.config.maxTicketsPerSession;
7326
7334
  const mode = ctx.state.mode ?? "auto";
7327
7335
  if (mode !== "auto") {
@@ -7342,15 +7350,17 @@ var CompleteStage = class {
7342
7350
  };
7343
7351
  }
7344
7352
  const handoverInterval = ctx.state.config.handoverInterval ?? 5;
7345
- if (handoverInterval > 0 && ticketsDone > 0 && ticketsDone % handoverInterval === 0) {
7353
+ if (handoverInterval > 0 && totalWorkDone > 0 && totalWorkDone % handoverInterval === 0) {
7346
7354
  try {
7347
7355
  const { handleHandoverCreate: handleHandoverCreate3 } = await Promise.resolve().then(() => (init_handover(), handover_exports));
7348
7356
  const completedIds = ctx.state.completedTickets.map((t) => t.id).join(", ");
7357
+ const resolvedIds = (ctx.state.resolvedIssues ?? []).join(", ");
7349
7358
  const content = [
7350
- `# Checkpoint \u2014 ${ticketsDone} tickets completed`,
7359
+ `# Checkpoint \u2014 ${totalWorkDone} items completed`,
7351
7360
  "",
7352
7361
  `**Session:** ${ctx.state.sessionId}`,
7353
- `**Tickets:** ${completedIds}`,
7362
+ ...completedIds ? [`**Tickets:** ${completedIds}`] : [],
7363
+ ...resolvedIds ? [`**Issues resolved:** ${resolvedIds}`] : [],
7354
7364
  "",
7355
7365
  "This is an automatic mid-session checkpoint. The session is still active."
7356
7366
  ].join("\n");
@@ -7364,24 +7374,19 @@ var CompleteStage = class {
7364
7374
  await saveSnapshot2(ctx.root, loadResult);
7365
7375
  } catch {
7366
7376
  }
7367
- ctx.appendEvent("checkpoint", { ticketsDone, interval: handoverInterval });
7377
+ ctx.appendEvent("checkpoint", { ticketsDone, issuesDone, totalWorkDone, interval: handoverInterval });
7368
7378
  }
7379
+ const { state: projectState } = await ctx.loadProject();
7369
7380
  let nextTarget;
7370
- if (maxTickets > 0 && ticketsDone >= maxTickets) {
7381
+ if (maxTickets > 0 && totalWorkDone >= maxTickets) {
7371
7382
  nextTarget = "HANDOVER";
7372
7383
  } else {
7373
- nextTarget = "PICK_TICKET";
7374
- }
7375
- const { state: projectState } = await ctx.loadProject();
7376
- const nextResult = nextTickets(projectState, 1);
7377
- if (nextResult.kind !== "found") {
7378
- const highIssues = projectState.issues.filter(
7379
- (i) => i.status === "open" && (i.severity === "critical" || i.severity === "high")
7380
- );
7381
- if (highIssues.length > 0) {
7384
+ const nextResult = nextTickets(projectState, 1);
7385
+ if (nextResult.kind === "found") {
7382
7386
  nextTarget = "PICK_TICKET";
7383
7387
  } else {
7384
- nextTarget = "HANDOVER";
7388
+ const openIssues = projectState.issues.filter((i) => i.status === "open");
7389
+ nextTarget = openIssues.length > 0 ? "PICK_TICKET" : "HANDOVER";
7385
7390
  }
7386
7391
  }
7387
7392
  if (nextTarget === "HANDOVER") {
@@ -7396,7 +7401,7 @@ var CompleteStage = class {
7396
7401
  target: "HANDOVER",
7397
7402
  result: {
7398
7403
  instruction: [
7399
- `# Session Complete \u2014 ${ticketsDone} ticket(s) done`,
7404
+ `# Session Complete \u2014 ${ticketsDone} ticket(s) and ${issuesDone} issue(s) done`,
7400
7405
  "",
7401
7406
  "Write a session handover summarizing what was accomplished, decisions made, and what's next.",
7402
7407
  "",
@@ -7459,6 +7464,7 @@ var LessonCaptureStage = class {
7459
7464
  const planReviews = ctx.state.reviews.plan ?? [];
7460
7465
  const codeReviews = ctx.state.reviews.code ?? [];
7461
7466
  const ticketsDone = ctx.state.completedTickets.length;
7467
+ const issuesDone = (ctx.state.resolvedIssues ?? []).length;
7462
7468
  const planFindings = planReviews.reduce((sum, r) => sum + (r.findingCount ?? 0), 0);
7463
7469
  const planCritical = planReviews.reduce((sum, r) => sum + (r.criticalCount ?? 0), 0);
7464
7470
  const planMajor = planReviews.reduce((sum, r) => sum + (r.majorCount ?? 0), 0);
@@ -7480,7 +7486,7 @@ var LessonCaptureStage = class {
7480
7486
  instruction: [
7481
7487
  "# Capture Lessons from Review Findings",
7482
7488
  "",
7483
- `This session completed ${ticketsDone} ticket(s). Review summary:`,
7489
+ `This session completed ${ticketsDone} ticket(s) and ${issuesDone} issue(s). Review summary:`,
7484
7490
  `- **Plan reviews:** ${planReviews.length} round(s), ${planCritical} critical, ${planMajor} major, ${planFindings} total findings`,
7485
7491
  `- **Code reviews:** ${codeReviews.length} round(s), ${codeCritical} critical, ${codeMajor} major, ${codeFindings} total findings`,
7486
7492
  "",
@@ -7692,9 +7698,10 @@ var HandoverStage = class {
7692
7698
  id = "HANDOVER";
7693
7699
  async enter(ctx) {
7694
7700
  const ticketsDone = ctx.state.completedTickets.length;
7701
+ const issuesDone = (ctx.state.resolvedIssues ?? []).length;
7695
7702
  return {
7696
7703
  instruction: [
7697
- `# Session Complete \u2014 ${ticketsDone} ticket(s) done`,
7704
+ `# Session Complete \u2014 ${ticketsDone} ticket(s) and ${issuesDone} issue(s) done`,
7698
7705
  "",
7699
7706
  "Write a session handover summarizing what was accomplished, decisions made, and what's next.",
7700
7707
  "",
@@ -7741,18 +7748,22 @@ var HandoverStage = class {
7741
7748
  });
7742
7749
  ctx.appendEvent("session_end", {
7743
7750
  ticketsCompleted: ctx.state.completedTickets.length,
7751
+ issuesResolved: (ctx.state.resolvedIssues ?? []).length,
7744
7752
  handoverFailed
7745
7753
  });
7746
7754
  const ticketsDone = ctx.state.completedTickets.length;
7755
+ const issuesDone = (ctx.state.resolvedIssues ?? []).length;
7756
+ const resolvedList = (ctx.state.resolvedIssues ?? []).map((id) => `- ${id} (resolved)`).join("\n");
7747
7757
  return {
7748
7758
  action: "advance",
7749
7759
  result: {
7750
7760
  instruction: [
7751
7761
  "# Session Complete",
7752
7762
  "",
7753
- `${ticketsDone} ticket(s) completed.${handoverFailed ? " Handover creation failed \u2014 fallback saved to session directory." : " Handover written."}${stashPopFailed ? " Auto-stash pop failed \u2014 run `git stash pop` manually." : ""} Session ended.`,
7763
+ `${ticketsDone} ticket(s) and ${issuesDone} issue(s) completed.${handoverFailed ? " Handover creation failed \u2014 fallback saved to session directory." : " Handover written."}${stashPopFailed ? " Auto-stash pop failed \u2014 run `git stash pop` manually." : ""} Session ended.`,
7754
7764
  "",
7755
- ctx.state.completedTickets.map((t) => `- ${t.id}${t.title ? `: ${t.title}` : ""} (${t.commitHash ?? "no commit"})`).join("\n")
7765
+ ctx.state.completedTickets.map((t) => `- ${t.id}${t.title ? `: ${t.title}` : ""} (${t.commitHash ?? "no commit"})`).join("\n"),
7766
+ ...resolvedList ? [resolvedList] : []
7756
7767
  ].join("\n"),
7757
7768
  reminders: [],
7758
7769
  transitionedFrom: "HANDOVER"
@@ -7816,7 +7827,7 @@ function getInstalledVersion() {
7816
7827
  }
7817
7828
  }
7818
7829
  function getRunningVersion() {
7819
- return "0.1.56";
7830
+ return "0.1.58";
7820
7831
  }
7821
7832
 
7822
7833
  // src/autonomous/guide.ts
@@ -8779,7 +8790,7 @@ ${driftPreamble}Recovered to state: **${mapping.state}**. Continue from here.`,
8779
8790
  instruction: [
8780
8791
  "# Resumed After Compact \u2014 Continue Working",
8781
8792
  "",
8782
- `${written.completedTickets.length} ticket(s) done so far. Context compacted. Pick the next ticket immediately.`,
8793
+ `${written.completedTickets.length} ticket(s) and ${(written.resolvedIssues ?? []).length} issue(s) done so far. Context compacted. Pick the next ticket or issue immediately.`,
8783
8794
  "",
8784
8795
  candidatesText,
8785
8796
  "",
@@ -8895,7 +8906,8 @@ async function handleCancel(root, args) {
8895
8906
  return guideError(new Error("Session already ended."));
8896
8907
  }
8897
8908
  const isAutoMode = info.state.mode === "auto" || !info.state.mode;
8898
- const hasTicketsRemaining = info.state.config.maxTicketsPerSession === 0 || info.state.completedTickets.length < info.state.config.maxTicketsPerSession;
8909
+ const totalDone = info.state.completedTickets.length + (info.state.resolvedIssues?.length ?? 0);
8910
+ const hasTicketsRemaining = info.state.config.maxTicketsPerSession === 0 || totalDone < info.state.config.maxTicketsPerSession;
8899
8911
  const isWorkingState = !["SESSION_END", "HANDOVER", "COMPACT"].includes(info.state.state);
8900
8912
  if (isAutoMode && hasTicketsRemaining && isWorkingState) {
8901
8913
  return {
@@ -8904,7 +8916,7 @@ async function handleCancel(root, args) {
8904
8916
  text: [
8905
8917
  "# Cancel Rejected \u2014 Session Still Active",
8906
8918
  "",
8907
- `You have completed ${info.state.completedTickets.length} ticket(s) with more work remaining.`,
8919
+ `You have completed ${info.state.completedTickets.length} ticket(s) and ${(info.state.resolvedIssues ?? []).length} issue(s) with more work remaining.`,
8908
8920
  "Do NOT cancel an autonomous session due to context size.",
8909
8921
  "If you need to manage context, Claude Code handles compaction automatically.",
8910
8922
  "",
@@ -8972,14 +8984,14 @@ async function handleCancel(root, args) {
8972
8984
  });
8973
8985
  const stashNote = stashPopFailed ? " Auto-stash pop failed \u2014 run `git stash pop` manually." : "";
8974
8986
  return {
8975
- content: [{ type: "text", text: `Session ${args.sessionId} cancelled. ${written.completedTickets.length} ticket(s) were completed.${stashNote}` }]
8987
+ content: [{ type: "text", text: `Session ${args.sessionId} cancelled. ${written.completedTickets.length} ticket(s) and ${(written.resolvedIssues ?? []).length} issue(s) were completed.${stashNote}` }]
8976
8988
  };
8977
8989
  }
8978
8990
  function guideResult(state, currentState, opts) {
8979
8991
  const summary = {
8980
8992
  ticket: state.ticket ? `${state.ticket.id}: ${state.ticket.title}` : "none",
8981
8993
  risk: state.ticket?.risk ?? "unknown",
8982
- completed: state.completedTickets.map((t) => t.id),
8994
+ completed: [...state.completedTickets.map((t) => t.id), ...state.resolvedIssues ?? []],
8983
8995
  currentStep: currentState,
8984
8996
  contextPressure: state.contextPressure?.level ?? "low",
8985
8997
  branch: state.git?.branch ?? null
@@ -10087,7 +10099,7 @@ async function ensureGitignoreEntries(gitignorePath, entries) {
10087
10099
  // src/mcp/index.ts
10088
10100
  var ENV_VAR2 = "CLAUDESTORY_PROJECT_ROOT";
10089
10101
  var CONFIG_PATH2 = ".story/config.json";
10090
- var version = "0.1.56";
10102
+ var version = "0.1.58";
10091
10103
  function tryDiscoverRoot() {
10092
10104
  const envRoot = process.env[ENV_VAR2];
10093
10105
  if (envRoot) {
package/package.json CHANGED
@@ -1,8 +1,13 @@
1
1
  {
2
2
  "name": "@anthropologies/claudestory",
3
- "version": "0.1.56",
3
+ "version": "0.1.58",
4
4
  "license": "PolyForm-Noncommercial-1.0.0",
5
5
  "description": "An agentic development framework. Track tickets, issues, and progress for your project so every session builds on the last.",
6
+ "homepage": "https://claudestory.com",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/AmirShayegh/ClaudeStory"
10
+ },
6
11
  "keywords": [
7
12
  "claudestory",
8
13
  "claude-code",