@programinglive/dev-workflow-mcp-server 1.1.5 → 1.1.7

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 CHANGED
@@ -2,6 +2,21 @@
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.1.7](https://github.com/programinglive/dev-workflow-mcp-server/compare/v1.1.6...v1.1.7) (2025-10-26)
6
+
7
+
8
+ ### ✨ Features
9
+
10
+ * prompt for documentation after tests pass ([a87e44f](https://github.com/programinglive/dev-workflow-mcp-server/commit/a87e44f2a78ea4c9220d62868ee1f9c7ad3b149b))
11
+
12
+ ### [1.1.6](https://github.com/programinglive/dev-workflow-mcp-server/compare/v1.1.5...v1.1.6) (2025-10-26)
13
+
14
+
15
+ ### šŸ› Bug Fixes
16
+
17
+ * avoid root workflow state path ([a9bd01b](https://github.com/programinglive/dev-workflow-mcp-server/commit/a9bd01bac6b0a17307385688a51873668498e0a0))
18
+ * require explicit commit before release ([5f58ead](https://github.com/programinglive/dev-workflow-mcp-server/commit/5f58ead9006595b7e57460fef585e3f9ea9de409))
19
+
5
20
  ### [1.1.5](https://github.com/programinglive/dev-workflow-mcp-server/compare/v1.1.4...v1.1.5) (2025-10-25)
6
21
 
7
22
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@programinglive/dev-workflow-mcp-server",
3
- "version": "1.1.5",
3
+ "version": "1.1.7",
4
4
  "description": "MCP server to enforce development workflow discipline",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -437,7 +437,7 @@ test("perform_release respects explicit releaseType option", async () => {
437
437
  });
438
438
  });
439
439
 
440
- test("perform_release auto-detects commit when tree is clean", async () => {
440
+ test("perform_release requires commit_and_push completion when tree is clean", async () => {
441
441
  await withWorkflowState(async (workflowState) => {
442
442
  workflowState.state.currentPhase = "release";
443
443
  workflowState.state.commitAndPushCompleted = false;
@@ -449,10 +449,6 @@ test("perform_release auto-detects commit when tree is clean", async () => {
449
449
  const commands = [];
450
450
  const execStub = async (command) => {
451
451
  commands.push(command);
452
- if (command === "git status --porcelain") {
453
- return { stdout: "" };
454
- }
455
-
456
452
  return { stdout: "" };
457
453
  };
458
454
 
@@ -475,15 +471,12 @@ test("perform_release auto-detects commit when tree is clean", async () => {
475
471
  utils,
476
472
  });
477
473
 
478
- const pushCommand = commands.find((command) => command.startsWith("git push --follow-tags"));
479
- assert.ok(pushCommand, "git push with tags should still run");
480
- assert.equal(workflowState.state.commitAndPushCompleted, true);
481
- assert.equal(workflowState.state.lastCommitMessage, "chore: already pushed");
482
- assert.equal(workflowState.state.lastPushBranch, "main");
483
- assert.equal(workflowState.state.currentPhase, "ready_to_complete");
474
+ assert.equal(commands.length, 0, "no release commands should run when commit_and_push not completed");
475
+ assert.equal(workflowState.state.currentPhase, "commit");
476
+ assert.equal(workflowState.state.commitAndPushCompleted, false);
484
477
  assert.ok(
485
- response.content[0].text.includes("Detected clean working tree"),
486
- "response should mention auto-detected commit"
478
+ response.content[0].text.includes("Please run 'commit_and_push' after the ready check"),
479
+ "response should instruct user to run commit_and_push"
487
480
  );
488
481
  });
489
482
  });
package/tools/handlers.js CHANGED
@@ -290,7 +290,7 @@ async function handleRunTests(args, workflowState) {
290
290
  await workflowState.save();
291
291
 
292
292
  return textResponse(
293
- `āœ… All tests passed! šŸŽ‰\n\nTest command: ${args.testCommand}\n\nNext Steps:\n1. āœ“ Fix/implement feature\n2. āœ“ Create tests\n3. āœ“ Run tests (GREEN!)\n4. ā³ Create/update documentation\n5. ā³ Run 'check_ready_to_commit'\n6. ā³ Run 'commit_and_push'\n7. ā³ Run 'perform_release'\n8. ā³ Complete task\n\nReminder: Document what you did before committing!`
293
+ `āœ… All tests passed! šŸŽ‰\n\nTest command: ${args.testCommand}\n\nšŸ“ Now create documentation using 'create_documentation' with:\n- documentationType: "README", "inline-comments", "API-docs", "changelog", or "other"\n- summary: Brief description of what was documented\n\nNext Steps:\n1. āœ“ Fix/implement feature\n2. āœ“ Create tests\n3. āœ“ Run tests (GREEN!)\n4. ā³ Create/update documentation\n5. ā³ Run 'check_ready_to_commit'\n6. ā³ Run 'commit_and_push'\n7. ā³ Run 'perform_release'\n8. ā³ Complete task`
294
294
  );
295
295
  }
296
296
 
@@ -480,8 +480,6 @@ async function handlePerformRelease(args, context) {
480
480
  );
481
481
  }
482
482
 
483
- let autoDetectedCommit = false;
484
-
485
483
  if (!workflowState.state.commitAndPushCompleted) {
486
484
  const hasWorkingChanges = await git.hasWorkingChanges();
487
485
 
@@ -491,16 +489,12 @@ async function handlePerformRelease(args, context) {
491
489
  );
492
490
  }
493
491
 
494
- const lastCommitMessage = await git.getLastCommitMessage();
495
- const currentBranch = await git.getCurrentBranch();
496
-
497
- workflowState.state.commitAndPushCompleted = true;
498
- workflowState.state.lastCommitMessage =
499
- lastCommitMessage || workflowState.state.lastCommitMessage || "";
500
- workflowState.state.lastPushBranch = currentBranch || workflowState.state.lastPushBranch || "";
501
- workflowState.state.currentPhase = "release";
502
- autoDetectedCommit = true;
492
+ workflowState.state.currentPhase = "commit";
503
493
  await workflowState.save();
494
+
495
+ return textResponse(
496
+ "āš ļø Please run 'commit_and_push' after the ready check before recording a release!"
497
+ );
504
498
  }
505
499
 
506
500
  const rawReleaseCommand = typeof args.command === "string" ? args.command.trim() : "";
@@ -610,16 +604,10 @@ async function handlePerformRelease(args, context) {
610
604
 
611
605
  const message = summarizeHistory(workflowState.state.history, args.limit || 10);
612
606
  if (!message) {
613
- const autoNote = autoDetectedCommit
614
- ? "\n\nā„¹ļø Detected clean working tree and treated commit/push as already completed."
615
- : "";
616
- return textResponse(`šŸ“œ No workflow history yet.${autoNote}`);
607
+ return textResponse("šŸ“œ No workflow history yet.");
617
608
  }
618
609
 
619
- const autoNote = autoDetectedCommit
620
- ? "\n\nā„¹ļø Detected clean working tree and treated commit/push as already completed."
621
- : "";
622
- return textResponse(`${message}${autoNote}`);
610
+ return textResponse(message);
623
611
  }
624
612
 
625
613
  async function handleCompleteTask(args, workflowState) {
package/workflow-state.js CHANGED
@@ -4,6 +4,16 @@ import { fileURLToPath } from "url";
4
4
 
5
5
  const __filename = fileURLToPath(import.meta.url);
6
6
  const __dirname = path.dirname(__filename);
7
+ const STATE_FILENAME = ".workflow-state.json";
8
+
9
+ function isRootPath(candidate) {
10
+ if (!candidate) {
11
+ return true;
12
+ }
13
+
14
+ const resolved = path.resolve(candidate);
15
+ return path.parse(resolved).root === resolved;
16
+ }
7
17
 
8
18
  function resolveDefaultStateFile() {
9
19
  if (process.env.DEV_WORKFLOW_STATE_FILE) {
@@ -11,20 +21,20 @@ function resolveDefaultStateFile() {
11
21
  }
12
22
 
13
23
  const cwd = process.cwd();
14
- if (!cwd.includes(`node_modules${path.sep}`)) {
15
- return path.join(cwd, ".workflow-state.json");
24
+ if (!cwd.includes(`node_modules${path.sep}`) && !isRootPath(cwd)) {
25
+ return path.join(cwd, STATE_FILENAME);
16
26
  }
17
27
 
18
- if (process.env.INIT_CWD) {
19
- return path.join(process.env.INIT_CWD, ".workflow-state.json");
28
+ if (process.env.INIT_CWD && !isRootPath(process.env.INIT_CWD)) {
29
+ return path.join(process.env.INIT_CWD, STATE_FILENAME);
20
30
  }
21
31
 
22
32
  const [beforeNodeModules] = cwd.split(`node_modules${path.sep}`);
23
- if (beforeNodeModules) {
24
- return path.join(beforeNodeModules, ".workflow-state.json");
33
+ if (beforeNodeModules && !isRootPath(beforeNodeModules)) {
34
+ return path.join(beforeNodeModules, STATE_FILENAME);
25
35
  }
26
36
 
27
- return path.join(__dirname, ".workflow-state.json");
37
+ return path.join(__dirname, STATE_FILENAME);
28
38
  }
29
39
 
30
40
  export class WorkflowState {