@programinglive/dev-workflow-mcp-server 1.1.16 → 1.2.0
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/CHANGELOG.md +16 -0
- package/README.md +3 -1
- package/git-helpers.js +25 -0
- package/index.js +8 -4
- package/package.json +1 -1
- package/tests/handlers.test.js +217 -7
- package/tools/handlers.js +13 -2
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,22 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
|
4
4
|
|
|
5
|
+
## [1.2.0](https://github.com/programinglive/dev-workflow-mcp-server/compare/v1.1.18...v1.2.0) (2025-11-03)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### 🐛 Bug Fixes
|
|
9
|
+
|
|
10
|
+
* reload workflow state from disk on each request to prevent stale state ([96bf50d](https://github.com/programinglive/dev-workflow-mcp-server/commit/96bf50de532713c2a83a3774d8e0dc05870eb24d))
|
|
11
|
+
|
|
12
|
+
### [1.1.18](https://github.com/programinglive/dev-workflow-mcp-server/compare/v1.1.17...v1.1.18) (2025-11-03)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### ✨ Features
|
|
16
|
+
|
|
17
|
+
* auto-detect primary branch for commit_and_push ([a68d38b](https://github.com/programinglive/dev-workflow-mcp-server/commit/a68d38ba547e6007bd2c0cfe5d231ebf417a2010))
|
|
18
|
+
|
|
19
|
+
### [1.1.17](https://github.com/programinglive/dev-workflow-mcp-server/compare/v1.1.16...v1.1.17) (2025-10-31)
|
|
20
|
+
|
|
5
21
|
### [1.1.16](https://github.com/programinglive/dev-workflow-mcp-server/compare/v1.1.15...v1.1.16) (2025-10-31)
|
|
6
22
|
|
|
7
23
|
|
package/README.md
CHANGED
|
@@ -378,9 +378,11 @@ Check if all workflow steps are completed and you're ready to commit & push.
|
|
|
378
378
|
### `commit_and_push`
|
|
379
379
|
Automatically run `git add`, `git commit`, and `git push` after the ready check passes.
|
|
380
380
|
|
|
381
|
+
**Auto-detection of primary branch:** If no `branch` is specified, the tool automatically detects your project's primary branch by checking for `origin/main` first, then falling back to `origin/master`. This eliminates the need to specify the branch parameter for most projects.
|
|
382
|
+
|
|
381
383
|
**Parameters:**
|
|
382
384
|
- `commitMessage` (string, required): Conventional commit message to use
|
|
383
|
-
- `branch` (string, optional): Target branch to push
|
|
385
|
+
- `branch` (string, optional): Target branch to push. If omitted, auto-detects primary branch (main or master)
|
|
384
386
|
|
|
385
387
|
### `perform_release`
|
|
386
388
|
Record the release after you've committed and pushed. Required before you can complete the task.
|
package/git-helpers.js
CHANGED
|
@@ -150,3 +150,28 @@ export async function getCurrentBranch() {
|
|
|
150
150
|
return "";
|
|
151
151
|
}
|
|
152
152
|
}
|
|
153
|
+
|
|
154
|
+
export async function getPrimaryBranch() {
|
|
155
|
+
try {
|
|
156
|
+
// Check if 'main' exists on origin
|
|
157
|
+
const { stdout: mainCheck } = await exec("git rev-parse --verify origin/main");
|
|
158
|
+
if (mainCheck.trim()) {
|
|
159
|
+
return "main";
|
|
160
|
+
}
|
|
161
|
+
} catch {
|
|
162
|
+
// main doesn't exist, fall through to master check
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
try {
|
|
166
|
+
// Check if 'master' exists on origin
|
|
167
|
+
const { stdout: masterCheck } = await exec("git rev-parse --verify origin/master");
|
|
168
|
+
if (masterCheck.trim()) {
|
|
169
|
+
return "master";
|
|
170
|
+
}
|
|
171
|
+
} catch {
|
|
172
|
+
// master doesn't exist either
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Fallback to current branch if neither main nor master exist
|
|
176
|
+
return await getCurrentBranch();
|
|
177
|
+
}
|
package/index.js
CHANGED
|
@@ -56,8 +56,12 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
|
56
56
|
}));
|
|
57
57
|
|
|
58
58
|
// Handle tool calls
|
|
59
|
-
server.setRequestHandler(CallToolRequestSchema, (request) =>
|
|
60
|
-
|
|
59
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
60
|
+
// Reload state from disk before each request to ensure consistency
|
|
61
|
+
if (workflowState) {
|
|
62
|
+
await workflowState.load();
|
|
63
|
+
}
|
|
64
|
+
return handleToolCall({
|
|
61
65
|
request,
|
|
62
66
|
normalizeRequestArgs,
|
|
63
67
|
workflowState,
|
|
@@ -72,8 +76,8 @@ server.setRequestHandler(CallToolRequestSchema, (request) =>
|
|
|
72
76
|
workingTreeSummary,
|
|
73
77
|
},
|
|
74
78
|
utils: { shellEscape, determineReleaseTypeFromCommit, createCommitMessageParts },
|
|
75
|
-
})
|
|
76
|
-
);
|
|
79
|
+
});
|
|
80
|
+
});
|
|
77
81
|
|
|
78
82
|
// Helper function
|
|
79
83
|
export function getNextStep(status) {
|
package/package.json
CHANGED
package/tests/handlers.test.js
CHANGED
|
@@ -62,6 +62,7 @@ test("commit_and_push commits changes and pushes", async () => {
|
|
|
62
62
|
hasTestChanges: async () => true,
|
|
63
63
|
getStagedChanges: async () => [{ status: "M", path: "src/index.js" }],
|
|
64
64
|
getCurrentBranch: async () => "main",
|
|
65
|
+
getPrimaryBranch: async () => "main",
|
|
65
66
|
getLastCommitMessage: async () => "",
|
|
66
67
|
workingTreeSummary: () => ({ hasChanges: false, lines: [] }),
|
|
67
68
|
};
|
|
@@ -129,6 +130,7 @@ test("run_full_workflow iterates until commit/release complete with clean tree",
|
|
|
129
130
|
hasTestChanges: async () => true,
|
|
130
131
|
getStagedChanges: async () => [],
|
|
131
132
|
getCurrentBranch: async () => "main",
|
|
133
|
+
getPrimaryBranch: async () => "main",
|
|
132
134
|
getLastCommitMessage: async () => "chore: existing",
|
|
133
135
|
workingTreeSummary: () => ({ hasChanges: false, lines: [] }),
|
|
134
136
|
};
|
|
@@ -163,6 +165,172 @@ test("run_full_workflow iterates until commit/release complete with clean tree",
|
|
|
163
165
|
});
|
|
164
166
|
});
|
|
165
167
|
|
|
168
|
+
test("commit_and_push uses primary branch when no branch specified", async () => {
|
|
169
|
+
await withWorkflowState(async (workflowState) => {
|
|
170
|
+
workflowState.state.readyToCommit = true;
|
|
171
|
+
workflowState.state.readyCheckCompleted = true;
|
|
172
|
+
workflowState.state.testsSkipped = false;
|
|
173
|
+
workflowState.state.testsCreated = true;
|
|
174
|
+
workflowState.state.testsPassed = true;
|
|
175
|
+
workflowState.state.currentPhase = "commit";
|
|
176
|
+
await workflowState.save();
|
|
177
|
+
|
|
178
|
+
const commands = [];
|
|
179
|
+
const execStub = async (command) => {
|
|
180
|
+
commands.push(command);
|
|
181
|
+
return { stdout: "" };
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
const git = {
|
|
185
|
+
hasWorkingChanges: async () => true,
|
|
186
|
+
hasStagedChanges: async () => false,
|
|
187
|
+
hasTestChanges: async () => true,
|
|
188
|
+
getStagedChanges: async () => [{ status: "M", path: "src/index.js" }],
|
|
189
|
+
getCurrentBranch: async () => "feature/test",
|
|
190
|
+
getPrimaryBranch: async () => "main",
|
|
191
|
+
getLastCommitMessage: async () => "",
|
|
192
|
+
workingTreeSummary: () => ({ hasChanges: false, lines: [] }),
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
const response = await handleToolCall({
|
|
196
|
+
request: createRequest("commit_and_push", { commitMessage: "feat: test" }),
|
|
197
|
+
normalizeRequestArgs,
|
|
198
|
+
workflowState,
|
|
199
|
+
exec: execStub,
|
|
200
|
+
git,
|
|
201
|
+
utils,
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
const pushCommand = commands.find((command) => command.startsWith("git push"));
|
|
205
|
+
assert.ok(pushCommand, "git push should be executed");
|
|
206
|
+
assert.ok(
|
|
207
|
+
pushCommand.includes("main"),
|
|
208
|
+
"push command should use detected primary branch (main)"
|
|
209
|
+
);
|
|
210
|
+
assert.ok(
|
|
211
|
+
response.content[0].text.includes("Commit and push completed!"),
|
|
212
|
+
"response should confirm commit and push"
|
|
213
|
+
);
|
|
214
|
+
});
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
test("commit_and_push falls back to master when main not found", async () => {
|
|
218
|
+
await withWorkflowState(async (workflowState) => {
|
|
219
|
+
workflowState.state.readyToCommit = true;
|
|
220
|
+
workflowState.state.readyCheckCompleted = true;
|
|
221
|
+
workflowState.state.testsSkipped = false;
|
|
222
|
+
workflowState.state.testsCreated = true;
|
|
223
|
+
workflowState.state.testsPassed = true;
|
|
224
|
+
workflowState.state.currentPhase = "commit";
|
|
225
|
+
await workflowState.save();
|
|
226
|
+
|
|
227
|
+
const commands = [];
|
|
228
|
+
const execStub = async (command) => {
|
|
229
|
+
commands.push(command);
|
|
230
|
+
return { stdout: "" };
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
const git = {
|
|
234
|
+
hasWorkingChanges: async () => true,
|
|
235
|
+
hasStagedChanges: async () => false,
|
|
236
|
+
hasTestChanges: async () => true,
|
|
237
|
+
getStagedChanges: async () => [{ status: "M", path: "src/index.js" }],
|
|
238
|
+
getCurrentBranch: async () => "feature/test",
|
|
239
|
+
getPrimaryBranch: async () => "master",
|
|
240
|
+
getLastCommitMessage: async () => "",
|
|
241
|
+
workingTreeSummary: () => ({ hasChanges: false, lines: [] }),
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
const response = await handleToolCall({
|
|
245
|
+
request: createRequest("commit_and_push", { commitMessage: "feat: test" }),
|
|
246
|
+
normalizeRequestArgs,
|
|
247
|
+
workflowState,
|
|
248
|
+
exec: execStub,
|
|
249
|
+
git,
|
|
250
|
+
utils,
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
const pushCommand = commands.find((command) => command.startsWith("git push"));
|
|
254
|
+
assert.ok(pushCommand, "git push should be executed");
|
|
255
|
+
assert.ok(
|
|
256
|
+
pushCommand.includes("master"),
|
|
257
|
+
"push command should use detected primary branch (master)"
|
|
258
|
+
);
|
|
259
|
+
});
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
test("run_full_workflow uses provided branch for release push when commit is clean", async () => {
|
|
263
|
+
await withWorkflowState(async (workflowState) => {
|
|
264
|
+
workflowState.state.taskDescription = "Ship feature";
|
|
265
|
+
workflowState.state.taskType = "feature";
|
|
266
|
+
workflowState.state.currentPhase = "commit";
|
|
267
|
+
workflowState.state.bugFixed = true;
|
|
268
|
+
workflowState.state.testsCreated = true;
|
|
269
|
+
workflowState.state.testsPassed = true;
|
|
270
|
+
workflowState.state.documentationCreated = true;
|
|
271
|
+
workflowState.state.readyToCommit = true;
|
|
272
|
+
workflowState.state.readyCheckCompleted = true;
|
|
273
|
+
workflowState.state.commitAndPushCompleted = false;
|
|
274
|
+
workflowState.state.released = false;
|
|
275
|
+
workflowState.state.documentationType = "README";
|
|
276
|
+
workflowState.state.documentationSummary = "Docs";
|
|
277
|
+
workflowState.state.fixSummary = "Feature done";
|
|
278
|
+
await workflowState.save();
|
|
279
|
+
|
|
280
|
+
const commands = [];
|
|
281
|
+
const execStub = async (command) => {
|
|
282
|
+
commands.push(command);
|
|
283
|
+
if (command === "git status --porcelain") {
|
|
284
|
+
return { stdout: "" };
|
|
285
|
+
}
|
|
286
|
+
return { stdout: "" };
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
const git = {
|
|
290
|
+
hasWorkingChanges: async () => false,
|
|
291
|
+
hasStagedChanges: async () => false,
|
|
292
|
+
hasTestChanges: async () => true,
|
|
293
|
+
getStagedChanges: async () => [],
|
|
294
|
+
getCurrentBranch: async () => "feature/local",
|
|
295
|
+
getPrimaryBranch: async () => "main",
|
|
296
|
+
getLastCommitMessage: async () => "chore: existing",
|
|
297
|
+
workingTreeSummary: () => ({ hasChanges: false, lines: [] }),
|
|
298
|
+
};
|
|
299
|
+
|
|
300
|
+
const branchName = "master";
|
|
301
|
+
const response = await handleToolCall({
|
|
302
|
+
request: createRequest("run_full_workflow", {
|
|
303
|
+
summary: "Feature done",
|
|
304
|
+
testCommand: "npm test",
|
|
305
|
+
documentationType: "README",
|
|
306
|
+
documentationSummary: "Docs",
|
|
307
|
+
commitMessage: "feat: ship feature",
|
|
308
|
+
branch: branchName,
|
|
309
|
+
releaseCommand: "npm run release:patch",
|
|
310
|
+
}),
|
|
311
|
+
normalizeRequestArgs,
|
|
312
|
+
workflowState,
|
|
313
|
+
exec: execStub,
|
|
314
|
+
git,
|
|
315
|
+
utils,
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
assert.ok(
|
|
319
|
+
response.content[0].text.includes("✅ Full workflow completed successfully"),
|
|
320
|
+
"run_full_workflow should finish successfully"
|
|
321
|
+
);
|
|
322
|
+
|
|
323
|
+
const tagPushCommand = commands.find((command) => command.startsWith("git push --follow-tags"));
|
|
324
|
+
assert.ok(tagPushCommand, "release should push tags");
|
|
325
|
+
assert.ok(
|
|
326
|
+
/origin\s+'?master'?/.test(tagPushCommand),
|
|
327
|
+
`release push should target the provided branch (${branchName})`
|
|
328
|
+
);
|
|
329
|
+
|
|
330
|
+
assert.equal(workflowState.state.currentPhase, "idle");
|
|
331
|
+
});
|
|
332
|
+
});
|
|
333
|
+
|
|
166
334
|
test("project_summary_data reads persisted file and falls back", async () => {
|
|
167
335
|
await withWorkflowState(async (workflowState) => {
|
|
168
336
|
// Seed some history
|
|
@@ -174,7 +342,16 @@ test("project_summary_data reads persisted file and falls back", async () => {
|
|
|
174
342
|
normalizeRequestArgs,
|
|
175
343
|
workflowState,
|
|
176
344
|
exec: async () => ({ stdout: "" }),
|
|
177
|
-
git: {
|
|
345
|
+
git: {
|
|
346
|
+
hasWorkingChanges: async () => false,
|
|
347
|
+
hasStagedChanges: async () => false,
|
|
348
|
+
hasTestChanges: async () => true,
|
|
349
|
+
getStagedChanges: async () => [],
|
|
350
|
+
getCurrentBranch: async () => "main",
|
|
351
|
+
getPrimaryBranch: async () => "main",
|
|
352
|
+
getLastCommitMessage: async () => "",
|
|
353
|
+
workingTreeSummary: () => ({ hasChanges: false, lines: [] }),
|
|
354
|
+
},
|
|
178
355
|
utils,
|
|
179
356
|
});
|
|
180
357
|
|
|
@@ -199,7 +376,16 @@ test("project_summary aggregates task types and recent activity", async () => {
|
|
|
199
376
|
normalizeRequestArgs,
|
|
200
377
|
workflowState,
|
|
201
378
|
exec: async () => ({ stdout: "" }),
|
|
202
|
-
git: {
|
|
379
|
+
git: {
|
|
380
|
+
hasWorkingChanges: async () => false,
|
|
381
|
+
hasStagedChanges: async () => false,
|
|
382
|
+
hasTestChanges: async () => true,
|
|
383
|
+
getStagedChanges: async () => [],
|
|
384
|
+
getCurrentBranch: async () => "main",
|
|
385
|
+
getPrimaryBranch: async () => "main",
|
|
386
|
+
getLastCommitMessage: async () => "",
|
|
387
|
+
workingTreeSummary: () => ({ hasChanges: false, lines: [] }),
|
|
388
|
+
},
|
|
203
389
|
utils,
|
|
204
390
|
});
|
|
205
391
|
|
|
@@ -239,6 +425,7 @@ test("run_full_workflow executes all steps successfully", async () => {
|
|
|
239
425
|
hasTestChanges: async () => true,
|
|
240
426
|
getStagedChanges: async () => [{ status: "M", path: "src/app.js" }],
|
|
241
427
|
getCurrentBranch: async () => "main",
|
|
428
|
+
getPrimaryBranch: async () => "main",
|
|
242
429
|
getLastCommitMessage: async () => "",
|
|
243
430
|
workingTreeSummary: () =>
|
|
244
431
|
workingChanges
|
|
@@ -315,6 +502,7 @@ test("run_full_workflow resumes from current phase when steps are already comple
|
|
|
315
502
|
hasTestChanges: async () => true,
|
|
316
503
|
getStagedChanges: async () => [],
|
|
317
504
|
getCurrentBranch: async () => "main",
|
|
505
|
+
getPrimaryBranch: async () => "main",
|
|
318
506
|
getLastCommitMessage: async () => "",
|
|
319
507
|
workingTreeSummary: () => ({ hasChanges: false, lines: [] }),
|
|
320
508
|
};
|
|
@@ -373,7 +561,16 @@ test("run_full_workflow validates required arguments", async () => {
|
|
|
373
561
|
normalizeRequestArgs,
|
|
374
562
|
workflowState,
|
|
375
563
|
exec: async () => ({ stdout: "" }),
|
|
376
|
-
git: {
|
|
564
|
+
git: {
|
|
565
|
+
hasWorkingChanges: async () => false,
|
|
566
|
+
hasStagedChanges: async () => false,
|
|
567
|
+
hasTestChanges: async () => true,
|
|
568
|
+
getStagedChanges: async () => [],
|
|
569
|
+
getCurrentBranch: async () => "main",
|
|
570
|
+
getPrimaryBranch: async () => "main",
|
|
571
|
+
getLastCommitMessage: async () => "",
|
|
572
|
+
workingTreeSummary: () => ({ hasChanges: false, lines: [] }),
|
|
573
|
+
},
|
|
377
574
|
utils,
|
|
378
575
|
});
|
|
379
576
|
|
|
@@ -400,7 +597,16 @@ test("force_complete_task records entry and resets state", async () => {
|
|
|
400
597
|
normalizeRequestArgs,
|
|
401
598
|
workflowState,
|
|
402
599
|
exec: async () => ({ stdout: "" }),
|
|
403
|
-
git: {
|
|
600
|
+
git: {
|
|
601
|
+
hasWorkingChanges: async () => false,
|
|
602
|
+
hasStagedChanges: async () => false,
|
|
603
|
+
hasTestChanges: async () => true,
|
|
604
|
+
getStagedChanges: async () => [],
|
|
605
|
+
getCurrentBranch: async () => "main",
|
|
606
|
+
getPrimaryBranch: async () => "main",
|
|
607
|
+
getLastCommitMessage: async () => "",
|
|
608
|
+
workingTreeSummary: () => ({ hasChanges: false, lines: [] }),
|
|
609
|
+
},
|
|
404
610
|
utils,
|
|
405
611
|
});
|
|
406
612
|
|
|
@@ -436,7 +642,8 @@ test("perform_release blocks when new changes detected", async () => {
|
|
|
436
642
|
hasTestChanges: async () => true,
|
|
437
643
|
getStagedChanges: async () => [],
|
|
438
644
|
getCurrentBranch: async () => "main",
|
|
439
|
-
|
|
645
|
+
getPrimaryBranch: async () => "main",
|
|
646
|
+
getLastCommitMessage: async () => "",
|
|
440
647
|
workingTreeSummary: () => ({ hasChanges: true, lines: ["?? new-file.js"] }),
|
|
441
648
|
};
|
|
442
649
|
|
|
@@ -466,6 +673,7 @@ test("continue_workflow warns when workflow is idle", async () => {
|
|
|
466
673
|
hasTestChanges: async () => false,
|
|
467
674
|
getStagedChanges: async () => [],
|
|
468
675
|
getCurrentBranch: async () => "main",
|
|
676
|
+
getPrimaryBranch: async () => "main",
|
|
469
677
|
getLastCommitMessage: async () => "",
|
|
470
678
|
workingTreeSummary: () => ({ hasChanges: false, lines: [] }),
|
|
471
679
|
};
|
|
@@ -499,8 +707,9 @@ test("continue_workflow resets to commit when new changes detected", async () =>
|
|
|
499
707
|
hasTestChanges: async () => true,
|
|
500
708
|
getStagedChanges: async () => [],
|
|
501
709
|
getCurrentBranch: async () => "main",
|
|
502
|
-
|
|
503
|
-
|
|
710
|
+
getPrimaryBranch: async () => "main",
|
|
711
|
+
getLastCommitMessage: async () => "",
|
|
712
|
+
workingTreeSummary: () => ({ hasChanges: true, lines: ["?? new-file.js"] }),
|
|
504
713
|
};
|
|
505
714
|
|
|
506
715
|
const response = await handleToolCall({
|
|
@@ -543,6 +752,7 @@ test("commit_and_push recognizes already committed work", async () => {
|
|
|
543
752
|
hasTestChanges: async () => true,
|
|
544
753
|
getStagedChanges: async () => [],
|
|
545
754
|
getCurrentBranch: async () => "main",
|
|
755
|
+
getPrimaryBranch: async () => "main",
|
|
546
756
|
getLastCommitMessage: async () => "fix: previous work",
|
|
547
757
|
workingTreeSummary: () => ({ hasChanges: false, lines: [] }),
|
|
548
758
|
};
|
package/tools/handlers.js
CHANGED
|
@@ -426,8 +426,9 @@ async function handleCommitAndPush(args, context) {
|
|
|
426
426
|
typeof args.commitMessage === "string" ? args.commitMessage.trim() : "";
|
|
427
427
|
|
|
428
428
|
const requestedBranch = typeof args.branch === "string" ? args.branch.trim() : "";
|
|
429
|
+
const primaryBranch = await git.getPrimaryBranch();
|
|
429
430
|
const currentBranch = await git.getCurrentBranch();
|
|
430
|
-
const branchForPush = requestedBranch || currentBranch || "";
|
|
431
|
+
const branchForPush = requestedBranch || primaryBranch || currentBranch || "";
|
|
431
432
|
|
|
432
433
|
const hasWorkingChanges = await git.hasWorkingChanges();
|
|
433
434
|
|
|
@@ -780,6 +781,7 @@ async function handleProjectSummaryDb(workflowState) {
|
|
|
780
781
|
}
|
|
781
782
|
|
|
782
783
|
async function handleRerunWorkflow(workflowState) {
|
|
784
|
+
// Capture task context BEFORE reset to avoid losing it
|
|
783
785
|
const currentDescription = workflowState.state.taskDescription;
|
|
784
786
|
const currentType = workflowState.state.taskType;
|
|
785
787
|
|
|
@@ -787,7 +789,10 @@ async function handleRerunWorkflow(workflowState) {
|
|
|
787
789
|
return textResponse("⚠️ No active task to rerun. Use 'start_task' to begin a new workflow.");
|
|
788
790
|
}
|
|
789
791
|
|
|
792
|
+
// Reset all progress flags but preserve history
|
|
790
793
|
workflowState.reset();
|
|
794
|
+
|
|
795
|
+
// Restore task context after reset
|
|
791
796
|
workflowState.state.currentPhase = "coding";
|
|
792
797
|
workflowState.state.taskDescription = currentDescription;
|
|
793
798
|
workflowState.state.taskType = currentType;
|
|
@@ -817,6 +822,12 @@ async function handleRunFullWorkflow(args, { workflowState, exec, git, utils })
|
|
|
817
822
|
|
|
818
823
|
await workflowState.ensurePrimaryFile();
|
|
819
824
|
|
|
825
|
+
const requestedBranch = typeof args.branch === "string" ? args.branch.trim() : "";
|
|
826
|
+
if (requestedBranch) {
|
|
827
|
+
workflowState.state.lastPushBranch = requestedBranch;
|
|
828
|
+
await workflowState.save();
|
|
829
|
+
}
|
|
830
|
+
|
|
820
831
|
const requiredStrings = [
|
|
821
832
|
{ key: "summary", message: "Provide a non-empty 'summary' for mark_bug_fixed." },
|
|
822
833
|
{ key: "testCommand", message: "Provide a non-empty 'testCommand' for run_tests." },
|
|
@@ -906,7 +917,7 @@ async function handleRunFullWorkflow(args, { workflowState, exec, git, utils })
|
|
|
906
917
|
const resp = await executeStep("commit_and_push", handleCommitAndPush, [
|
|
907
918
|
{
|
|
908
919
|
commitMessage: args.commitMessage,
|
|
909
|
-
branch:
|
|
920
|
+
branch: requestedBranch,
|
|
910
921
|
},
|
|
911
922
|
{ workflowState, exec, git, utils },
|
|
912
923
|
]);
|