@programinglive/dev-workflow-mcp-server 1.7.0 → 1.7.9

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/db/index.js CHANGED
@@ -1,204 +1,73 @@
1
- import Database from "better-sqlite3";
2
- import { existsSync } from "fs";
3
- import path from "path";
4
- import { fileURLToPath } from "url";
1
+ import { SqliteAdapter } from "./adapters/sqlite.js";
2
+ import { MysqlAdapter } from "./adapters/mysql.js";
3
+ import { PostgresAdapter } from "./adapters/postgres.js";
5
4
 
6
- const __filename = fileURLToPath(import.meta.url);
7
- const __dirname = path.dirname(__filename);
8
- const DB_FILENAME = "dev-workflow.db";
9
- const FREQUENCY_FORMATS = {
10
- daily: "%Y-%m-%d",
11
- monthly: "%Y-%m",
12
- yearly: "%Y",
13
- };
5
+ let adapterInstance = null;
14
6
 
15
- function getDbPath() {
16
- const initCwd = process.env.INIT_CWD || process.cwd();
17
- let projectRoot = initCwd;
18
- while (projectRoot !== path.dirname(projectRoot)) {
19
- if (existsSync(path.join(projectRoot, "package.json"))) break;
20
- projectRoot = path.dirname(projectRoot);
7
+ export async function getAdapter() {
8
+ if (adapterInstance) {
9
+ return adapterInstance;
21
10
  }
22
- return path.join(projectRoot, ".state", DB_FILENAME);
23
- }
24
11
 
25
- let db;
26
- export function getDb() {
27
- if (!db) {
28
- const dbPath = getDbPath();
29
- db = new Database(dbPath);
30
- db.pragma("journal_mode = WAL");
31
- migrate();
12
+ const type = (process.env.DEV_WORKFLOW_DB_TYPE || "sqlite").toLowerCase();
13
+ const config = {
14
+ connectionUrl: process.env.DEV_WORKFLOW_DB_URL,
15
+ dbPath: process.env.DEV_WORKFLOW_DB_PATH // optional override for sqlite
16
+ };
17
+
18
+ switch (type) {
19
+ case "mysql":
20
+ adapterInstance = new MysqlAdapter(config);
21
+ break;
22
+ case "postgres":
23
+ case "postgresql":
24
+ adapterInstance = new PostgresAdapter(config);
25
+ break;
26
+ case "sqlite":
27
+ default:
28
+ adapterInstance = new SqliteAdapter(config);
29
+ break;
32
30
  }
33
- return db;
31
+
32
+ await adapterInstance.connect();
33
+ return adapterInstance;
34
34
  }
35
35
 
36
- function migrate() {
37
- const createHistory = `
38
- CREATE TABLE IF NOT EXISTS workflow_history (
39
- id INTEGER PRIMARY KEY AUTOINCREMENT,
40
- user_id TEXT NOT NULL,
41
- task_description TEXT NOT NULL,
42
- task_type TEXT NOT NULL,
43
- commit_message TEXT,
44
- timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
45
- forced INTEGER DEFAULT 0,
46
- force_reason TEXT,
47
- dropped INTEGER DEFAULT 0,
48
- drop_reason TEXT,
49
- UNIQUE(user_id, timestamp, task_description)
50
- )
51
- `;
52
- const createSummary = `
53
- CREATE TABLE IF NOT EXISTS project_summary (
54
- user_id TEXT PRIMARY KEY,
55
- total_tasks INTEGER DEFAULT 0,
56
- task_types TEXT DEFAULT '{}',
57
- last_active DATETIME,
58
- updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
59
- recent_tasks TEXT DEFAULT '[]'
60
- )
61
- `;
62
- const idxHistory = `CREATE INDEX IF NOT EXISTS idx_workflow_history_user ON workflow_history(user_id)`;
63
- const idxSummary = `CREATE INDEX IF NOT EXISTS idx_project_summary_user ON project_summary(user_id)`;
36
+ // Proxies for backward compatibility (though call sites need to handle Promises now)
64
37
 
65
- db.exec(createHistory);
66
- db.exec(createSummary);
67
- db.exec(idxHistory);
68
- db.exec(idxSummary);
38
+ export async function insertHistoryEntry(userId, projectPath, entry) {
39
+ const db = await getAdapter();
40
+ await db.insertHistoryEntry(userId, projectPath, entry);
69
41
  }
70
42
 
71
- export function insertHistoryEntry(userId, entry) {
72
- const stmt = getDb().prepare(`
73
- INSERT OR REPLACE INTO workflow_history
74
- (user_id, task_description, task_type, commit_message, timestamp, forced, force_reason, dropped, drop_reason)
75
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
76
- `);
77
- stmt.run(
78
- userId,
79
- entry.taskDescription,
80
- entry.taskType,
81
- entry.commitMessage,
82
- entry.timestamp || new Date().toISOString(),
83
- entry.forced ? 1 : 0,
84
- entry.forceReason || null,
85
- entry.dropped ? 1 : 0,
86
- entry.dropReason || null
87
- );
88
- updateSummaryForUser(userId);
43
+ export async function updateSummaryForUser(userId, projectPath) {
44
+ const db = await getAdapter();
45
+ await db.updateSummaryForUser(userId, projectPath);
89
46
  }
90
47
 
91
- export function updateSummaryForUser(userId) {
92
- const getHistory = getDb().prepare(`
93
- SELECT task_type, timestamp, task_description
94
- FROM workflow_history
95
- WHERE user_id = ?
96
- ORDER BY timestamp DESC
97
- LIMIT 20
98
- `);
99
- const rows = getHistory.all(userId);
100
-
101
- const taskTypes = {};
102
- for (const row of rows) {
103
- taskTypes[row.task_type] = (taskTypes[row.task_type] || 0) + 1;
104
- }
105
-
106
- const recentTasks = rows.slice(0, 5).map(r => ({
107
- description: r.task_description,
108
- type: r.task_type,
109
- timestamp: r.timestamp,
110
- }));
111
-
112
- const lastActive = rows[0]?.timestamp || null;
113
-
114
- const upsert = getDb().prepare(`
115
- INSERT OR REPLACE INTO project_summary
116
- (user_id, total_tasks, task_types, last_active, recent_tasks, updated_at)
117
- VALUES (?, ?, ?, ?, ?, ?)
118
- `);
119
- upsert.run(
120
- userId,
121
- rows.length,
122
- JSON.stringify(taskTypes),
123
- lastActive,
124
- JSON.stringify(recentTasks),
125
- new Date().toISOString()
126
- );
48
+ export async function getSummaryForUser(userId, projectPath) {
49
+ const db = await getAdapter();
50
+ return await db.getSummaryForUser(userId, projectPath);
127
51
  }
128
52
 
129
- export function getSummaryForUser(userId) {
130
- const stmt = getDb().prepare(`
131
- SELECT * FROM project_summary WHERE user_id = ?
132
- `);
133
- const row = stmt.get(userId);
134
- if (!row) return null;
135
- return {
136
- totalTasks: row.total_tasks,
137
- taskTypes: JSON.parse(row.task_types),
138
- lastActive: row.last_active,
139
- recentTasks: JSON.parse(row.recent_tasks),
140
- updatedAt: row.updated_at,
141
- };
53
+ export async function getHistoryForUser(userId, projectPath, options) {
54
+ const db = await getAdapter();
55
+ return await db.getHistoryForUser(userId, projectPath, options);
142
56
  }
143
57
 
144
- function buildHistoryFilters({ startDate, endDate }) {
145
- const clauses = [];
146
- const params = [];
147
- if (startDate) {
148
- clauses.push("DATE(timestamp) >= DATE(?)");
149
- params.push(startDate);
150
- }
151
- if (endDate) {
152
- clauses.push("DATE(timestamp) <= DATE(?)");
153
- params.push(endDate);
154
- }
155
- return { clauses, params };
58
+ export async function getHistorySummary(userId, projectPath, options) {
59
+ const db = await getAdapter();
60
+ return await db.getHistorySummary(userId, projectPath, options);
156
61
  }
157
62
 
158
- export function getHistoryForUser(userId, options = {}) {
159
- const { page = 1, pageSize = 20, startDate, endDate } = options;
160
- const sanitizedPage = Math.max(1, Number.isFinite(Number(page)) ? Math.floor(Number(page)) : 1);
161
- const sanitizedPageSize = Math.min(100, Math.max(1, Number.isFinite(Number(pageSize)) ? Math.floor(Number(pageSize)) : 20));
162
- const offset = (sanitizedPage - 1) * sanitizedPageSize;
163
-
164
- const { clauses, params } = buildHistoryFilters({ startDate, endDate });
165
- const where = ["user_id = ?", ...clauses].join(" AND ");
166
- const dbInstance = getDb();
167
-
168
- const countStmt = dbInstance.prepare(`SELECT COUNT(*) as total FROM workflow_history WHERE ${where}`);
169
- const total = countStmt.get(userId, ...params).total;
170
-
171
- const rowsStmt = dbInstance.prepare(`
172
- SELECT *
173
- FROM workflow_history
174
- WHERE ${where}
175
- ORDER BY timestamp DESC
176
- LIMIT ?
177
- OFFSET ?
178
- `);
179
- const entries = rowsStmt.all(userId, ...params, sanitizedPageSize, offset);
180
-
181
- return {
182
- entries,
183
- total,
184
- page: sanitizedPage,
185
- pageSize: sanitizedPageSize,
186
- };
63
+ export async function saveState(userId, projectPath, state) {
64
+ const db = await getAdapter();
65
+ await db.saveState(userId, projectPath, state);
187
66
  }
188
67
 
189
- export function getHistorySummary(userId, options = {}) {
190
- const { startDate, endDate, frequency = "daily" } = options;
191
- const format = FREQUENCY_FORMATS[frequency] || FREQUENCY_FORMATS.daily;
192
- const { clauses, params } = buildHistoryFilters({ startDate, endDate });
193
- const where = ["user_id = ?", ...clauses].join(" AND ");
194
- const stmt = getDb().prepare(`
195
- SELECT strftime('${format}', timestamp) AS period, COUNT(*) AS count
196
- FROM workflow_history
197
- WHERE ${where}
198
- GROUP BY period
199
- ORDER BY period DESC
200
- `);
201
- return stmt
202
- .all(userId, ...params)
203
- .map((row) => ({ period: row.period, count: row.count }));
68
+ export async function getState(userId, projectPath) {
69
+ const db = await getAdapter();
70
+ return await db.getState(userId, projectPath);
204
71
  }
72
+
73
+
@@ -3,8 +3,8 @@
3
3
  ## 1. Overview
4
4
  - **Product**: Development Workflow MCP Server
5
5
  - **Prepared by**: Cascade (AI assistant)
6
- - **Date**: 2025-10-31
7
- - **Status**: Draft v0.1
6
+ - **Date**: 2025-12-16
7
+ - **Status**: Live v1.6+
8
8
 
9
9
  ## 2. Problem Statement
10
10
  Developers need structured guidance to maintain disciplined workflows across projects. Existing tooling lacks enforcement of sequential best practices (testing, documentation, release hygiene) and offers limited visibility into historical task execution.
@@ -13,6 +13,7 @@ Developers need structured guidance to maintain disciplined workflows across pro
13
13
  1. Enforce a consistent, auditable development workflow across teams.
14
14
  2. Provide actionable guidance for each workflow phase within IDE-integrated environments.
15
15
  3. Maintain per-project, per-user workflow state while supporting shared infrastructure (e.g., SQLite summaries, dashboard).
16
+ 4. **Support flexible data persistence**: Enable usage of various database backends (MySQL, PostgreSQL, SQLite) to adapt to different hosting and enterprise environments.
16
17
 
17
18
  ## 4. Non-Goals
18
19
  - Replacing full-featured project management tools.
@@ -28,19 +29,24 @@ Developers need structured guidance to maintain disciplined workflows across pro
28
29
  1. As a developer, I want to be guided through the workflow steps so I can avoid skipping critical tasks.
29
30
  2. As a team lead, I want an auditable history of workflow completion so I can ensure compliance.
30
31
  3. As an integrator, I want a simple API (tools/prompts) so I can plug the MCP server into existing agent workflows.
32
+ 4. As a devops engineer, I want to configure the server to use my existing database infrastructure (MySQL/PostgreSQL) instead of local files.
31
33
 
32
34
  ## 7. Functional Requirements
33
35
  - Provide MCP tools covering the full workflow lifecycle (start task, fix, test, document, commit, release, complete).
34
36
  - Persist workflow state per project and per user, with compatibility handling for legacy locations.
35
- - Offer aggregated project summaries (JSON artifacts, SQLite sync, optional web dashboard).
37
+ - Offer aggregated project summaries (JSON artifacts, Database sync, optional web dashboard).
36
38
  - Guard release commands to ensure prerequisites are satisfied.
37
39
  - Support `run_full_workflow` for scripted execution of all steps with validation.
38
40
  - Web dashboard displays version dynamically from `package.json` via `/api/version` endpoint to stay in sync after releases.
41
+ - **Multi-Database Support**: Abstract the storage layer to support:
42
+ - SQLite (default/local)
43
+ - MySQL
44
+ - PostgreSQL
39
45
 
40
46
  ## 8. Technical Considerations
41
47
  - Node.js (ESM) codebase leveraging `@modelcontextprotocol/sdk`.
42
48
  - File-based state stored under `.state/users/<user>/workflow-state.json` with compatibility symlinks.
43
- - Optional SQLite integration for history and summary caching.
49
+ - **Database Abstraction**: Implement an Adapter/Repository pattern or use an ORM (e.g., Knex, Prisma, Drizzle) to support multiple SQL dialects.
44
50
  - Vite build pipeline for distribution bundle; source usage recommended for MCP.
45
51
  - Windows compatibility requirements (Python, Build Tools for native modules).
46
52
  - **Deployment options**: Local development, Netlify (static), Plesk (full-featured).
@@ -49,17 +55,21 @@ Developers need structured guidance to maintain disciplined workflows across pro
49
55
  - ≥90% of workflow operations executed via MCP tools (vs. manual overrides).
50
56
  - Reduction in release guard violations to <5% of attempts.
51
57
  - Positive qualitative feedback on guidance clarity from pilot teams.
58
+ - Seamless switching between SQLite, MySQL, and PostgreSQL via configuration.
52
59
 
53
60
  ## 10. Milestones
54
61
  1. **MVP**: Core workflow tools, state persistence, basic history (complete).
55
62
  2. **Enhancements**: Improved project root detection, compatibility mirrors, `run_full_workflow` automation (complete).
56
63
  3. **v1.5.0**: Netlify deployment support for static web dashboard (complete).
57
- 4. **Future**: Expanded dashboard analytics, customizable workflows, richer integrations.
64
+ 4. **v1.6.0+**: Dark/Light mode, UI Improvements (complete).
65
+ 5. **Multi-Database Support**: Refactor storage layer to support MySQL and PostgreSQL (Upcoming).
66
+ 6. **Future**: Expanded dashboard analytics, customizable workflows, richer integrations.
58
67
 
59
68
  ## 11. Risks & Mitigations
60
69
  - **Risk**: Workflow feels overly prescriptive. **Mitigation**: Provide escape hatches (`force_complete_task`, `drop_task`) with audit trails.
61
70
  - **Risk**: State corruption due to concurrent access. **Mitigation**: File locking and defensive JSON parsing (existing code handles gracefully, but monitor).
62
71
  - **Risk**: Integration friction with IDE clients. **Mitigation**: Maintain detailed README instructions and example configurations.
72
+ - **Risk**: Complicated setup for users not needing external DBs. **Mitigation**: Keep SQLite/File-system as the default zero-config option.
63
73
 
64
74
  ## 12. Open Questions
65
75
  - Should additional workflow phases (e.g., design review) be supported?
@@ -2,6 +2,135 @@
2
2
 
3
3
  Authoritative history of user-visible changes for the Development Workflow MCP Server. Each entry highlights the improvements that shipped with the tagged version.
4
4
 
5
+ | Version | Date | Notes |
6
+ |---------|------|-------|
7
+ | 1.7.8 | 2025-12-16 | **ci:** remove all token config for pure OIDC publishing (d4759cc) |
8
+ | 1.7.7 | 2025-12-16 | **ci:** remove duplicates and apply robust trusted publishing config (eedb661) |
9
+ | 1.7.6 | 2025-12-16 | **ci:** restore registry config with token fallback for Trusted Publishing (542615c) |
10
+ | 1.7.5 | 2025-12-16 | **ci:** switch to tokenless trusted publishing (fdfc4a9) |
11
+ | 1.7.4 | 2025-12-16 | **ci:** add id-token permission for npm provenance (8930338) |
12
+ | 1.7.3 | 2025-12-16 | **ci:** add web dependencies installation step (7d5dc62) |
13
+ | 1.7.2 | 2025-12-16 | **ci:** consolidate release and publish workflows (98e5b31) |
14
+ | 1.7.1 | 2025-12-16 | build errors and warnings (dc24831) |
15
+ | 1.7.0 | 2025-12-16 | See CHANGELOG for details. |
16
+ | 1.6.3 | 2025-12-06 | update release notes for 1.6.2 (f0c2d49) |
17
+ | 1.6.2 | 2025-12-06 | update release notest for 1.6.1 (72a9284) |
18
+ | 1.6.1 | 2025-12-06 | add table header to release notes for release script compatibility (44e47fc) |
19
+
20
+
21
+
22
+
23
+
24
+
25
+
26
+
27
+
28
+
29
+
30
+
31
+
32
+ ## 1.7.8 – 🐛 Bug Fixes
33
+
34
+ Released on **2025-12-16**.
35
+
36
+ - **ci:** remove all token config for pure OIDC publishing (d4759cc)
37
+
38
+ ## 1.7.7 – 🐛 Bug Fixes
39
+
40
+ Released on **2025-12-16**.
41
+
42
+ - **ci:** remove duplicates and apply robust trusted publishing config (eedb661)
43
+
44
+ ## 1.7.6 – 🐛 Bug Fixes
45
+
46
+ Released on **2025-12-16**.
47
+
48
+ - **ci:** restore registry config with token fallback for Trusted Publishing (542615c)
49
+
50
+ ## 1.7.5 – 🐛 Bug Fixes
51
+
52
+ Released on **2025-12-16**.
53
+
54
+ - **ci:** switch to tokenless trusted publishing (fdfc4a9)
55
+
56
+ ## 1.7.4 – 🐛 Bug Fixes
57
+
58
+ Released on **2025-12-16**.
59
+
60
+ - **ci:** add id-token permission for npm provenance (8930338)
61
+
62
+ ## 1.7.3 – 🐛 Bug Fixes
63
+
64
+ Released on **2025-12-16**.
65
+
66
+ - **ci:** add web dependencies installation step (7d5dc62)
67
+
68
+ ## 1.7.2 – 🐛 Bug Fixes
69
+
70
+ Released on **2025-12-16**.
71
+
72
+ - **ci:** consolidate release and publish workflows (98e5b31)
73
+
74
+ ## 1.7.1 – 🐛 Bug Fixes
75
+
76
+ Released on **2025-12-16**.
77
+
78
+ - build errors and warnings (dc24831)
79
+ - suppress remaining build warnings (f7d9b2d)
80
+ - handle null CustPL in birthday-customers.blade.php (ERP-19) (71b8f7e)
81
+ - integrate database adapters into workflow state (370cbb4)
82
+ - update PRD and add configuration guide (1dfccf5)
83
+ - update release notes for 1.6.3 (afb9fb9)
84
+ - add mysql2 and pg dependencies (94423d7)
85
+ - **release:** null 🚀 (93a17e2)
86
+ - **release:** null 🚀 (033097e)
87
+ - **release:** null 🚀 (91c800a)
88
+ - **release:** null 🚀 (f0958c4)
89
+ - **release:** null 🚀 (ac3cc6e)
90
+ - **release:** null 🚀 (f3f9a00)
91
+ - **release:** null 🚀 (bcf7d95)
92
+ - **release:** null 🚀 (74df6d6)
93
+ - **release:** null 🚀 (0d9dc4d)
94
+ - **release:** null 🚀 (9667012)
95
+ - **release:** null 🚀 (db25d0c)
96
+ - **release:** null 🚀 (50d5353)
97
+ - **release:** null 🚀 (ee0a540)
98
+ - **release:** null 🚀 (92558af)
99
+ - **release:** null 🚀 (cd851ac)
100
+ - **release:** null 🚀 (49ec562)
101
+ - **release:** null 🚀 (bcc7a3c)
102
+ - implement database adapters for sqlite, mysql, postgres (8e7416a)
103
+ - persist active workflow state to database (d29546d)
104
+
105
+ ## 1.7.0
106
+
107
+ Released on **2025-12-16**.
108
+
109
+ - See CHANGELOG for details.
110
+
111
+ ## 1.6.3 – 📝 Documentation
112
+
113
+ Released on **2025-12-06**.
114
+
115
+ - update release notes for 1.6.2 (f0c2d49)
116
+ - add light mode support to docs page (490cf22)
117
+
118
+ ## 1.6.2 – 📝 Documentation
119
+
120
+ Released on **2025-12-06**.
121
+
122
+ - update release notest for 1.6.1 (72a9284)
123
+ - update create_documentation test to verify PRD check and remove incompatible jest test (a7f2b28)
124
+ - add PRD file existence check to create_documentation workflow step (62cdee3)
125
+ - add PRD file existence check to create_documentation workflow step (6c51012)
126
+
127
+ ## 1.6.1 – 🐛 Bug Fixes
128
+
129
+ Released on **2025-12-06**.
130
+
131
+ - add table header to release notes for release script compatibility (44e47fc)
132
+ - add responsive vertical monitor support and dark/light mode toggle (5565765)
133
+
5
134
  ## Unreleased
6
135
 
7
136
  ## 1.5.11 — 2025-12-05
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@programinglive/dev-workflow-mcp-server",
3
- "version": "1.7.0",
3
+ "version": "1.7.9",
4
4
  "description": "MCP server to enforce development workflow discipline",
5
5
  "homepage": "https://devworkflow.programinglive.com/",
6
6
  "mcpName": "io.github.programinglive/dev-workflow-mcp-server",
@@ -25,7 +25,8 @@
25
25
  "release:major": "node scripts/release.cjs major",
26
26
  "release:minor": "node scripts/release.cjs minor",
27
27
  "release:patch": "node scripts/release.cjs patch",
28
- "web": "npm start --prefix web"
28
+ "web": "npm start --prefix web",
29
+ "release:first": "node scripts/release.cjs --first-release"
29
30
  },
30
31
  "keywords": [
31
32
  "mcp",
@@ -45,6 +46,8 @@
45
46
  "esbuild": "^0.25.0",
46
47
  "get-port": "^7.1.0",
47
48
  "marked": "^12.0.2",
49
+ "mysql2": "^3.15.3",
50
+ "pg": "^8.16.3",
48
51
  "vite": "^7.1.12"
49
52
  },
50
53
  "publishConfig": {
@@ -53,7 +56,7 @@
53
56
  "devDependencies": {
54
57
  "@commitlint/cli": "^20.2.0",
55
58
  "@commitlint/config-conventional": "^20.2.0",
56
- "@programinglive/commiter": "^1.2.8",
59
+ "@programinglive/commiter": "^1.2.16",
57
60
  "autoprefixer": "^10.4.22",
58
61
  "husky": "^9.1.7",
59
62
  "postcss": "^8.5.6",
@@ -26,18 +26,18 @@ const SEMVER_REGEX = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/;
26
26
  const LOCKFILE_PREFERENCES = [
27
27
  { manager: 'pnpm', file: 'pnpm-lock.yaml' },
28
28
  { manager: 'yarn', file: 'yarn.lock' },
29
- { manager: 'bun', file: 'bun.lockb' },
29
+ { manager: 'bun', file: 'bun.lock' },
30
30
  { manager: 'npm', file: 'package-lock.json' }
31
31
  ];
32
32
 
33
33
  function getCliArguments(argv = process.argv) {
34
34
  const rawArgs = argv.slice(2);
35
35
  if (rawArgs.length === 0) {
36
- return { releaseType: undefined, extraArgs: [] };
36
+ return { releaseType: 'patch', extraArgs: [] };
37
37
  }
38
38
 
39
39
  if (rawArgs[0].startsWith('-')) {
40
- return { releaseType: undefined, extraArgs: rawArgs };
40
+ return { releaseType: 'patch', extraArgs: rawArgs };
41
41
  }
42
42
 
43
43
  const [firstArg, ...rest] = rawArgs;
@@ -60,7 +60,14 @@ function getNpmRunArgument(env = process.env) {
60
60
 
61
61
  function buildStandardVersionArgs({ releaseType, extraArgs }) {
62
62
  const args = [];
63
- if (releaseType) {
63
+
64
+ // Handle --first-release flag
65
+ const isFirstRelease = Array.isArray(extraArgs) && extraArgs.includes('--first-release');
66
+ if (isFirstRelease) {
67
+ args.push('--release-as', '0.0.1');
68
+ // Remove --first-release from extraArgs to avoid passing it to standard-version
69
+ extraArgs = extraArgs.filter(arg => arg !== '--first-release');
70
+ } else if (releaseType) {
64
71
  const normalized = releaseType.trim();
65
72
  const isValid = VALID_RELEASE_TYPES.has(normalized) || SEMVER_REGEX.test(normalized);
66
73
  if (!isValid) {
@@ -79,7 +79,7 @@ test("run_tests guidance mentions core documentation types", async () => {
79
79
  });
80
80
  });
81
81
 
82
- test("create_documentation accepts PRD and records created/updated message", async () => {
82
+ test("create_documentation verifies PRD file exists", async () => {
83
83
  await withWorkflowState(async (workflowState) => {
84
84
  workflowState.state.testsPassed = true;
85
85
  await workflowState.save();
@@ -105,6 +105,7 @@ test("create_documentation accepts PRD and records created/updated message", asy
105
105
  utils,
106
106
  });
107
107
 
108
+ // Should succeed since PRD.md exists in the project
108
109
  assert.equal(workflowState.state.documentationCreated, true);
109
110
  assert.equal(workflowState.state.documentationType, "PRD");
110
111
  assert.equal(
@@ -115,6 +116,10 @@ test("create_documentation accepts PRD and records created/updated message", asy
115
116
  response.content[0].text.includes("Documentation created/updated!"),
116
117
  "create_documentation response should mention created/updated",
117
118
  );
119
+ assert.ok(
120
+ response.content[0].text.includes("PRD verified"),
121
+ "create_documentation response should verify PRD file",
122
+ );
118
123
  });
119
124
  });
120
125
 
package/tools/handlers.js CHANGED
@@ -23,7 +23,7 @@ async function resetToCommitIfWorkingChanges(workflowState, git) {
23
23
 
24
24
  const hasWorkingChanges = await git.hasWorkingChanges();
25
25
  const hasStagedChanges = await git.hasStagedChanges();
26
-
26
+
27
27
  if (!hasWorkingChanges && !hasStagedChanges) {
28
28
  return false;
29
29
  }
@@ -105,9 +105,8 @@ function getContinueGuidance(status) {
105
105
  : "Run your automated tests and record the outcome with 'run_tests'. Fix any failures before moving forward.";
106
106
  case "documentation":
107
107
  return status.testsSkipped
108
- ? `Document the change (including manual QA for skipped tests) with 'create_documentation'. Reason recorded: ${
109
- status.testsSkippedReason || "(none provided)"
110
- }.`
108
+ ? `Document the change (including manual QA for skipped tests) with 'create_documentation'. Reason recorded: ${status.testsSkippedReason || "(none provided)"
109
+ }.`
111
110
  : "Capture your updates with 'create_documentation' (provide the documentation type and a short summary).";
112
111
  case "ready":
113
112
  return "Run 'check_ready_to_commit' to verify all prerequisite steps before committing.";
@@ -355,6 +354,16 @@ async function handleCreateDocumentation(args, workflowState) {
355
354
  return textResponse("⚠️ Please ensure tests are passing first! Run 'run_tests' with passed=true.");
356
355
  }
357
356
 
357
+ // Check if PRD exists in docs folder
358
+ const prdPath = path.join(__dirname, "..", "docs", "product", "PRD.md");
359
+ const prdExists = existsSync(prdPath);
360
+
361
+ if (!prdExists) {
362
+ return textResponse(
363
+ `⚠️ PRD file not found!\n\nExpected location: docs/product/PRD.md\n\nPlease create or update the PRD before marking documentation as complete.`
364
+ );
365
+ }
366
+
358
367
  workflowState.state.documentationCreated = true;
359
368
  workflowState.state.documentationType = args.documentationType;
360
369
  workflowState.state.documentationSummary = args.summary;
@@ -368,7 +377,7 @@ async function handleCreateDocumentation(args, workflowState) {
368
377
  await workflowState.save();
369
378
 
370
379
  return textResponse(
371
- `✅ Documentation created/updated!\n\nType: ${args.documentationType}\nSummary: ${args.summary}\n\n🎉 You're ready to verify your work!\n\nNext Steps:\n1. ✓ Fix/implement feature\n2. ✓ Create tests\n3. ✓ Run tests (GREEN!)\n4. ✓ Create/update documentation\n5. ⏳ Run 'check_ready_to_commit' to verify\n6. ⏳ Run 'commit_and_push'\n7. ⏳ Run 'perform_release'\n8. ⏳ Mark as complete with 'complete_task'`
380
+ `✅ Documentation created/updated!\n\nType: ${args.documentationType}\nSummary: ${args.summary}\n✅ PRD verified: docs/product/PRD.md exists\n\n🎉 You're ready to verify your work!\n\nNext Steps:\n1. ✓ Fix/implement feature\n2. ✓ Create tests\n3. ✓ Run tests (GREEN!)\n4. ✓ Create/update documentation\n5. ⏳ Run 'check_ready_to_commit' to verify\n6. ⏳ Run 'commit_and_push'\n7. ⏳ Run 'perform_release'\n8. ⏳ Mark as complete with 'complete_task'`
372
381
  );
373
382
  }
374
383
 
@@ -443,8 +452,7 @@ async function handleCommitAndPush(args, context) {
443
452
  await workflowState.save();
444
453
 
445
454
  return textResponse(
446
- `ℹ️ No changes detected. Assuming commit and push already completed.\nLast commit: ${
447
- effectiveCommitMessage || "(unavailable)"
455
+ `ℹ️ No changes detected. Assuming commit and push already completed.\nLast commit: ${effectiveCommitMessage || "(unavailable)"
448
456
  }\n\nNext: Run 'perform_release' to handle the release and push tags.`
449
457
  );
450
458
  }
@@ -510,8 +518,7 @@ async function handleCommitAndPush(args, context) {
510
518
  await workflowState.save();
511
519
 
512
520
  return textResponse(
513
- `✅ Commit and push completed!\n\nCommit message: ${generatedSummary}\nPushed to: ${
514
- branchForPush || "(default upstream)"
521
+ `✅ Commit and push completed!\n\nCommit message: ${generatedSummary}\nPushed to: ${branchForPush || "(default upstream)"
515
522
  }\n\nNext: Run 'perform_release' to handle the release and push tags.`
516
523
  );
517
524
  }
@@ -772,7 +779,11 @@ async function handleProjectSummaryData(workflowState) {
772
779
  async function handleProjectSummaryDb(workflowState) {
773
780
  const { getSummaryForUser } = await import("../db/index.js");
774
781
  const userId = process.env.DEV_WORKFLOW_USER_ID || "default";
775
- const summary = getSummaryForUser(userId);
782
+
783
+ // Calculate project root from state file path: <root>/.state/users/<user>/workflow-state.json
784
+ const projectPath = path.dirname(path.dirname(path.dirname(path.dirname(workflowState.stateFile))));
785
+
786
+ const summary = await getSummaryForUser(userId, projectPath);
776
787
  if (!summary) {
777
788
  return textResponse("📜 No project summary in database yet.");
778
789
  }
@@ -791,7 +802,7 @@ async function handleRerunWorkflow(workflowState) {
791
802
 
792
803
  // Reset all progress flags but preserve history
793
804
  workflowState.reset();
794
-
805
+
795
806
  // Restore task context after reset
796
807
  workflowState.state.currentPhase = "coding";
797
808
  workflowState.state.taskDescription = currentDescription;
package/vite.config.js CHANGED
@@ -34,6 +34,14 @@ export default defineConfig({
34
34
  'os',
35
35
  'process',
36
36
  'child_process',
37
+ 'events',
38
+ 'net',
39
+ 'tls',
40
+ 'timers',
41
+ 'stream',
42
+ 'crypto',
43
+ 'zlib',
44
+ 'dns',
37
45
  ],
38
46
  },
39
47
  },