@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 +16 -0
- package/README.md +36 -3
- package/install.js +60 -0
- package/package.json +2 -1
- package/tests/handlers.test.js +29 -0
- package/tools/definitions.js +18 -0
- package/tools/handlers.js +28 -0
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
|
|
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
|
-
###
|
|
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
|
-
###
|
|
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.
|
|
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",
|
package/tests/handlers.test.js
CHANGED
|
@@ -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";
|
package/tools/definitions.js
CHANGED
|
@@ -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":
|