@anthropologies/claudestory 0.1.23 → 0.1.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +78 -16
- package/dist/mcp.js +77 -15
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -5798,6 +5798,13 @@ async function gitStashPop(cwd, commitHash) {
|
|
|
5798
5798
|
}
|
|
5799
5799
|
return git(cwd, ["stash", "pop", match.ref], () => void 0);
|
|
5800
5800
|
}
|
|
5801
|
+
async function gitDiffTreeNames(cwd, commitHash) {
|
|
5802
|
+
return git(
|
|
5803
|
+
cwd,
|
|
5804
|
+
["diff-tree", "--name-only", "--no-commit-id", "-r", commitHash],
|
|
5805
|
+
(out) => out.split("\n").filter((l) => l.trim().length > 0)
|
|
5806
|
+
);
|
|
5807
|
+
}
|
|
5801
5808
|
async function gitLogRange(cwd, from, to, limit = 20) {
|
|
5802
5809
|
if (from && !SAFE_REF.test(from)) {
|
|
5803
5810
|
return { ok: false, reason: "invalid_ref", message: `Invalid git ref: ${from}` };
|
|
@@ -6372,8 +6379,10 @@ var init_plan_review = __esm({
|
|
|
6372
6379
|
const isRevise = verdict === "revise" || verdict === "request_changes";
|
|
6373
6380
|
const isReject = verdict === "reject";
|
|
6374
6381
|
let nextAction;
|
|
6375
|
-
if (isReject
|
|
6382
|
+
if (isReject) {
|
|
6376
6383
|
nextAction = "PLAN";
|
|
6384
|
+
} else if (isRevise) {
|
|
6385
|
+
nextAction = "PLAN_REVIEW";
|
|
6377
6386
|
} else if (verdict === "approve" || !hasCriticalOrMajor && roundNum >= minRounds) {
|
|
6378
6387
|
nextAction = "IMPLEMENT";
|
|
6379
6388
|
} else if (roundNum >= 5) {
|
|
@@ -6395,7 +6404,21 @@ var init_plan_review = __esm({
|
|
|
6395
6404
|
return {
|
|
6396
6405
|
action: "back",
|
|
6397
6406
|
target: "PLAN",
|
|
6398
|
-
reason:
|
|
6407
|
+
reason: "reject"
|
|
6408
|
+
};
|
|
6409
|
+
}
|
|
6410
|
+
if (isRevise) {
|
|
6411
|
+
const findingSummary = findings.length > 0 ? findings.slice(0, 5).map((f) => `- [${f.severity}] ${f.description}`).join("\n") : "Address the reviewer's concerns.";
|
|
6412
|
+
return {
|
|
6413
|
+
action: "retry",
|
|
6414
|
+
instruction: [
|
|
6415
|
+
`# Plan Review \u2014 Round ${roundNum} requested changes`,
|
|
6416
|
+
"",
|
|
6417
|
+
'Update the plan to address these findings, then call me with completedAction: "plan_review_round" and the new review verdict.',
|
|
6418
|
+
"",
|
|
6419
|
+
findingSummary
|
|
6420
|
+
].join("\n"),
|
|
6421
|
+
reminders: ["Update the plan file, then re-review. Do NOT rewrite from scratch."]
|
|
6399
6422
|
};
|
|
6400
6423
|
}
|
|
6401
6424
|
if (nextAction === "IMPLEMENT") {
|
|
@@ -6501,7 +6524,7 @@ function exhaustionAction(ctx) {
|
|
|
6501
6524
|
return {
|
|
6502
6525
|
action: "back",
|
|
6503
6526
|
target: "PLAN",
|
|
6504
|
-
reason: "
|
|
6527
|
+
reason: "TDD exhausted: could not verify new failing tests after 3 attempts. Revise the plan to make the test expectations clearer or simpler."
|
|
6505
6528
|
};
|
|
6506
6529
|
}
|
|
6507
6530
|
var MAX_WRITE_TESTS_RETRIES, EXIT_CODE_REGEX, FAIL_COUNT_REGEX, WriteTestsStage;
|
|
@@ -6664,6 +6687,13 @@ var init_test = __esm({
|
|
|
6664
6687
|
const retryCount = ctx.state.testRetryCount ?? 0;
|
|
6665
6688
|
const exitCodeMatch = notes.match(/exit\s*(?:code[:\s]*)?\s*(\d+)/i);
|
|
6666
6689
|
if (!exitCodeMatch) {
|
|
6690
|
+
const nextRetry = retryCount + 1;
|
|
6691
|
+
if (nextRetry >= MAX_TEST_RETRIES) {
|
|
6692
|
+
ctx.writeState({ testRetryCount: 0 });
|
|
6693
|
+
ctx.appendEvent("tests_parse_exhausted", { retryCount: nextRetry });
|
|
6694
|
+
return { action: "advance" };
|
|
6695
|
+
}
|
|
6696
|
+
ctx.writeState({ testRetryCount: nextRetry });
|
|
6667
6697
|
return { action: "retry", instruction: 'Could not parse exit code from notes. Include "exit code: 0" (or non-zero) in your notes.' };
|
|
6668
6698
|
}
|
|
6669
6699
|
const exitCode = parseInt(exitCodeMatch[1], 10);
|
|
@@ -7092,6 +7122,22 @@ var init_finalize = __esm({
|
|
|
7092
7122
|
async handleStage(ctx, report) {
|
|
7093
7123
|
const stagedResult = await gitDiffCachedNames(ctx.root);
|
|
7094
7124
|
if (!stagedResult.ok || stagedResult.data.length === 0) {
|
|
7125
|
+
const headResult = await gitHead(ctx.root);
|
|
7126
|
+
const previousHead = ctx.state.git.expectedHead ?? ctx.state.git.initHead;
|
|
7127
|
+
if (headResult.ok && previousHead && headResult.data.hash !== previousHead) {
|
|
7128
|
+
const ticketId2 = ctx.state.ticket?.id;
|
|
7129
|
+
if (ticketId2) {
|
|
7130
|
+
const treeResult = await gitDiffTreeNames(ctx.root, headResult.data.hash);
|
|
7131
|
+
const ticketPath = `.story/tickets/${ticketId2}.json`;
|
|
7132
|
+
if (treeResult.ok && !treeResult.data.includes(ticketPath)) {
|
|
7133
|
+
return {
|
|
7134
|
+
action: "retry",
|
|
7135
|
+
instruction: `Commit detected (${headResult.data.hash.slice(0, 7)}) but ticket file ${ticketPath} is not in the commit. Amend the commit to include it: \`git add ${ticketPath} && git commit --amend --no-edit\`, then report completedAction: "commit_done" with the new hash.`
|
|
7136
|
+
};
|
|
7137
|
+
}
|
|
7138
|
+
}
|
|
7139
|
+
return this.handleCommit(ctx, { ...report, commitHash: headResult.data.hash });
|
|
7140
|
+
}
|
|
7095
7141
|
return { action: "retry", instruction: 'No files are staged. Stage your changes and call me again with completedAction: "files_staged".' };
|
|
7096
7142
|
}
|
|
7097
7143
|
const baselineUntracked = ctx.state.git.baseline?.untrackedPaths ?? [];
|
|
@@ -7109,6 +7155,16 @@ var init_finalize = __esm({
|
|
|
7109
7155
|
}
|
|
7110
7156
|
}
|
|
7111
7157
|
}
|
|
7158
|
+
const ticketId = ctx.state.ticket?.id;
|
|
7159
|
+
if (ticketId) {
|
|
7160
|
+
const ticketPath = `.story/tickets/${ticketId}.json`;
|
|
7161
|
+
if (!stagedResult.data.includes(ticketPath)) {
|
|
7162
|
+
return {
|
|
7163
|
+
action: "retry",
|
|
7164
|
+
instruction: `Ticket file ${ticketPath} is not staged. Run \`git add ${ticketPath}\` and call me again with completedAction: "files_staged".`
|
|
7165
|
+
};
|
|
7166
|
+
}
|
|
7167
|
+
}
|
|
7112
7168
|
ctx.writeState({
|
|
7113
7169
|
finalizeCheckpoint: overlapOverridden ? "staged_override" : "staged"
|
|
7114
7170
|
});
|
|
@@ -7169,27 +7225,29 @@ var init_finalize = __esm({
|
|
|
7169
7225
|
}
|
|
7170
7226
|
const headResult = await gitHead(ctx.root);
|
|
7171
7227
|
const previousHead = ctx.state.git.expectedHead ?? ctx.state.git.initHead;
|
|
7172
|
-
|
|
7228
|
+
const fullHead = headResult.ok ? headResult.data.hash : null;
|
|
7229
|
+
if (!fullHead || !fullHead.startsWith(commitHash) && commitHash !== fullHead) {
|
|
7173
7230
|
return {
|
|
7174
7231
|
action: "retry",
|
|
7175
|
-
instruction: `Commit hash mismatch: reported ${commitHash} but HEAD is ${
|
|
7232
|
+
instruction: `Commit hash mismatch: reported ${commitHash} but HEAD is ${fullHead ?? "unknown"}. Verify the commit succeeded and report the correct hash.`
|
|
7176
7233
|
};
|
|
7177
7234
|
}
|
|
7178
|
-
|
|
7179
|
-
|
|
7235
|
+
const normalizedHash = fullHead;
|
|
7236
|
+
if (previousHead && normalizedHash === previousHead) {
|
|
7237
|
+
return { action: "retry", instruction: `No new commit detected: HEAD (${normalizedHash}) has not changed. Create a commit first, then report the new hash.` };
|
|
7180
7238
|
}
|
|
7181
|
-
const completedTicket = ctx.state.ticket ? { id: ctx.state.ticket.id, title: ctx.state.ticket.title, commitHash, risk: ctx.state.ticket.risk } : void 0;
|
|
7239
|
+
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;
|
|
7182
7240
|
ctx.writeState({
|
|
7183
7241
|
finalizeCheckpoint: "committed",
|
|
7184
7242
|
completedTickets: completedTicket ? [...ctx.state.completedTickets, completedTicket] : ctx.state.completedTickets,
|
|
7185
7243
|
ticket: void 0,
|
|
7186
7244
|
git: {
|
|
7187
7245
|
...ctx.state.git,
|
|
7188
|
-
mergeBase:
|
|
7189
|
-
expectedHead:
|
|
7246
|
+
mergeBase: normalizedHash,
|
|
7247
|
+
expectedHead: normalizedHash
|
|
7190
7248
|
}
|
|
7191
7249
|
});
|
|
7192
|
-
ctx.appendEvent("commit", { commitHash, ticketId: completedTicket?.id });
|
|
7250
|
+
ctx.appendEvent("commit", { commitHash: normalizedHash, ticketId: completedTicket?.id });
|
|
7193
7251
|
return { action: "advance" };
|
|
7194
7252
|
}
|
|
7195
7253
|
};
|
|
@@ -7323,7 +7381,7 @@ var init_complete = __esm({
|
|
|
7323
7381
|
"You are in autonomous mode \u2014 continue working until all tickets are done or the session limit is reached."
|
|
7324
7382
|
],
|
|
7325
7383
|
transitionedFrom: "COMPLETE",
|
|
7326
|
-
contextAdvice:
|
|
7384
|
+
contextAdvice: "ok"
|
|
7327
7385
|
}
|
|
7328
7386
|
};
|
|
7329
7387
|
}
|
|
@@ -8534,11 +8592,15 @@ async function handleCancel(root, args) {
|
|
|
8534
8592
|
}
|
|
8535
8593
|
const info = findSessionById(root, args.sessionId);
|
|
8536
8594
|
if (!info) return guideError(new Error(`Session ${args.sessionId} not found`));
|
|
8537
|
-
if (info.state.
|
|
8595
|
+
if (info.state.state === "SESSION_END" || info.state.status === "completed") {
|
|
8596
|
+
return guideError(new Error("Session already ended."));
|
|
8597
|
+
}
|
|
8598
|
+
const CANCELLABLE_STATES = /* @__PURE__ */ new Set(["PICK_TICKET", "COMPLETE", "HANDOVER"]);
|
|
8599
|
+
if (info.state.recipe === "coding" && !CANCELLABLE_STATES.has(info.state.state)) {
|
|
8538
8600
|
const sessionMode = info.state.mode ?? "auto";
|
|
8539
8601
|
const modeGuidance = sessionMode === "plan" ? "Plan mode sessions end after plan review approval \u2014 continue to that step." : sessionMode === "review" ? "Review mode sessions end after code review approval \u2014 continue to that step." : sessionMode === "guided" ? "Guided mode sessions end after ticket completion \u2014 continue to FINALIZE." : "Complete the current ticket and write a handover to end the session.";
|
|
8540
8602
|
return guideError(new Error(
|
|
8541
|
-
`Cannot cancel a coding session. ${modeGuidance}`
|
|
8603
|
+
`Cannot cancel a coding session from ${info.state.state}. ${modeGuidance}`
|
|
8542
8604
|
));
|
|
8543
8605
|
}
|
|
8544
8606
|
await recoverPendingMutation(info.dir, info.state, root);
|
|
@@ -10028,7 +10090,7 @@ var init_mcp = __esm({
|
|
|
10028
10090
|
init_init();
|
|
10029
10091
|
ENV_VAR2 = "CLAUDESTORY_PROJECT_ROOT";
|
|
10030
10092
|
CONFIG_PATH2 = ".story/config.json";
|
|
10031
|
-
version = "0.1.
|
|
10093
|
+
version = "0.1.24";
|
|
10032
10094
|
main().catch((err) => {
|
|
10033
10095
|
process.stderr.write(`Fatal: ${err instanceof Error ? err.message : String(err)}
|
|
10034
10096
|
`);
|
|
@@ -13306,7 +13368,7 @@ async function runCli() {
|
|
|
13306
13368
|
registerConfigCommand: registerConfigCommand2,
|
|
13307
13369
|
registerSessionCommand: registerSessionCommand2
|
|
13308
13370
|
} = await Promise.resolve().then(() => (init_register(), register_exports));
|
|
13309
|
-
const version2 = "0.1.
|
|
13371
|
+
const version2 = "0.1.24";
|
|
13310
13372
|
class HandledError extends Error {
|
|
13311
13373
|
constructor() {
|
|
13312
13374
|
super("HANDLED_ERROR");
|
package/dist/mcp.js
CHANGED
|
@@ -5402,6 +5402,13 @@ async function gitStashPop(cwd, commitHash) {
|
|
|
5402
5402
|
}
|
|
5403
5403
|
return git(cwd, ["stash", "pop", match.ref], () => void 0);
|
|
5404
5404
|
}
|
|
5405
|
+
async function gitDiffTreeNames(cwd, commitHash) {
|
|
5406
|
+
return git(
|
|
5407
|
+
cwd,
|
|
5408
|
+
["diff-tree", "--name-only", "--no-commit-id", "-r", commitHash],
|
|
5409
|
+
(out) => out.split("\n").filter((l) => l.trim().length > 0)
|
|
5410
|
+
);
|
|
5411
|
+
}
|
|
5405
5412
|
var SAFE_REF = /^[0-9a-f]{4,40}$/i;
|
|
5406
5413
|
async function gitLogRange(cwd, from, to, limit = 20) {
|
|
5407
5414
|
if (from && !SAFE_REF.test(from)) {
|
|
@@ -5935,8 +5942,10 @@ var PlanReviewStage = class {
|
|
|
5935
5942
|
const isRevise = verdict === "revise" || verdict === "request_changes";
|
|
5936
5943
|
const isReject = verdict === "reject";
|
|
5937
5944
|
let nextAction;
|
|
5938
|
-
if (isReject
|
|
5945
|
+
if (isReject) {
|
|
5939
5946
|
nextAction = "PLAN";
|
|
5947
|
+
} else if (isRevise) {
|
|
5948
|
+
nextAction = "PLAN_REVIEW";
|
|
5940
5949
|
} else if (verdict === "approve" || !hasCriticalOrMajor && roundNum >= minRounds) {
|
|
5941
5950
|
nextAction = "IMPLEMENT";
|
|
5942
5951
|
} else if (roundNum >= 5) {
|
|
@@ -5958,7 +5967,21 @@ var PlanReviewStage = class {
|
|
|
5958
5967
|
return {
|
|
5959
5968
|
action: "back",
|
|
5960
5969
|
target: "PLAN",
|
|
5961
|
-
reason:
|
|
5970
|
+
reason: "reject"
|
|
5971
|
+
};
|
|
5972
|
+
}
|
|
5973
|
+
if (isRevise) {
|
|
5974
|
+
const findingSummary = findings.length > 0 ? findings.slice(0, 5).map((f) => `- [${f.severity}] ${f.description}`).join("\n") : "Address the reviewer's concerns.";
|
|
5975
|
+
return {
|
|
5976
|
+
action: "retry",
|
|
5977
|
+
instruction: [
|
|
5978
|
+
`# Plan Review \u2014 Round ${roundNum} requested changes`,
|
|
5979
|
+
"",
|
|
5980
|
+
'Update the plan to address these findings, then call me with completedAction: "plan_review_round" and the new review verdict.',
|
|
5981
|
+
"",
|
|
5982
|
+
findingSummary
|
|
5983
|
+
].join("\n"),
|
|
5984
|
+
reminders: ["Update the plan file, then re-review. Do NOT rewrite from scratch."]
|
|
5962
5985
|
};
|
|
5963
5986
|
}
|
|
5964
5987
|
if (nextAction === "IMPLEMENT") {
|
|
@@ -6168,7 +6191,7 @@ function exhaustionAction(ctx) {
|
|
|
6168
6191
|
return {
|
|
6169
6192
|
action: "back",
|
|
6170
6193
|
target: "PLAN",
|
|
6171
|
-
reason: "
|
|
6194
|
+
reason: "TDD exhausted: could not verify new failing tests after 3 attempts. Revise the plan to make the test expectations clearer or simpler."
|
|
6172
6195
|
};
|
|
6173
6196
|
}
|
|
6174
6197
|
|
|
@@ -6207,6 +6230,13 @@ var TestStage = class {
|
|
|
6207
6230
|
const retryCount = ctx.state.testRetryCount ?? 0;
|
|
6208
6231
|
const exitCodeMatch = notes.match(/exit\s*(?:code[:\s]*)?\s*(\d+)/i);
|
|
6209
6232
|
if (!exitCodeMatch) {
|
|
6233
|
+
const nextRetry = retryCount + 1;
|
|
6234
|
+
if (nextRetry >= MAX_TEST_RETRIES) {
|
|
6235
|
+
ctx.writeState({ testRetryCount: 0 });
|
|
6236
|
+
ctx.appendEvent("tests_parse_exhausted", { retryCount: nextRetry });
|
|
6237
|
+
return { action: "advance" };
|
|
6238
|
+
}
|
|
6239
|
+
ctx.writeState({ testRetryCount: nextRetry });
|
|
6210
6240
|
return { action: "retry", instruction: 'Could not parse exit code from notes. Include "exit code: 0" (or non-zero) in your notes.' };
|
|
6211
6241
|
}
|
|
6212
6242
|
const exitCode = parseInt(exitCodeMatch[1], 10);
|
|
@@ -6614,6 +6644,22 @@ var FinalizeStage = class {
|
|
|
6614
6644
|
async handleStage(ctx, report) {
|
|
6615
6645
|
const stagedResult = await gitDiffCachedNames(ctx.root);
|
|
6616
6646
|
if (!stagedResult.ok || stagedResult.data.length === 0) {
|
|
6647
|
+
const headResult = await gitHead(ctx.root);
|
|
6648
|
+
const previousHead = ctx.state.git.expectedHead ?? ctx.state.git.initHead;
|
|
6649
|
+
if (headResult.ok && previousHead && headResult.data.hash !== previousHead) {
|
|
6650
|
+
const ticketId2 = ctx.state.ticket?.id;
|
|
6651
|
+
if (ticketId2) {
|
|
6652
|
+
const treeResult = await gitDiffTreeNames(ctx.root, headResult.data.hash);
|
|
6653
|
+
const ticketPath = `.story/tickets/${ticketId2}.json`;
|
|
6654
|
+
if (treeResult.ok && !treeResult.data.includes(ticketPath)) {
|
|
6655
|
+
return {
|
|
6656
|
+
action: "retry",
|
|
6657
|
+
instruction: `Commit detected (${headResult.data.hash.slice(0, 7)}) but ticket file ${ticketPath} is not in the commit. Amend the commit to include it: \`git add ${ticketPath} && git commit --amend --no-edit\`, then report completedAction: "commit_done" with the new hash.`
|
|
6658
|
+
};
|
|
6659
|
+
}
|
|
6660
|
+
}
|
|
6661
|
+
return this.handleCommit(ctx, { ...report, commitHash: headResult.data.hash });
|
|
6662
|
+
}
|
|
6617
6663
|
return { action: "retry", instruction: 'No files are staged. Stage your changes and call me again with completedAction: "files_staged".' };
|
|
6618
6664
|
}
|
|
6619
6665
|
const baselineUntracked = ctx.state.git.baseline?.untrackedPaths ?? [];
|
|
@@ -6631,6 +6677,16 @@ var FinalizeStage = class {
|
|
|
6631
6677
|
}
|
|
6632
6678
|
}
|
|
6633
6679
|
}
|
|
6680
|
+
const ticketId = ctx.state.ticket?.id;
|
|
6681
|
+
if (ticketId) {
|
|
6682
|
+
const ticketPath = `.story/tickets/${ticketId}.json`;
|
|
6683
|
+
if (!stagedResult.data.includes(ticketPath)) {
|
|
6684
|
+
return {
|
|
6685
|
+
action: "retry",
|
|
6686
|
+
instruction: `Ticket file ${ticketPath} is not staged. Run \`git add ${ticketPath}\` and call me again with completedAction: "files_staged".`
|
|
6687
|
+
};
|
|
6688
|
+
}
|
|
6689
|
+
}
|
|
6634
6690
|
ctx.writeState({
|
|
6635
6691
|
finalizeCheckpoint: overlapOverridden ? "staged_override" : "staged"
|
|
6636
6692
|
});
|
|
@@ -6691,27 +6747,29 @@ var FinalizeStage = class {
|
|
|
6691
6747
|
}
|
|
6692
6748
|
const headResult = await gitHead(ctx.root);
|
|
6693
6749
|
const previousHead = ctx.state.git.expectedHead ?? ctx.state.git.initHead;
|
|
6694
|
-
|
|
6750
|
+
const fullHead = headResult.ok ? headResult.data.hash : null;
|
|
6751
|
+
if (!fullHead || !fullHead.startsWith(commitHash) && commitHash !== fullHead) {
|
|
6695
6752
|
return {
|
|
6696
6753
|
action: "retry",
|
|
6697
|
-
instruction: `Commit hash mismatch: reported ${commitHash} but HEAD is ${
|
|
6754
|
+
instruction: `Commit hash mismatch: reported ${commitHash} but HEAD is ${fullHead ?? "unknown"}. Verify the commit succeeded and report the correct hash.`
|
|
6698
6755
|
};
|
|
6699
6756
|
}
|
|
6700
|
-
|
|
6701
|
-
|
|
6757
|
+
const normalizedHash = fullHead;
|
|
6758
|
+
if (previousHead && normalizedHash === previousHead) {
|
|
6759
|
+
return { action: "retry", instruction: `No new commit detected: HEAD (${normalizedHash}) has not changed. Create a commit first, then report the new hash.` };
|
|
6702
6760
|
}
|
|
6703
|
-
const completedTicket = ctx.state.ticket ? { id: ctx.state.ticket.id, title: ctx.state.ticket.title, commitHash, risk: ctx.state.ticket.risk } : void 0;
|
|
6761
|
+
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;
|
|
6704
6762
|
ctx.writeState({
|
|
6705
6763
|
finalizeCheckpoint: "committed",
|
|
6706
6764
|
completedTickets: completedTicket ? [...ctx.state.completedTickets, completedTicket] : ctx.state.completedTickets,
|
|
6707
6765
|
ticket: void 0,
|
|
6708
6766
|
git: {
|
|
6709
6767
|
...ctx.state.git,
|
|
6710
|
-
mergeBase:
|
|
6711
|
-
expectedHead:
|
|
6768
|
+
mergeBase: normalizedHash,
|
|
6769
|
+
expectedHead: normalizedHash
|
|
6712
6770
|
}
|
|
6713
6771
|
});
|
|
6714
|
-
ctx.appendEvent("commit", { commitHash, ticketId: completedTicket?.id });
|
|
6772
|
+
ctx.appendEvent("commit", { commitHash: normalizedHash, ticketId: completedTicket?.id });
|
|
6715
6773
|
return { action: "advance" };
|
|
6716
6774
|
}
|
|
6717
6775
|
};
|
|
@@ -6837,7 +6895,7 @@ var CompleteStage = class {
|
|
|
6837
6895
|
"You are in autonomous mode \u2014 continue working until all tickets are done or the session limit is reached."
|
|
6838
6896
|
],
|
|
6839
6897
|
transitionedFrom: "COMPLETE",
|
|
6840
|
-
contextAdvice:
|
|
6898
|
+
contextAdvice: "ok"
|
|
6841
6899
|
}
|
|
6842
6900
|
};
|
|
6843
6901
|
}
|
|
@@ -8024,11 +8082,15 @@ async function handleCancel(root, args) {
|
|
|
8024
8082
|
}
|
|
8025
8083
|
const info = findSessionById(root, args.sessionId);
|
|
8026
8084
|
if (!info) return guideError(new Error(`Session ${args.sessionId} not found`));
|
|
8027
|
-
if (info.state.
|
|
8085
|
+
if (info.state.state === "SESSION_END" || info.state.status === "completed") {
|
|
8086
|
+
return guideError(new Error("Session already ended."));
|
|
8087
|
+
}
|
|
8088
|
+
const CANCELLABLE_STATES = /* @__PURE__ */ new Set(["PICK_TICKET", "COMPLETE", "HANDOVER"]);
|
|
8089
|
+
if (info.state.recipe === "coding" && !CANCELLABLE_STATES.has(info.state.state)) {
|
|
8028
8090
|
const sessionMode = info.state.mode ?? "auto";
|
|
8029
8091
|
const modeGuidance = sessionMode === "plan" ? "Plan mode sessions end after plan review approval \u2014 continue to that step." : sessionMode === "review" ? "Review mode sessions end after code review approval \u2014 continue to that step." : sessionMode === "guided" ? "Guided mode sessions end after ticket completion \u2014 continue to FINALIZE." : "Complete the current ticket and write a handover to end the session.";
|
|
8030
8092
|
return guideError(new Error(
|
|
8031
|
-
`Cannot cancel a coding session. ${modeGuidance}`
|
|
8093
|
+
`Cannot cancel a coding session from ${info.state.state}. ${modeGuidance}`
|
|
8032
8094
|
));
|
|
8033
8095
|
}
|
|
8034
8096
|
await recoverPendingMutation(info.dir, info.state, root);
|
|
@@ -9193,7 +9255,7 @@ async function ensureGitignoreEntries(gitignorePath, entries) {
|
|
|
9193
9255
|
// src/mcp/index.ts
|
|
9194
9256
|
var ENV_VAR2 = "CLAUDESTORY_PROJECT_ROOT";
|
|
9195
9257
|
var CONFIG_PATH2 = ".story/config.json";
|
|
9196
|
-
var version = "0.1.
|
|
9258
|
+
var version = "0.1.24";
|
|
9197
9259
|
function tryDiscoverRoot() {
|
|
9198
9260
|
const envRoot = process.env[ENV_VAR2];
|
|
9199
9261
|
if (envRoot) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@anthropologies/claudestory",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.24",
|
|
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": [
|