@programinglive/dev-workflow-mcp-server 1.5.1 → 1.5.2

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.
Files changed (78) hide show
  1. package/.agent/workflows/dev-workflow-bugfix.md +250 -250
  2. package/.agent/workflows/dev-workflow-feature.md +201 -201
  3. package/.agent/workflows/dev-workflow-full-cycle.md +400 -400
  4. package/.agent/workflows/dev-workflow-refactor.md +238 -238
  5. package/.github/ISSUE_TEMPLATE/bug_report.md +34 -34
  6. package/.github/ISSUE_TEMPLATE/feature_request.md +25 -25
  7. package/.github/pull_request_template.md +22 -22
  8. package/.github/workflows/npm-publish.yml +50 -50
  9. package/.husky/commit-msg +0 -0
  10. package/CHANGELOG.md +749 -739
  11. package/CODE_OF_CONDUCT.md +79 -79
  12. package/CONTRIBUTING.md +60 -60
  13. package/LICENSE +21 -21
  14. package/README.md +632 -632
  15. package/SECURITY.md +20 -20
  16. package/db/index.js +204 -204
  17. package/docs/NETLIFY_DEPLOYMENT.md +125 -125
  18. package/docs/PLESK_DEPLOYMENT.md +170 -170
  19. package/docs/WORKFLOW-BEST-PRACTICES.md +58 -58
  20. package/docs/antigravity/EXAMPLES.md +535 -535
  21. package/docs/antigravity/GETTING-STARTED.md +292 -292
  22. package/docs/antigravity/TROUBLESHOOTING.md +742 -742
  23. package/docs/antigravity/WALKTHROUGH.md +25 -25
  24. package/docs/antigravity/WORKFLOW-TEMPLATES.md +670 -670
  25. package/docs/product/PRD.md +67 -67
  26. package/docs/release-notes/RELEASE_NOTES.md +226 -226
  27. package/docs/web-dashboard.md +175 -175
  28. package/exec.js +49 -49
  29. package/index.js +279 -279
  30. package/install.js +73 -73
  31. package/package.json +4 -4
  32. package/release-wrapper.js +192 -192
  33. package/scripts/build-docs.js +63 -63
  34. package/scripts/hello-world.js +1 -1
  35. package/scripts/release.cjs +252 -252
  36. package/scripts/update-release-notes.cjs +178 -178
  37. package/server.json +23 -23
  38. package/tailwind.config.js +8 -8
  39. package/tests/build.test.js +83 -91
  40. package/tests/exec.test.js +35 -35
  41. package/tests/handlers.test.js +1058 -1058
  42. package/tests/hello-world.test.js +13 -13
  43. package/tests/mcpRegistry.test.js +65 -65
  44. package/tests/release-wrapper.test.js +107 -107
  45. package/tests/workflowState.test.js +505 -505
  46. package/tools/definitions.js +332 -332
  47. package/tools/handlers.js +1019 -1019
  48. package/vite.config.js +43 -43
  49. package/vite.web.config.js +23 -23
  50. package/web/README.md +36 -36
  51. package/web/app/docs/page.tsx +202 -202
  52. package/web/app/globals.css +90 -90
  53. package/web/app/layout.tsx +36 -36
  54. package/web/app/page.tsx +15 -15
  55. package/web/components/ApiReference.tsx +20 -20
  56. package/web/components/Features.tsx +61 -61
  57. package/web/components/Footer.tsx +9 -9
  58. package/web/components/Hero.tsx +96 -97
  59. package/web/components/History.tsx +143 -143
  60. package/web/components/Navbar.tsx +64 -64
  61. package/web/components/Terminal.tsx +114 -114
  62. package/web/eslint.config.mjs +18 -18
  63. package/web/lib/db.js +131 -131
  64. package/web/lib/docs.js +73 -73
  65. package/web/netlify.toml +3 -6
  66. package/web/next.config.ts +12 -7
  67. package/web/package-lock.json +6560 -6560
  68. package/web/package.json +28 -28
  69. package/web/postcss.config.mjs +9 -9
  70. package/web/server.js +31 -31
  71. package/web/tailwind.config.ts +19 -19
  72. package/web/tsconfig.json +42 -42
  73. package/workflow-state.js +612 -612
  74. package/web/app/api/docs/route.ts +0 -32
  75. package/web/app/api/history/route.ts +0 -12
  76. package/web/app/api/npm-downloads/route.ts +0 -21
  77. package/web/app/api/summary/route.ts +0 -13
  78. package/web/app/api/version/route.ts +0 -8
package/SECURITY.md CHANGED
@@ -1,20 +1,20 @@
1
- # Security Policy
2
-
3
- ## Supported Versions
4
-
5
- We release patches for security vulnerabilities under new minor or patch versions. Always use the latest release.
6
-
7
- ## Reporting a Vulnerability
8
-
9
- If you discover a vulnerability, please email `security@programinglive.com` with:
10
-
11
- - Description of the issue
12
- - Steps to reproduce
13
- - Potential impact
14
- - Suggested remediation (if known)
15
-
16
- We aim to acknowledge reports within 72 hours and will keep you informed as we work on a fix. Please do not disclose the vulnerability publicly until we have released an update.
17
-
18
- ## Disclosure Policy
19
-
20
- Once a fix is available, we will publish a security advisory in the repository releases and notify contributors via the README.
1
+ # Security Policy
2
+
3
+ ## Supported Versions
4
+
5
+ We release patches for security vulnerabilities under new minor or patch versions. Always use the latest release.
6
+
7
+ ## Reporting a Vulnerability
8
+
9
+ If you discover a vulnerability, please email `security@programinglive.com` with:
10
+
11
+ - Description of the issue
12
+ - Steps to reproduce
13
+ - Potential impact
14
+ - Suggested remediation (if known)
15
+
16
+ We aim to acknowledge reports within 72 hours and will keep you informed as we work on a fix. Please do not disclose the vulnerability publicly until we have released an update.
17
+
18
+ ## Disclosure Policy
19
+
20
+ Once a fix is available, we will publish a security advisory in the repository releases and notify contributors via the README.
package/db/index.js CHANGED
@@ -1,204 +1,204 @@
1
- import Database from "better-sqlite3";
2
- import { existsSync } from "fs";
3
- import path from "path";
4
- import { fileURLToPath } from "url";
5
-
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
- };
14
-
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);
21
- }
22
- return path.join(projectRoot, ".state", DB_FILENAME);
23
- }
24
-
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();
32
- }
33
- return db;
34
- }
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)`;
64
-
65
- db.exec(createHistory);
66
- db.exec(createSummary);
67
- db.exec(idxHistory);
68
- db.exec(idxSummary);
69
- }
70
-
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);
89
- }
90
-
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
- );
127
- }
128
-
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
- };
142
- }
143
-
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 };
156
- }
157
-
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
- };
187
- }
188
-
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 }));
204
- }
1
+ import Database from "better-sqlite3";
2
+ import { existsSync } from "fs";
3
+ import path from "path";
4
+ import { fileURLToPath } from "url";
5
+
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
+ };
14
+
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);
21
+ }
22
+ return path.join(projectRoot, ".state", DB_FILENAME);
23
+ }
24
+
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();
32
+ }
33
+ return db;
34
+ }
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)`;
64
+
65
+ db.exec(createHistory);
66
+ db.exec(createSummary);
67
+ db.exec(idxHistory);
68
+ db.exec(idxSummary);
69
+ }
70
+
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);
89
+ }
90
+
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
+ );
127
+ }
128
+
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
+ };
142
+ }
143
+
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 };
156
+ }
157
+
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
+ };
187
+ }
188
+
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 }));
204
+ }