@anthropologies/claudestory 0.1.23 → 0.1.25
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 +80 -17
- package/dist/mcp.js +79 -16
- 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) {
|
|
@@ -6383,7 +6392,7 @@ var init_plan_review = __esm({
|
|
|
6383
6392
|
}
|
|
6384
6393
|
const reviewsForWrite = isReject ? { ...ctx.state.reviews, plan: [] } : { ...ctx.state.reviews, plan: planReviews };
|
|
6385
6394
|
ctx.writeState({
|
|
6386
|
-
reviews:
|
|
6395
|
+
reviews: reviewsForWrite
|
|
6387
6396
|
});
|
|
6388
6397
|
ctx.appendEvent("plan_review", {
|
|
6389
6398
|
round: roundNum,
|
|
@@ -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,23 @@ 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
|
+
ctx.writeState({ finalizeCheckpoint: "precommit_passed" });
|
|
7140
|
+
return this.handleCommit(ctx, { ...report, commitHash: headResult.data.hash });
|
|
7141
|
+
}
|
|
7095
7142
|
return { action: "retry", instruction: 'No files are staged. Stage your changes and call me again with completedAction: "files_staged".' };
|
|
7096
7143
|
}
|
|
7097
7144
|
const baselineUntracked = ctx.state.git.baseline?.untrackedPaths ?? [];
|
|
@@ -7109,6 +7156,16 @@ var init_finalize = __esm({
|
|
|
7109
7156
|
}
|
|
7110
7157
|
}
|
|
7111
7158
|
}
|
|
7159
|
+
const ticketId = ctx.state.ticket?.id;
|
|
7160
|
+
if (ticketId) {
|
|
7161
|
+
const ticketPath = `.story/tickets/${ticketId}.json`;
|
|
7162
|
+
if (!stagedResult.data.includes(ticketPath)) {
|
|
7163
|
+
return {
|
|
7164
|
+
action: "retry",
|
|
7165
|
+
instruction: `Ticket file ${ticketPath} is not staged. Run \`git add ${ticketPath}\` and call me again with completedAction: "files_staged".`
|
|
7166
|
+
};
|
|
7167
|
+
}
|
|
7168
|
+
}
|
|
7112
7169
|
ctx.writeState({
|
|
7113
7170
|
finalizeCheckpoint: overlapOverridden ? "staged_override" : "staged"
|
|
7114
7171
|
});
|
|
@@ -7169,27 +7226,29 @@ var init_finalize = __esm({
|
|
|
7169
7226
|
}
|
|
7170
7227
|
const headResult = await gitHead(ctx.root);
|
|
7171
7228
|
const previousHead = ctx.state.git.expectedHead ?? ctx.state.git.initHead;
|
|
7172
|
-
|
|
7229
|
+
const fullHead = headResult.ok ? headResult.data.hash : null;
|
|
7230
|
+
if (!fullHead || !fullHead.startsWith(commitHash) && commitHash !== fullHead) {
|
|
7173
7231
|
return {
|
|
7174
7232
|
action: "retry",
|
|
7175
|
-
instruction: `Commit hash mismatch: reported ${commitHash} but HEAD is ${
|
|
7233
|
+
instruction: `Commit hash mismatch: reported ${commitHash} but HEAD is ${fullHead ?? "unknown"}. Verify the commit succeeded and report the correct hash.`
|
|
7176
7234
|
};
|
|
7177
7235
|
}
|
|
7178
|
-
|
|
7179
|
-
|
|
7236
|
+
const normalizedHash = fullHead;
|
|
7237
|
+
if (previousHead && normalizedHash === previousHead) {
|
|
7238
|
+
return { action: "retry", instruction: `No new commit detected: HEAD (${normalizedHash}) has not changed. Create a commit first, then report the new hash.` };
|
|
7180
7239
|
}
|
|
7181
|
-
const completedTicket = ctx.state.ticket ? { id: ctx.state.ticket.id, title: ctx.state.ticket.title, commitHash, risk: ctx.state.ticket.risk } : void 0;
|
|
7240
|
+
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
7241
|
ctx.writeState({
|
|
7183
7242
|
finalizeCheckpoint: "committed",
|
|
7184
7243
|
completedTickets: completedTicket ? [...ctx.state.completedTickets, completedTicket] : ctx.state.completedTickets,
|
|
7185
7244
|
ticket: void 0,
|
|
7186
7245
|
git: {
|
|
7187
7246
|
...ctx.state.git,
|
|
7188
|
-
mergeBase:
|
|
7189
|
-
expectedHead:
|
|
7247
|
+
mergeBase: normalizedHash,
|
|
7248
|
+
expectedHead: normalizedHash
|
|
7190
7249
|
}
|
|
7191
7250
|
});
|
|
7192
|
-
ctx.appendEvent("commit", { commitHash, ticketId: completedTicket?.id });
|
|
7251
|
+
ctx.appendEvent("commit", { commitHash: normalizedHash, ticketId: completedTicket?.id });
|
|
7193
7252
|
return { action: "advance" };
|
|
7194
7253
|
}
|
|
7195
7254
|
};
|
|
@@ -7323,7 +7382,7 @@ var init_complete = __esm({
|
|
|
7323
7382
|
"You are in autonomous mode \u2014 continue working until all tickets are done or the session limit is reached."
|
|
7324
7383
|
],
|
|
7325
7384
|
transitionedFrom: "COMPLETE",
|
|
7326
|
-
contextAdvice:
|
|
7385
|
+
contextAdvice: "ok"
|
|
7327
7386
|
}
|
|
7328
7387
|
};
|
|
7329
7388
|
}
|
|
@@ -8534,11 +8593,15 @@ async function handleCancel(root, args) {
|
|
|
8534
8593
|
}
|
|
8535
8594
|
const info = findSessionById(root, args.sessionId);
|
|
8536
8595
|
if (!info) return guideError(new Error(`Session ${args.sessionId} not found`));
|
|
8537
|
-
if (info.state.
|
|
8596
|
+
if (info.state.state === "SESSION_END" || info.state.status === "completed") {
|
|
8597
|
+
return guideError(new Error("Session already ended."));
|
|
8598
|
+
}
|
|
8599
|
+
const CANCELLABLE_STATES = /* @__PURE__ */ new Set(["PICK_TICKET", "COMPLETE", "HANDOVER"]);
|
|
8600
|
+
if (info.state.recipe === "coding" && !CANCELLABLE_STATES.has(info.state.state)) {
|
|
8538
8601
|
const sessionMode = info.state.mode ?? "auto";
|
|
8539
8602
|
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
8603
|
return guideError(new Error(
|
|
8541
|
-
`Cannot cancel a coding session. ${modeGuidance}`
|
|
8604
|
+
`Cannot cancel a coding session from ${info.state.state}. ${modeGuidance}`
|
|
8542
8605
|
));
|
|
8543
8606
|
}
|
|
8544
8607
|
await recoverPendingMutation(info.dir, info.state, root);
|
|
@@ -10028,7 +10091,7 @@ var init_mcp = __esm({
|
|
|
10028
10091
|
init_init();
|
|
10029
10092
|
ENV_VAR2 = "CLAUDESTORY_PROJECT_ROOT";
|
|
10030
10093
|
CONFIG_PATH2 = ".story/config.json";
|
|
10031
|
-
version = "0.1.
|
|
10094
|
+
version = "0.1.25";
|
|
10032
10095
|
main().catch((err) => {
|
|
10033
10096
|
process.stderr.write(`Fatal: ${err instanceof Error ? err.message : String(err)}
|
|
10034
10097
|
`);
|
|
@@ -13306,7 +13369,7 @@ async function runCli() {
|
|
|
13306
13369
|
registerConfigCommand: registerConfigCommand2,
|
|
13307
13370
|
registerSessionCommand: registerSessionCommand2
|
|
13308
13371
|
} = await Promise.resolve().then(() => (init_register(), register_exports));
|
|
13309
|
-
const version2 = "0.1.
|
|
13372
|
+
const version2 = "0.1.25";
|
|
13310
13373
|
class HandledError extends Error {
|
|
13311
13374
|
constructor() {
|
|
13312
13375
|
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) {
|
|
@@ -5946,7 +5955,7 @@ var PlanReviewStage = class {
|
|
|
5946
5955
|
}
|
|
5947
5956
|
const reviewsForWrite = isReject ? { ...ctx.state.reviews, plan: [] } : { ...ctx.state.reviews, plan: planReviews };
|
|
5948
5957
|
ctx.writeState({
|
|
5949
|
-
reviews:
|
|
5958
|
+
reviews: reviewsForWrite
|
|
5950
5959
|
});
|
|
5951
5960
|
ctx.appendEvent("plan_review", {
|
|
5952
5961
|
round: roundNum,
|
|
@@ -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,23 @@ 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
|
+
ctx.writeState({ finalizeCheckpoint: "precommit_passed" });
|
|
6662
|
+
return this.handleCommit(ctx, { ...report, commitHash: headResult.data.hash });
|
|
6663
|
+
}
|
|
6617
6664
|
return { action: "retry", instruction: 'No files are staged. Stage your changes and call me again with completedAction: "files_staged".' };
|
|
6618
6665
|
}
|
|
6619
6666
|
const baselineUntracked = ctx.state.git.baseline?.untrackedPaths ?? [];
|
|
@@ -6631,6 +6678,16 @@ var FinalizeStage = class {
|
|
|
6631
6678
|
}
|
|
6632
6679
|
}
|
|
6633
6680
|
}
|
|
6681
|
+
const ticketId = ctx.state.ticket?.id;
|
|
6682
|
+
if (ticketId) {
|
|
6683
|
+
const ticketPath = `.story/tickets/${ticketId}.json`;
|
|
6684
|
+
if (!stagedResult.data.includes(ticketPath)) {
|
|
6685
|
+
return {
|
|
6686
|
+
action: "retry",
|
|
6687
|
+
instruction: `Ticket file ${ticketPath} is not staged. Run \`git add ${ticketPath}\` and call me again with completedAction: "files_staged".`
|
|
6688
|
+
};
|
|
6689
|
+
}
|
|
6690
|
+
}
|
|
6634
6691
|
ctx.writeState({
|
|
6635
6692
|
finalizeCheckpoint: overlapOverridden ? "staged_override" : "staged"
|
|
6636
6693
|
});
|
|
@@ -6691,27 +6748,29 @@ var FinalizeStage = class {
|
|
|
6691
6748
|
}
|
|
6692
6749
|
const headResult = await gitHead(ctx.root);
|
|
6693
6750
|
const previousHead = ctx.state.git.expectedHead ?? ctx.state.git.initHead;
|
|
6694
|
-
|
|
6751
|
+
const fullHead = headResult.ok ? headResult.data.hash : null;
|
|
6752
|
+
if (!fullHead || !fullHead.startsWith(commitHash) && commitHash !== fullHead) {
|
|
6695
6753
|
return {
|
|
6696
6754
|
action: "retry",
|
|
6697
|
-
instruction: `Commit hash mismatch: reported ${commitHash} but HEAD is ${
|
|
6755
|
+
instruction: `Commit hash mismatch: reported ${commitHash} but HEAD is ${fullHead ?? "unknown"}. Verify the commit succeeded and report the correct hash.`
|
|
6698
6756
|
};
|
|
6699
6757
|
}
|
|
6700
|
-
|
|
6701
|
-
|
|
6758
|
+
const normalizedHash = fullHead;
|
|
6759
|
+
if (previousHead && normalizedHash === previousHead) {
|
|
6760
|
+
return { action: "retry", instruction: `No new commit detected: HEAD (${normalizedHash}) has not changed. Create a commit first, then report the new hash.` };
|
|
6702
6761
|
}
|
|
6703
|
-
const completedTicket = ctx.state.ticket ? { id: ctx.state.ticket.id, title: ctx.state.ticket.title, commitHash, risk: ctx.state.ticket.risk } : void 0;
|
|
6762
|
+
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
6763
|
ctx.writeState({
|
|
6705
6764
|
finalizeCheckpoint: "committed",
|
|
6706
6765
|
completedTickets: completedTicket ? [...ctx.state.completedTickets, completedTicket] : ctx.state.completedTickets,
|
|
6707
6766
|
ticket: void 0,
|
|
6708
6767
|
git: {
|
|
6709
6768
|
...ctx.state.git,
|
|
6710
|
-
mergeBase:
|
|
6711
|
-
expectedHead:
|
|
6769
|
+
mergeBase: normalizedHash,
|
|
6770
|
+
expectedHead: normalizedHash
|
|
6712
6771
|
}
|
|
6713
6772
|
});
|
|
6714
|
-
ctx.appendEvent("commit", { commitHash, ticketId: completedTicket?.id });
|
|
6773
|
+
ctx.appendEvent("commit", { commitHash: normalizedHash, ticketId: completedTicket?.id });
|
|
6715
6774
|
return { action: "advance" };
|
|
6716
6775
|
}
|
|
6717
6776
|
};
|
|
@@ -6837,7 +6896,7 @@ var CompleteStage = class {
|
|
|
6837
6896
|
"You are in autonomous mode \u2014 continue working until all tickets are done or the session limit is reached."
|
|
6838
6897
|
],
|
|
6839
6898
|
transitionedFrom: "COMPLETE",
|
|
6840
|
-
contextAdvice:
|
|
6899
|
+
contextAdvice: "ok"
|
|
6841
6900
|
}
|
|
6842
6901
|
};
|
|
6843
6902
|
}
|
|
@@ -8024,11 +8083,15 @@ async function handleCancel(root, args) {
|
|
|
8024
8083
|
}
|
|
8025
8084
|
const info = findSessionById(root, args.sessionId);
|
|
8026
8085
|
if (!info) return guideError(new Error(`Session ${args.sessionId} not found`));
|
|
8027
|
-
if (info.state.
|
|
8086
|
+
if (info.state.state === "SESSION_END" || info.state.status === "completed") {
|
|
8087
|
+
return guideError(new Error("Session already ended."));
|
|
8088
|
+
}
|
|
8089
|
+
const CANCELLABLE_STATES = /* @__PURE__ */ new Set(["PICK_TICKET", "COMPLETE", "HANDOVER"]);
|
|
8090
|
+
if (info.state.recipe === "coding" && !CANCELLABLE_STATES.has(info.state.state)) {
|
|
8028
8091
|
const sessionMode = info.state.mode ?? "auto";
|
|
8029
8092
|
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
8093
|
return guideError(new Error(
|
|
8031
|
-
`Cannot cancel a coding session. ${modeGuidance}`
|
|
8094
|
+
`Cannot cancel a coding session from ${info.state.state}. ${modeGuidance}`
|
|
8032
8095
|
));
|
|
8033
8096
|
}
|
|
8034
8097
|
await recoverPendingMutation(info.dir, info.state, root);
|
|
@@ -9193,7 +9256,7 @@ async function ensureGitignoreEntries(gitignorePath, entries) {
|
|
|
9193
9256
|
// src/mcp/index.ts
|
|
9194
9257
|
var ENV_VAR2 = "CLAUDESTORY_PROJECT_ROOT";
|
|
9195
9258
|
var CONFIG_PATH2 = ".story/config.json";
|
|
9196
|
-
var version = "0.1.
|
|
9259
|
+
var version = "0.1.25";
|
|
9197
9260
|
function tryDiscoverRoot() {
|
|
9198
9261
|
const envRoot = process.env[ENV_VAR2];
|
|
9199
9262
|
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.25",
|
|
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": [
|