@programinglive/dev-workflow-mcp-server 1.1.0 → 1.1.3

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,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.1.3](https://github.com/programinglive/dev-workflow-mcp-server/compare/v1.1.2...v1.1.3) (2025-10-25)
6
+
7
+
8
+ ### ✨ Features
9
+
10
+ * make dev-workflow MCP installable with per-project workflow state isolation ([50e9ead](https://github.com/programinglive/dev-workflow-mcp-server/commit/50e9ead788f2bba1b0ff1a62515f3bcc78d0c8e6))
11
+
12
+ ### [1.1.2](https://github.com/programinglive/dev-workflow-mcp-server/compare/v1.1.1...v1.1.2) (2025-10-25)
13
+
14
+ ### [1.1.1](https://github.com/programinglive/dev-workflow-mcp-server/compare/v1.1.0...v1.1.1) (2025-10-25)
15
+
16
+
17
+ ### ✨ Features
18
+
19
+ * add force_complete_task tool ([f731a7d](https://github.com/programinglive/dev-workflow-mcp-server/commit/f731a7d2e48295963b8573d4a2abd3ebd42ba5ab))
20
+
5
21
  ## [1.1.0](https://github.com/programinglive/dev-workflow-mcp-server/compare/v1.0.11...v1.1.0) (2025-10-25)
6
22
 
7
23
 
package/README.md CHANGED
@@ -16,13 +16,25 @@ This MCP server guides you through a disciplined development workflow:
16
16
 
17
17
  ## 🚀 Installation
18
18
 
19
- ### 1. Install Dependencies
19
+ ### Option 1: Install as Dependency in Your Project (Recommended)
20
+
21
+ Each project gets its own isolated workflow state file.
22
+
23
+ ```bash
24
+ npm install @programinglive/dev-workflow-mcp-server
25
+ ```
26
+
27
+ This will automatically create a `.workflow-state.json` file in your project root, keeping workflow history separate per project.
28
+
29
+ ### Option 2: Install from Source
20
30
 
21
31
  ```bash
32
+ git clone https://github.com/programinglive/dev-workflow-mcp-server.git
33
+ cd dev-workflow-mcp-server
22
34
  npm install
23
35
  ```
24
36
 
25
- ### 2. Configure in Windsurf/Claude Desktop
37
+ ### 3. Configure in Windsurf/Claude Desktop
26
38
 
27
39
  Point your MCP client to the server entry point. Replace `<PROJECT_ROOT>` with the absolute path to this repository on your machine.
28
40
 
@@ -112,10 +124,31 @@ Point your MCP client to the server entry point. Replace `<PROJECT_ROOT>` with t
112
124
 
113
125
  > **Note:** On Windows paths in JSON require escaped backslashes (e.g., `"C:\\path\\to\\project"`).
114
126
 
115
- ### 3. Restart Windsurf/Claude Desktop
127
+ ### 4. Restart Windsurf/Claude Desktop
116
128
 
117
129
  After adding the configuration, restart the application to load the MCP server.
118
130
 
131
+ ## 📁 Project-Specific Workflow State
132
+
133
+ When you install this package in a project, a `.workflow-state.json` file is automatically created in your project root. This file:
134
+
135
+ - **Stores workflow history** specific to that project
136
+ - **Tracks task progress** independently per project
137
+ - **Should be gitignored** (already in `.gitignore` by default)
138
+ - **Persists across sessions** so your workflow state is preserved
139
+
140
+ Each project maintains its own isolated workflow history, so you can work on multiple projects without mixing their histories.
141
+
142
+ ### Adding to .gitignore
143
+
144
+ If you're using this package, add this to your project's `.gitignore`:
145
+
146
+ ```
147
+ .workflow-state.json
148
+ ```
149
+
150
+ This keeps workflow state local to each developer's machine.
151
+
119
152
  ## 🛠️ Available Tools
120
153
 
121
154
  ### Tool Argument Requirements
package/install.js ADDED
@@ -0,0 +1,60 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Installation script for dev-workflow MCP server
5
+ * Sets up per-project workflow state file in the target project directory
6
+ */
7
+
8
+ import fs from 'fs/promises';
9
+ import path from 'path';
10
+ import { fileURLToPath } from 'url';
11
+
12
+ const __filename = fileURLToPath(import.meta.url);
13
+ const __dirname = path.dirname(__filename);
14
+
15
+ async function install() {
16
+ try {
17
+ // Get the project root (where npm install was run)
18
+ const projectRoot = process.cwd();
19
+ const stateFile = path.join(projectRoot, '.workflow-state.json');
20
+
21
+ // Check if state file already exists
22
+ try {
23
+ await fs.access(stateFile);
24
+ console.log(`✓ Workflow state file already exists at ${stateFile}`);
25
+ return;
26
+ } catch {
27
+ // File doesn't exist, create it
28
+ }
29
+
30
+ // Create initial workflow state
31
+ const initialState = {
32
+ currentPhase: 'idle',
33
+ taskDescription: '',
34
+ bugFixed: false,
35
+ testsCreated: false,
36
+ testsPassed: false,
37
+ testsSkipped: false,
38
+ testsSkippedReason: '',
39
+ documentationCreated: false,
40
+ readyToCommit: false,
41
+ readyCheckCompleted: false,
42
+ released: false,
43
+ releaseCommand: '',
44
+ releaseNotes: '',
45
+ commitAndPushCompleted: false,
46
+ lastCommitMessage: '',
47
+ lastPushBranch: '',
48
+ history: [],
49
+ };
50
+
51
+ await fs.writeFile(stateFile, JSON.stringify(initialState, null, 2));
52
+ console.log(`✓ Created workflow state file at ${stateFile}`);
53
+ console.log(`✓ Each project now has its own isolated workflow history`);
54
+ } catch (error) {
55
+ console.error('✗ Installation failed:', error.message);
56
+ process.exit(1);
57
+ }
58
+ }
59
+
60
+ install();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@programinglive/dev-workflow-mcp-server",
3
- "version": "1.1.0",
3
+ "version": "1.1.3",
4
4
  "description": "MCP server to enforce development workflow discipline",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -13,6 +13,7 @@
13
13
  "start": "node index.js",
14
14
  "dev": "node --watch index.js",
15
15
  "prepare": "husky",
16
+ "postinstall": "node install.js",
16
17
  "release": "standard-version",
17
18
  "release:major": "npm run release -- --release-as major",
18
19
  "release:minor": "npm run release -- --release-as minor",
@@ -96,6 +96,35 @@ test("commit_and_push commits changes and pushes", async () => {
96
96
  });
97
97
  });
98
98
 
99
+ test("force_complete_task records entry and resets state", async () => {
100
+ await withWorkflowState(async (workflowState) => {
101
+ workflowState.state.taskDescription = "Improve caching";
102
+ workflowState.state.taskType = "feature";
103
+ workflowState.state.lastCommitMessage = "chore: wip";
104
+ workflowState.state.currentPhase = "release";
105
+ await workflowState.save();
106
+
107
+ const response = await handleToolCall({
108
+ request: createRequest("force_complete_task", {
109
+ commitMessage: "chore: force finish",
110
+ reason: "Deadline hit",
111
+ }),
112
+ normalizeRequestArgs,
113
+ workflowState,
114
+ exec: async () => ({ stdout: "" }),
115
+ git: {},
116
+ utils,
117
+ });
118
+
119
+ assert.ok(response.content[0].text.includes("Task force-completed."));
120
+ assert.equal(workflowState.state.currentPhase, "idle");
121
+ assert.equal(workflowState.state.history.length, 1);
122
+ assert.equal(workflowState.state.history[0].commitMessage, "chore: force finish");
123
+ assert.equal(workflowState.state.history[0].forced, true);
124
+ assert.equal(workflowState.state.history[0].forceReason, "Deadline hit");
125
+ });
126
+ });
127
+
99
128
  test("perform_release blocks when new changes detected", async () => {
100
129
  await withWorkflowState(async (workflowState) => {
101
130
  workflowState.state.currentPhase = "release";
@@ -163,6 +163,24 @@ export function getToolList() {
163
163
  required: ["commitMessage"],
164
164
  },
165
165
  },
166
+ {
167
+ name: "force_complete_task",
168
+ description:
169
+ "Force completion of the current task even if workflow steps are incomplete. Records history entry and resets the workflow.",
170
+ inputSchema: {
171
+ type: "object",
172
+ properties: {
173
+ commitMessage: {
174
+ type: "string",
175
+ description: "Commit message or summary to record (optional)",
176
+ },
177
+ reason: {
178
+ type: "string",
179
+ description: "Why the task was force completed",
180
+ },
181
+ },
182
+ },
183
+ },
166
184
  {
167
185
  name: "drop_task",
168
186
  description:
package/tools/handlers.js CHANGED
@@ -638,6 +638,32 @@ async function handleCompleteTask(args, workflowState) {
638
638
  );
639
639
  }
640
640
 
641
+ async function handleForceCompleteTask(args, workflowState) {
642
+ const commitMessageArg =
643
+ typeof args.commitMessage === "string" ? args.commitMessage.trim() : "";
644
+ const reason = typeof args.reason === "string" ? args.reason.trim() : "";
645
+
646
+ const commitMessage =
647
+ commitMessageArg || workflowState.state.lastCommitMessage || "(no commit recorded)";
648
+
649
+ workflowState.addToHistory({
650
+ taskDescription: workflowState.state.taskDescription,
651
+ taskType: workflowState.state.taskType,
652
+ commitMessage,
653
+ forced: true,
654
+ forceReason: reason,
655
+ });
656
+
657
+ workflowState.reset();
658
+ await workflowState.save();
659
+
660
+ const reasonText = reason ? reason : "(none provided)";
661
+
662
+ return textResponse(
663
+ `⚠️ Task force-completed.\n\nRecorded commit message: ${commitMessage}\nReason: ${reasonText}\nWorkflow state reset. Start a new task when ready.`
664
+ );
665
+ }
666
+
641
667
  async function handleDropTask(args, workflowState) {
642
668
  workflowState.addToHistory({
643
669
  taskDescription: workflowState.state.taskDescription,
@@ -719,6 +745,8 @@ export async function handleToolCall({
719
745
  return handlePerformRelease(args, { workflowState, exec, git, utils });
720
746
  case "complete_task":
721
747
  return handleCompleteTask(args, workflowState);
748
+ case "force_complete_task":
749
+ return handleForceCompleteTask(args, workflowState);
722
750
  case "drop_task":
723
751
  return handleDropTask(args, workflowState);
724
752
  case "get_workflow_status":