@pixelbyte-software/pixcode 1.30.1 → 1.31.0

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 (205) hide show
  1. package/LICENSE +718 -718
  2. package/README.de.md +248 -248
  3. package/README.ja.md +240 -240
  4. package/README.ko.md +240 -240
  5. package/README.md +295 -285
  6. package/README.ru.md +248 -248
  7. package/README.tr.md +250 -250
  8. package/README.zh-CN.md +240 -240
  9. package/dist/api-docs.html +879 -879
  10. package/dist/assets/index-BRRJ47XQ.css +32 -0
  11. package/dist/assets/index-EQohwyiC.js +837 -0
  12. package/dist/clear-cache.html +85 -85
  13. package/dist/convert-icons.md +52 -52
  14. package/dist/favicon.png +0 -0
  15. package/dist/favicon.svg +7 -8
  16. package/dist/generate-icons.js +48 -48
  17. package/dist/icons/codex-white.svg +3 -3
  18. package/dist/icons/codex.svg +3 -3
  19. package/dist/icons/cursor-white.svg +11 -11
  20. package/dist/icons/icon-128x128.png +0 -0
  21. package/dist/icons/icon-128x128.svg +9 -12
  22. package/dist/icons/icon-144x144.png +0 -0
  23. package/dist/icons/icon-144x144.svg +9 -12
  24. package/dist/icons/icon-152x152.png +0 -0
  25. package/dist/icons/icon-152x152.svg +9 -12
  26. package/dist/icons/icon-192x192.png +0 -0
  27. package/dist/icons/icon-192x192.svg +9 -12
  28. package/dist/icons/icon-384x384.png +0 -0
  29. package/dist/icons/icon-384x384.svg +9 -12
  30. package/dist/icons/icon-512x512.png +0 -0
  31. package/dist/icons/icon-512x512.svg +9 -12
  32. package/dist/icons/icon-72x72.png +0 -0
  33. package/dist/icons/icon-72x72.svg +9 -12
  34. package/dist/icons/icon-96x96.png +0 -0
  35. package/dist/icons/icon-96x96.svg +9 -12
  36. package/dist/icons/icon-template.svg +9 -12
  37. package/dist/icons/qwen-ai-icon.png +0 -0
  38. package/dist/index.html +59 -49
  39. package/dist/logo.png +0 -0
  40. package/dist/logo.svg +11 -16
  41. package/dist/manifest.json +60 -60
  42. package/dist/sw.js +124 -124
  43. package/dist-server/server/cli.js +100 -97
  44. package/dist-server/server/cli.js.map +1 -1
  45. package/dist-server/server/daemon/manager.js +33 -33
  46. package/dist-server/server/daemon-manager.js +62 -62
  47. package/dist-server/server/database/db.js +114 -22
  48. package/dist-server/server/database/db.js.map +1 -1
  49. package/dist-server/server/database/schema.js +122 -89
  50. package/dist-server/server/database/schema.js.map +1 -1
  51. package/dist-server/server/gemini-cli.js +6 -1
  52. package/dist-server/server/gemini-cli.js.map +1 -1
  53. package/dist-server/server/index.js +234 -65
  54. package/dist-server/server/index.js.map +1 -1
  55. package/dist-server/server/modules/providers/list/claude/claude-auth.provider.js +29 -2
  56. package/dist-server/server/modules/providers/list/claude/claude-auth.provider.js.map +1 -1
  57. package/dist-server/server/modules/providers/list/codex/codex-auth.provider.js +22 -2
  58. package/dist-server/server/modules/providers/list/codex/codex-auth.provider.js.map +1 -1
  59. package/dist-server/server/modules/providers/list/cursor/cursor-auth.provider.js +2 -2
  60. package/dist-server/server/modules/providers/list/cursor/cursor-auth.provider.js.map +1 -1
  61. package/dist-server/server/modules/providers/list/gemini/gemini-auth.provider.js +14 -2
  62. package/dist-server/server/modules/providers/list/gemini/gemini-auth.provider.js.map +1 -1
  63. package/dist-server/server/modules/providers/list/qwen/qwen-auth.provider.js +132 -0
  64. package/dist-server/server/modules/providers/list/qwen/qwen-auth.provider.js.map +1 -0
  65. package/dist-server/server/modules/providers/list/qwen/qwen-mcp.provider.js +87 -0
  66. package/dist-server/server/modules/providers/list/qwen/qwen-mcp.provider.js.map +1 -0
  67. package/dist-server/server/modules/providers/list/qwen/qwen-sessions.provider.js +201 -0
  68. package/dist-server/server/modules/providers/list/qwen/qwen-sessions.provider.js.map +1 -0
  69. package/dist-server/server/modules/providers/list/qwen/qwen.provider.js +19 -0
  70. package/dist-server/server/modules/providers/list/qwen/qwen.provider.js.map +1 -0
  71. package/dist-server/server/modules/providers/provider.registry.js +2 -0
  72. package/dist-server/server/modules/providers/provider.registry.js.map +1 -1
  73. package/dist-server/server/modules/providers/provider.routes.js +310 -1
  74. package/dist-server/server/modules/providers/provider.routes.js.map +1 -1
  75. package/dist-server/server/projects.js +197 -6
  76. package/dist-server/server/projects.js.map +1 -1
  77. package/dist-server/server/qwen-code-cli.js +350 -0
  78. package/dist-server/server/qwen-code-cli.js.map +1 -0
  79. package/dist-server/server/qwen-response-handler.js +70 -0
  80. package/dist-server/server/qwen-response-handler.js.map +1 -0
  81. package/dist-server/server/routes/commands.js +25 -25
  82. package/dist-server/server/routes/git.js +17 -17
  83. package/dist-server/server/routes/network.js +116 -0
  84. package/dist-server/server/routes/network.js.map +1 -0
  85. package/dist-server/server/routes/projects.js +43 -0
  86. package/dist-server/server/routes/projects.js.map +1 -1
  87. package/dist-server/server/routes/qwen.js +23 -0
  88. package/dist-server/server/routes/qwen.js.map +1 -0
  89. package/dist-server/server/routes/taskmaster.js +419 -419
  90. package/dist-server/server/routes/telegram.js +119 -0
  91. package/dist-server/server/routes/telegram.js.map +1 -0
  92. package/dist-server/server/services/external-access.js +228 -0
  93. package/dist-server/server/services/external-access.js.map +1 -0
  94. package/dist-server/server/services/install-jobs.js +394 -0
  95. package/dist-server/server/services/install-jobs.js.map +1 -0
  96. package/dist-server/server/services/notification-orchestrator.js +19 -5
  97. package/dist-server/server/services/notification-orchestrator.js.map +1 -1
  98. package/dist-server/server/services/provider-credentials.js +154 -0
  99. package/dist-server/server/services/provider-credentials.js.map +1 -0
  100. package/dist-server/server/services/provider-models.js +218 -0
  101. package/dist-server/server/services/provider-models.js.map +1 -0
  102. package/dist-server/server/services/telegram/bot.js +259 -0
  103. package/dist-server/server/services/telegram/bot.js.map +1 -0
  104. package/dist-server/server/services/telegram/translations.js +160 -0
  105. package/dist-server/server/services/telegram/translations.js.map +1 -0
  106. package/dist-server/server/utils/port-access.js +196 -0
  107. package/dist-server/server/utils/port-access.js.map +1 -0
  108. package/dist-server/shared/modelConstants.js +18 -0
  109. package/dist-server/shared/modelConstants.js.map +1 -1
  110. package/package.json +177 -168
  111. package/scripts/fix-node-pty.js +67 -67
  112. package/server/claude-sdk.js +834 -834
  113. package/server/cli.js +940 -937
  114. package/server/constants/config.js +4 -4
  115. package/server/cursor-cli.js +342 -342
  116. package/server/daemon/manager.js +564 -564
  117. package/server/daemon-manager.js +920 -920
  118. package/server/database/db.js +696 -593
  119. package/server/database/schema.js +138 -102
  120. package/server/gemini-cli.js +475 -469
  121. package/server/gemini-response-handler.js +79 -79
  122. package/server/index.js +2730 -2557
  123. package/server/load-env.js +34 -34
  124. package/server/middleware/auth.js +132 -132
  125. package/server/modules/providers/list/claude/claude-auth.provider.ts +145 -123
  126. package/server/modules/providers/list/claude/claude-mcp.provider.ts +135 -135
  127. package/server/modules/providers/list/claude/claude-sessions.provider.ts +306 -306
  128. package/server/modules/providers/list/claude/claude.provider.ts +15 -15
  129. package/server/modules/providers/list/codex/codex-auth.provider.ts +115 -100
  130. package/server/modules/providers/list/codex/codex-mcp.provider.ts +135 -135
  131. package/server/modules/providers/list/codex/codex-sessions.provider.ts +319 -319
  132. package/server/modules/providers/list/codex/codex.provider.ts +15 -15
  133. package/server/modules/providers/list/cursor/cursor-auth.provider.ts +143 -143
  134. package/server/modules/providers/list/cursor/cursor-mcp.provider.ts +108 -108
  135. package/server/modules/providers/list/cursor/cursor-sessions.provider.ts +421 -421
  136. package/server/modules/providers/list/cursor/cursor.provider.ts +15 -15
  137. package/server/modules/providers/list/gemini/gemini-auth.provider.ts +163 -151
  138. package/server/modules/providers/list/gemini/gemini-mcp.provider.ts +110 -110
  139. package/server/modules/providers/list/gemini/gemini-sessions.provider.ts +227 -227
  140. package/server/modules/providers/list/gemini/gemini.provider.ts +15 -15
  141. package/server/modules/providers/list/qwen/qwen-auth.provider.ts +145 -0
  142. package/server/modules/providers/list/qwen/qwen-mcp.provider.ts +114 -0
  143. package/server/modules/providers/list/qwen/qwen-sessions.provider.ts +218 -0
  144. package/server/modules/providers/list/qwen/qwen.provider.ts +21 -0
  145. package/server/modules/providers/provider.registry.ts +38 -36
  146. package/server/modules/providers/provider.routes.ts +583 -217
  147. package/server/modules/providers/services/mcp.service.ts +94 -94
  148. package/server/modules/providers/services/provider-auth.service.ts +26 -26
  149. package/server/modules/providers/services/sessions.service.ts +45 -45
  150. package/server/modules/providers/shared/base/abstract.provider.ts +20 -20
  151. package/server/modules/providers/shared/mcp/mcp.provider.ts +151 -151
  152. package/server/modules/providers/tests/mcp.test.ts +293 -293
  153. package/server/openai-codex.js +426 -426
  154. package/server/projects.js +2993 -2792
  155. package/server/qwen-code-cli.js +392 -0
  156. package/server/qwen-response-handler.js +73 -0
  157. package/server/routes/agent.js +1245 -1245
  158. package/server/routes/auth.js +134 -134
  159. package/server/routes/codex.js +19 -19
  160. package/server/routes/commands.js +554 -554
  161. package/server/routes/cursor.js +52 -52
  162. package/server/routes/gemini.js +24 -24
  163. package/server/routes/git.js +1488 -1488
  164. package/server/routes/mcp-utils.js +31 -31
  165. package/server/routes/messages.js +61 -61
  166. package/server/routes/network.js +128 -0
  167. package/server/routes/plugins.js +307 -307
  168. package/server/routes/projects.js +675 -627
  169. package/server/routes/qwen.js +27 -0
  170. package/server/routes/settings.js +286 -286
  171. package/server/routes/taskmaster.js +1471 -1471
  172. package/server/routes/telegram.js +125 -0
  173. package/server/routes/user.js +123 -123
  174. package/server/services/external-access.js +240 -0
  175. package/server/services/install-jobs.js +410 -0
  176. package/server/services/notification-orchestrator.js +242 -227
  177. package/server/services/provider-credentials.js +151 -0
  178. package/server/services/provider-models.js +225 -0
  179. package/server/services/telegram/bot.js +280 -0
  180. package/server/services/telegram/translations.js +170 -0
  181. package/server/services/vapid-keys.js +35 -35
  182. package/server/sessionManager.js +225 -225
  183. package/server/shared/interfaces.ts +54 -54
  184. package/server/shared/types.ts +172 -172
  185. package/server/shared/utils.ts +193 -193
  186. package/server/tsconfig.json +36 -36
  187. package/server/utils/colors.js +21 -21
  188. package/server/utils/commandParser.js +303 -303
  189. package/server/utils/frontmatter.js +18 -18
  190. package/server/utils/gitConfig.js +34 -34
  191. package/server/utils/mcp-detector.js +147 -147
  192. package/server/utils/plugin-loader.js +457 -457
  193. package/server/utils/plugin-process-manager.js +184 -184
  194. package/server/utils/port-access.js +209 -0
  195. package/server/utils/runtime-paths.js +37 -37
  196. package/server/utils/taskmaster-websocket.js +128 -128
  197. package/server/utils/url-detection.js +71 -71
  198. package/server/vite-daemon.js +78 -78
  199. package/shared/modelConstants.js +117 -97
  200. package/shared/networkHosts.js +22 -22
  201. package/dist/assets/index-C2c9QNwK.css +0 -32
  202. package/dist/assets/index-DyXDZED-.js +0 -1277
  203. package/dist-server/server/routes/cli-auth.js +0 -25
  204. package/dist-server/server/routes/cli-auth.js.map +0 -1
  205. package/server/routes/cli-auth.js +0 -27
@@ -1,1471 +1,1471 @@
1
- /**
2
- * TASKMASTER API ROUTES
3
- * ====================
4
- *
5
- * This module provides API endpoints for TaskMaster integration including:
6
- * - .taskmaster folder detection in project directories
7
- * - MCP server configuration detection
8
- * - TaskMaster state and metadata management
9
- */
10
-
11
- import express from 'express';
12
- import fs from 'fs';
13
- import path from 'path';
14
- import { promises as fsPromises } from 'fs';
15
- import { spawn } from 'child_process';
16
- import { extractProjectDirectory } from '../projects.js';
17
- import { detectTaskMasterMCPServer } from '../utils/mcp-detector.js';
18
- import { broadcastTaskMasterProjectUpdate, broadcastTaskMasterTasksUpdate } from '../utils/taskmaster-websocket.js';
19
-
20
- const router = express.Router();
21
-
22
- /**
23
- * Check if TaskMaster CLI is installed globally
24
- * @returns {Promise<Object>} Installation status result
25
- */
26
- async function checkTaskMasterInstallation() {
27
- return new Promise((resolve) => {
28
- // Check if task-master command is available
29
- const child = spawn('which', ['task-master'], {
30
- stdio: ['ignore', 'pipe', 'pipe'],
31
- shell: true
32
- });
33
-
34
- let output = '';
35
- let errorOutput = '';
36
-
37
- child.stdout.on('data', (data) => {
38
- output += data.toString();
39
- });
40
-
41
- child.stderr.on('data', (data) => {
42
- errorOutput += data.toString();
43
- });
44
-
45
- child.on('close', (code) => {
46
- if (code === 0 && output.trim()) {
47
- // TaskMaster is installed, get version
48
- const versionChild = spawn('task-master', ['--version'], {
49
- stdio: ['ignore', 'pipe', 'pipe'],
50
- shell: true
51
- });
52
-
53
- let versionOutput = '';
54
-
55
- versionChild.stdout.on('data', (data) => {
56
- versionOutput += data.toString();
57
- });
58
-
59
- versionChild.on('close', (versionCode) => {
60
- resolve({
61
- isInstalled: true,
62
- installPath: output.trim(),
63
- version: versionCode === 0 ? versionOutput.trim() : 'unknown',
64
- reason: null
65
- });
66
- });
67
-
68
- versionChild.on('error', () => {
69
- resolve({
70
- isInstalled: true,
71
- installPath: output.trim(),
72
- version: 'unknown',
73
- reason: null
74
- });
75
- });
76
- } else {
77
- resolve({
78
- isInstalled: false,
79
- installPath: null,
80
- version: null,
81
- reason: 'TaskMaster CLI not found in PATH'
82
- });
83
- }
84
- });
85
-
86
- child.on('error', (error) => {
87
- resolve({
88
- isInstalled: false,
89
- installPath: null,
90
- version: null,
91
- reason: `Error checking installation: ${error.message}`
92
- });
93
- });
94
- });
95
- }
96
-
97
- // API Routes
98
-
99
- /**
100
- * GET /api/taskmaster/installation-status
101
- * Check if TaskMaster CLI is installed on the system
102
- */
103
- router.get('/installation-status', async (req, res) => {
104
- try {
105
- const installationStatus = await checkTaskMasterInstallation();
106
-
107
- // Also check for MCP server configuration
108
- const mcpStatus = await detectTaskMasterMCPServer();
109
-
110
- res.json({
111
- success: true,
112
- installation: installationStatus,
113
- mcpServer: mcpStatus,
114
- isReady: installationStatus.isInstalled && mcpStatus.hasMCPServer
115
- });
116
- } catch (error) {
117
- console.error('Error checking TaskMaster installation:', error);
118
- res.status(500).json({
119
- success: false,
120
- error: 'Failed to check TaskMaster installation status',
121
- installation: {
122
- isInstalled: false,
123
- reason: `Server error: ${error.message}`
124
- },
125
- mcpServer: {
126
- hasMCPServer: false,
127
- reason: `Server error: ${error.message}`
128
- },
129
- isReady: false
130
- });
131
- }
132
- });
133
-
134
- /**
135
- * GET /api/taskmaster/tasks/:projectName
136
- * Load actual tasks from .taskmaster/tasks/tasks.json
137
- */
138
- router.get('/tasks/:projectName', async (req, res) => {
139
- try {
140
- const { projectName } = req.params;
141
-
142
- // Get project path
143
- let projectPath;
144
- try {
145
- projectPath = await extractProjectDirectory(projectName);
146
- } catch (error) {
147
- return res.status(404).json({
148
- error: 'Project not found',
149
- message: `Project "${projectName}" does not exist`
150
- });
151
- }
152
-
153
- const taskMasterPath = path.join(projectPath, '.taskmaster');
154
- const tasksFilePath = path.join(taskMasterPath, 'tasks', 'tasks.json');
155
-
156
- // Check if tasks file exists
157
- try {
158
- await fsPromises.access(tasksFilePath);
159
- } catch (error) {
160
- return res.json({
161
- projectName,
162
- tasks: [],
163
- message: 'No tasks.json file found'
164
- });
165
- }
166
-
167
- // Read and parse tasks file
168
- try {
169
- const tasksContent = await fsPromises.readFile(tasksFilePath, 'utf8');
170
- const tasksData = JSON.parse(tasksContent);
171
-
172
- let tasks = [];
173
- let currentTag = 'master';
174
-
175
- // Handle both tagged and legacy formats
176
- if (Array.isArray(tasksData)) {
177
- // Legacy format
178
- tasks = tasksData;
179
- } else if (tasksData.tasks) {
180
- // Simple format with tasks array
181
- tasks = tasksData.tasks;
182
- } else {
183
- // Tagged format - get tasks from current tag or master
184
- if (tasksData[currentTag] && tasksData[currentTag].tasks) {
185
- tasks = tasksData[currentTag].tasks;
186
- } else if (tasksData.master && tasksData.master.tasks) {
187
- tasks = tasksData.master.tasks;
188
- } else {
189
- // Get tasks from first available tag
190
- const firstTag = Object.keys(tasksData).find(key =>
191
- tasksData[key].tasks && Array.isArray(tasksData[key].tasks)
192
- );
193
- if (firstTag) {
194
- tasks = tasksData[firstTag].tasks;
195
- currentTag = firstTag;
196
- }
197
- }
198
- }
199
-
200
- // Transform tasks to ensure all have required fields
201
- const transformedTasks = tasks.map(task => ({
202
- id: task.id,
203
- title: task.title || 'Untitled Task',
204
- description: task.description || '',
205
- status: task.status || 'pending',
206
- priority: task.priority || 'medium',
207
- dependencies: task.dependencies || [],
208
- createdAt: task.createdAt || task.created || new Date().toISOString(),
209
- updatedAt: task.updatedAt || task.updated || new Date().toISOString(),
210
- details: task.details || '',
211
- testStrategy: task.testStrategy || task.test_strategy || '',
212
- subtasks: task.subtasks || []
213
- }));
214
-
215
- res.json({
216
- projectName,
217
- projectPath,
218
- tasks: transformedTasks,
219
- currentTag,
220
- totalTasks: transformedTasks.length,
221
- tasksByStatus: {
222
- pending: transformedTasks.filter(t => t.status === 'pending').length,
223
- 'in-progress': transformedTasks.filter(t => t.status === 'in-progress').length,
224
- done: transformedTasks.filter(t => t.status === 'done').length,
225
- review: transformedTasks.filter(t => t.status === 'review').length,
226
- deferred: transformedTasks.filter(t => t.status === 'deferred').length,
227
- cancelled: transformedTasks.filter(t => t.status === 'cancelled').length
228
- },
229
- timestamp: new Date().toISOString()
230
- });
231
-
232
- } catch (parseError) {
233
- console.error('Failed to parse tasks.json:', parseError);
234
- return res.status(500).json({
235
- error: 'Failed to parse tasks file',
236
- message: parseError.message
237
- });
238
- }
239
-
240
- } catch (error) {
241
- console.error('TaskMaster tasks loading error:', error);
242
- res.status(500).json({
243
- error: 'Failed to load TaskMaster tasks',
244
- message: error.message
245
- });
246
- }
247
- });
248
-
249
- /**
250
- * GET /api/taskmaster/prd/:projectName
251
- * List all PRD files in the project's .taskmaster/docs directory
252
- */
253
- router.get('/prd/:projectName', async (req, res) => {
254
- try {
255
- const { projectName } = req.params;
256
-
257
- // Get project path
258
- let projectPath;
259
- try {
260
- projectPath = await extractProjectDirectory(projectName);
261
- } catch (error) {
262
- return res.status(404).json({
263
- error: 'Project not found',
264
- message: `Project "${projectName}" does not exist`
265
- });
266
- }
267
-
268
- const docsPath = path.join(projectPath, '.taskmaster', 'docs');
269
-
270
- // Check if docs directory exists
271
- try {
272
- await fsPromises.access(docsPath, fs.constants.R_OK);
273
- } catch (error) {
274
- return res.json({
275
- projectName,
276
- prdFiles: [],
277
- message: 'No .taskmaster/docs directory found'
278
- });
279
- }
280
-
281
- // Read directory and filter for PRD files
282
- try {
283
- const files = await fsPromises.readdir(docsPath);
284
- const prdFiles = [];
285
-
286
- for (const file of files) {
287
- const filePath = path.join(docsPath, file);
288
- const stats = await fsPromises.stat(filePath);
289
-
290
- if (stats.isFile() && (file.endsWith('.txt') || file.endsWith('.md'))) {
291
- prdFiles.push({
292
- name: file,
293
- path: path.relative(projectPath, filePath),
294
- size: stats.size,
295
- modified: stats.mtime.toISOString(),
296
- created: stats.birthtime.toISOString()
297
- });
298
- }
299
- }
300
-
301
- res.json({
302
- projectName,
303
- projectPath,
304
- prdFiles: prdFiles.sort((a, b) => new Date(b.modified) - new Date(a.modified)),
305
- timestamp: new Date().toISOString()
306
- });
307
-
308
- } catch (readError) {
309
- console.error('Error reading docs directory:', readError);
310
- return res.status(500).json({
311
- error: 'Failed to read PRD files',
312
- message: readError.message
313
- });
314
- }
315
-
316
- } catch (error) {
317
- console.error('PRD list error:', error);
318
- res.status(500).json({
319
- error: 'Failed to list PRD files',
320
- message: error.message
321
- });
322
- }
323
- });
324
-
325
- /**
326
- * POST /api/taskmaster/prd/:projectName
327
- * Create or update a PRD file in the project's .taskmaster/docs directory
328
- */
329
- router.post('/prd/:projectName', async (req, res) => {
330
- try {
331
- const { projectName } = req.params;
332
- const { fileName, content } = req.body;
333
-
334
- if (!fileName || !content) {
335
- return res.status(400).json({
336
- error: 'Missing required fields',
337
- message: 'fileName and content are required'
338
- });
339
- }
340
-
341
- // Validate filename
342
- if (!fileName.match(/^[\w\-. ]+\.(txt|md)$/)) {
343
- return res.status(400).json({
344
- error: 'Invalid filename',
345
- message: 'Filename must end with .txt or .md and contain only alphanumeric characters, spaces, dots, and dashes'
346
- });
347
- }
348
-
349
- // Get project path
350
- let projectPath;
351
- try {
352
- projectPath = await extractProjectDirectory(projectName);
353
- } catch (error) {
354
- return res.status(404).json({
355
- error: 'Project not found',
356
- message: `Project "${projectName}" does not exist`
357
- });
358
- }
359
-
360
- const docsPath = path.join(projectPath, '.taskmaster', 'docs');
361
- const filePath = path.join(docsPath, fileName);
362
-
363
- // Ensure docs directory exists
364
- try {
365
- await fsPromises.mkdir(docsPath, { recursive: true });
366
- } catch (error) {
367
- console.error('Failed to create docs directory:', error);
368
- return res.status(500).json({
369
- error: 'Failed to create directory',
370
- message: error.message
371
- });
372
- }
373
-
374
- // Write the PRD file
375
- try {
376
- await fsPromises.writeFile(filePath, content, 'utf8');
377
-
378
- // Get file stats
379
- const stats = await fsPromises.stat(filePath);
380
-
381
- res.json({
382
- projectName,
383
- projectPath,
384
- fileName,
385
- filePath: path.relative(projectPath, filePath),
386
- size: stats.size,
387
- created: stats.birthtime.toISOString(),
388
- modified: stats.mtime.toISOString(),
389
- message: 'PRD file saved successfully',
390
- timestamp: new Date().toISOString()
391
- });
392
-
393
- } catch (writeError) {
394
- console.error('Failed to write PRD file:', writeError);
395
- return res.status(500).json({
396
- error: 'Failed to write PRD file',
397
- message: writeError.message
398
- });
399
- }
400
-
401
- } catch (error) {
402
- console.error('PRD create/update error:', error);
403
- res.status(500).json({
404
- error: 'Failed to create/update PRD file',
405
- message: error.message
406
- });
407
- }
408
- });
409
-
410
- /**
411
- * GET /api/taskmaster/prd/:projectName/:fileName
412
- * Get content of a specific PRD file
413
- */
414
- router.get('/prd/:projectName/:fileName', async (req, res) => {
415
- try {
416
- const { projectName, fileName } = req.params;
417
-
418
- // Get project path
419
- let projectPath;
420
- try {
421
- projectPath = await extractProjectDirectory(projectName);
422
- } catch (error) {
423
- return res.status(404).json({
424
- error: 'Project not found',
425
- message: `Project "${projectName}" does not exist`
426
- });
427
- }
428
-
429
- const filePath = path.join(projectPath, '.taskmaster', 'docs', fileName);
430
-
431
- // Check if file exists
432
- try {
433
- await fsPromises.access(filePath, fs.constants.R_OK);
434
- } catch (error) {
435
- return res.status(404).json({
436
- error: 'PRD file not found',
437
- message: `File "${fileName}" does not exist`
438
- });
439
- }
440
-
441
- // Read file content
442
- try {
443
- const content = await fsPromises.readFile(filePath, 'utf8');
444
- const stats = await fsPromises.stat(filePath);
445
-
446
- res.json({
447
- projectName,
448
- projectPath,
449
- fileName,
450
- filePath: path.relative(projectPath, filePath),
451
- content,
452
- size: stats.size,
453
- created: stats.birthtime.toISOString(),
454
- modified: stats.mtime.toISOString(),
455
- timestamp: new Date().toISOString()
456
- });
457
-
458
- } catch (readError) {
459
- console.error('Failed to read PRD file:', readError);
460
- return res.status(500).json({
461
- error: 'Failed to read PRD file',
462
- message: readError.message
463
- });
464
- }
465
-
466
- } catch (error) {
467
- console.error('PRD read error:', error);
468
- res.status(500).json({
469
- error: 'Failed to read PRD file',
470
- message: error.message
471
- });
472
- }
473
- });
474
-
475
- /**
476
- * POST /api/taskmaster/init/:projectName
477
- * Initialize TaskMaster in a project
478
- */
479
- router.post('/init/:projectName', async (req, res) => {
480
- try {
481
- const { projectName } = req.params;
482
-
483
- // Get project path
484
- let projectPath;
485
- try {
486
- projectPath = await extractProjectDirectory(projectName);
487
- } catch (error) {
488
- return res.status(404).json({
489
- error: 'Project not found',
490
- message: `Project "${projectName}" does not exist`
491
- });
492
- }
493
-
494
- // Check if TaskMaster is already initialized
495
- const taskMasterPath = path.join(projectPath, '.taskmaster');
496
- try {
497
- await fsPromises.access(taskMasterPath, fs.constants.F_OK);
498
- return res.status(400).json({
499
- error: 'TaskMaster already initialized',
500
- message: 'TaskMaster is already configured for this project'
501
- });
502
- } catch (error) {
503
- // Directory doesn't exist, we can proceed
504
- }
505
-
506
- // Run taskmaster init command
507
- const initProcess = spawn('npx', ['task-master', 'init'], {
508
- cwd: projectPath,
509
- stdio: ['pipe', 'pipe', 'pipe']
510
- });
511
-
512
- let stdout = '';
513
- let stderr = '';
514
-
515
- initProcess.stdout.on('data', (data) => {
516
- stdout += data.toString();
517
- });
518
-
519
- initProcess.stderr.on('data', (data) => {
520
- stderr += data.toString();
521
- });
522
-
523
- initProcess.on('close', (code) => {
524
- if (code === 0) {
525
- // Broadcast TaskMaster project update via WebSocket
526
- if (req.app.locals.wss) {
527
- broadcastTaskMasterProjectUpdate(
528
- req.app.locals.wss,
529
- projectName,
530
- { hasTaskmaster: true, status: 'initialized' }
531
- );
532
- }
533
-
534
- res.json({
535
- projectName,
536
- projectPath,
537
- message: 'TaskMaster initialized successfully',
538
- output: stdout,
539
- timestamp: new Date().toISOString()
540
- });
541
- } else {
542
- console.error('TaskMaster init failed:', stderr);
543
- res.status(500).json({
544
- error: 'Failed to initialize TaskMaster',
545
- message: stderr || stdout,
546
- code
547
- });
548
- }
549
- });
550
-
551
- // Send 'yes' responses to automated prompts
552
- initProcess.stdin.write('yes\n');
553
- initProcess.stdin.end();
554
-
555
- } catch (error) {
556
- console.error('TaskMaster init error:', error);
557
- res.status(500).json({
558
- error: 'Failed to initialize TaskMaster',
559
- message: error.message
560
- });
561
- }
562
- });
563
-
564
- /**
565
- * POST /api/taskmaster/add-task/:projectName
566
- * Add a new task to the project
567
- */
568
- router.post('/add-task/:projectName', async (req, res) => {
569
- try {
570
- const { projectName } = req.params;
571
- const { prompt, title, description, priority = 'medium', dependencies } = req.body;
572
-
573
- if (!prompt && (!title || !description)) {
574
- return res.status(400).json({
575
- error: 'Missing required parameters',
576
- message: 'Either "prompt" or both "title" and "description" are required'
577
- });
578
- }
579
-
580
- // Get project path
581
- let projectPath;
582
- try {
583
- projectPath = await extractProjectDirectory(projectName);
584
- } catch (error) {
585
- return res.status(404).json({
586
- error: 'Project not found',
587
- message: `Project "${projectName}" does not exist`
588
- });
589
- }
590
-
591
- // Build the task-master add-task command
592
- const args = ['task-master-ai', 'add-task'];
593
-
594
- if (prompt) {
595
- args.push('--prompt', prompt);
596
- args.push('--research'); // Use research for AI-generated tasks
597
- } else {
598
- args.push('--prompt', `Create a task titled "${title}" with description: ${description}`);
599
- }
600
-
601
- if (priority) {
602
- args.push('--priority', priority);
603
- }
604
-
605
- if (dependencies) {
606
- args.push('--dependencies', dependencies);
607
- }
608
-
609
- // Run task-master add-task command
610
- const addTaskProcess = spawn('npx', args, {
611
- cwd: projectPath,
612
- stdio: ['pipe', 'pipe', 'pipe']
613
- });
614
-
615
- let stdout = '';
616
- let stderr = '';
617
-
618
- addTaskProcess.stdout.on('data', (data) => {
619
- stdout += data.toString();
620
- });
621
-
622
- addTaskProcess.stderr.on('data', (data) => {
623
- stderr += data.toString();
624
- });
625
-
626
- addTaskProcess.on('close', (code) => {
627
- console.log('Add task process completed with code:', code);
628
- console.log('Stdout:', stdout);
629
- console.log('Stderr:', stderr);
630
-
631
- if (code === 0) {
632
- // Broadcast task update via WebSocket
633
- if (req.app.locals.wss) {
634
- broadcastTaskMasterTasksUpdate(
635
- req.app.locals.wss,
636
- projectName
637
- );
638
- }
639
-
640
- res.json({
641
- projectName,
642
- projectPath,
643
- message: 'Task added successfully',
644
- output: stdout,
645
- timestamp: new Date().toISOString()
646
- });
647
- } else {
648
- console.error('Add task failed:', stderr);
649
- res.status(500).json({
650
- error: 'Failed to add task',
651
- message: stderr || stdout,
652
- code
653
- });
654
- }
655
- });
656
-
657
- addTaskProcess.stdin.end();
658
-
659
- } catch (error) {
660
- console.error('Add task error:', error);
661
- res.status(500).json({
662
- error: 'Failed to add task',
663
- message: error.message
664
- });
665
- }
666
- });
667
-
668
- /**
669
- * PUT /api/taskmaster/update-task/:projectName/:taskId
670
- * Update a specific task using TaskMaster CLI
671
- */
672
- router.put('/update-task/:projectName/:taskId', async (req, res) => {
673
- try {
674
- const { projectName, taskId } = req.params;
675
- const { title, description, status, priority, details } = req.body;
676
-
677
- // Get project path
678
- let projectPath;
679
- try {
680
- projectPath = await extractProjectDirectory(projectName);
681
- } catch (error) {
682
- return res.status(404).json({
683
- error: 'Project not found',
684
- message: `Project "${projectName}" does not exist`
685
- });
686
- }
687
-
688
- // If only updating status, use set-status command
689
- if (status && Object.keys(req.body).length === 1) {
690
- const setStatusProcess = spawn('npx', ['task-master-ai', 'set-status', `--id=${taskId}`, `--status=${status}`], {
691
- cwd: projectPath,
692
- stdio: ['pipe', 'pipe', 'pipe']
693
- });
694
-
695
- let stdout = '';
696
- let stderr = '';
697
-
698
- setStatusProcess.stdout.on('data', (data) => {
699
- stdout += data.toString();
700
- });
701
-
702
- setStatusProcess.stderr.on('data', (data) => {
703
- stderr += data.toString();
704
- });
705
-
706
- setStatusProcess.on('close', (code) => {
707
- if (code === 0) {
708
- // Broadcast task update via WebSocket
709
- if (req.app.locals.wss) {
710
- broadcastTaskMasterTasksUpdate(req.app.locals.wss, projectName);
711
- }
712
-
713
- res.json({
714
- projectName,
715
- projectPath,
716
- taskId,
717
- message: 'Task status updated successfully',
718
- output: stdout,
719
- timestamp: new Date().toISOString()
720
- });
721
- } else {
722
- console.error('Set task status failed:', stderr);
723
- res.status(500).json({
724
- error: 'Failed to update task status',
725
- message: stderr || stdout,
726
- code
727
- });
728
- }
729
- });
730
-
731
- setStatusProcess.stdin.end();
732
- } else {
733
- // For other updates, use update-task command with a prompt describing the changes
734
- const updates = [];
735
- if (title) updates.push(`title: "${title}"`);
736
- if (description) updates.push(`description: "${description}"`);
737
- if (priority) updates.push(`priority: "${priority}"`);
738
- if (details) updates.push(`details: "${details}"`);
739
-
740
- const prompt = `Update task with the following changes: ${updates.join(', ')}`;
741
-
742
- const updateProcess = spawn('npx', ['task-master-ai', 'update-task', `--id=${taskId}`, `--prompt=${prompt}`], {
743
- cwd: projectPath,
744
- stdio: ['pipe', 'pipe', 'pipe']
745
- });
746
-
747
- let stdout = '';
748
- let stderr = '';
749
-
750
- updateProcess.stdout.on('data', (data) => {
751
- stdout += data.toString();
752
- });
753
-
754
- updateProcess.stderr.on('data', (data) => {
755
- stderr += data.toString();
756
- });
757
-
758
- updateProcess.on('close', (code) => {
759
- if (code === 0) {
760
- // Broadcast task update via WebSocket
761
- if (req.app.locals.wss) {
762
- broadcastTaskMasterTasksUpdate(req.app.locals.wss, projectName);
763
- }
764
-
765
- res.json({
766
- projectName,
767
- projectPath,
768
- taskId,
769
- message: 'Task updated successfully',
770
- output: stdout,
771
- timestamp: new Date().toISOString()
772
- });
773
- } else {
774
- console.error('Update task failed:', stderr);
775
- res.status(500).json({
776
- error: 'Failed to update task',
777
- message: stderr || stdout,
778
- code
779
- });
780
- }
781
- });
782
-
783
- updateProcess.stdin.end();
784
- }
785
-
786
- } catch (error) {
787
- console.error('Update task error:', error);
788
- res.status(500).json({
789
- error: 'Failed to update task',
790
- message: error.message
791
- });
792
- }
793
- });
794
-
795
- /**
796
- * POST /api/taskmaster/parse-prd/:projectName
797
- * Parse a PRD file to generate tasks
798
- */
799
- router.post('/parse-prd/:projectName', async (req, res) => {
800
- try {
801
- const { projectName } = req.params;
802
- const { fileName = 'prd.txt', numTasks, append = false } = req.body;
803
-
804
- // Get project path
805
- let projectPath;
806
- try {
807
- projectPath = await extractProjectDirectory(projectName);
808
- } catch (error) {
809
- return res.status(404).json({
810
- error: 'Project not found',
811
- message: `Project "${projectName}" does not exist`
812
- });
813
- }
814
-
815
- const prdPath = path.join(projectPath, '.taskmaster', 'docs', fileName);
816
-
817
- // Check if PRD file exists
818
- try {
819
- await fsPromises.access(prdPath, fs.constants.F_OK);
820
- } catch (error) {
821
- return res.status(404).json({
822
- error: 'PRD file not found',
823
- message: `File "${fileName}" does not exist in .taskmaster/docs/`
824
- });
825
- }
826
-
827
- // Build the command args
828
- const args = ['task-master-ai', 'parse-prd', prdPath];
829
-
830
- if (numTasks) {
831
- args.push('--num-tasks', numTasks.toString());
832
- }
833
-
834
- if (append) {
835
- args.push('--append');
836
- }
837
-
838
- args.push('--research'); // Use research for better PRD parsing
839
-
840
- // Run task-master parse-prd command
841
- const parsePRDProcess = spawn('npx', args, {
842
- cwd: projectPath,
843
- stdio: ['pipe', 'pipe', 'pipe']
844
- });
845
-
846
- let stdout = '';
847
- let stderr = '';
848
-
849
- parsePRDProcess.stdout.on('data', (data) => {
850
- stdout += data.toString();
851
- });
852
-
853
- parsePRDProcess.stderr.on('data', (data) => {
854
- stderr += data.toString();
855
- });
856
-
857
- parsePRDProcess.on('close', (code) => {
858
- if (code === 0) {
859
- // Broadcast task update via WebSocket
860
- if (req.app.locals.wss) {
861
- broadcastTaskMasterTasksUpdate(
862
- req.app.locals.wss,
863
- projectName
864
- );
865
- }
866
-
867
- res.json({
868
- projectName,
869
- projectPath,
870
- prdFile: fileName,
871
- message: 'PRD parsed and tasks generated successfully',
872
- output: stdout,
873
- timestamp: new Date().toISOString()
874
- });
875
- } else {
876
- console.error('Parse PRD failed:', stderr);
877
- res.status(500).json({
878
- error: 'Failed to parse PRD',
879
- message: stderr || stdout,
880
- code
881
- });
882
- }
883
- });
884
-
885
- parsePRDProcess.stdin.end();
886
-
887
- } catch (error) {
888
- console.error('Parse PRD error:', error);
889
- res.status(500).json({
890
- error: 'Failed to parse PRD',
891
- message: error.message
892
- });
893
- }
894
- });
895
-
896
- /**
897
- * GET /api/taskmaster/prd-templates
898
- * Get available PRD templates
899
- */
900
- router.get('/prd-templates', async (req, res) => {
901
- try {
902
- // Return built-in templates
903
- const templates = [
904
- {
905
- id: 'web-app',
906
- name: 'Web Application',
907
- description: 'Template for web application projects with frontend and backend components',
908
- category: 'web',
909
- content: `# Product Requirements Document - Web Application
910
-
911
- ## Overview
912
- **Product Name:** [Your App Name]
913
- **Version:** 1.0
914
- **Date:** ${new Date().toISOString().split('T')[0]}
915
- **Author:** [Your Name]
916
-
917
- ## Executive Summary
918
- Brief description of what this web application will do and why it's needed.
919
-
920
- ## Product Goals
921
- - Goal 1: [Specific measurable goal]
922
- - Goal 2: [Specific measurable goal]
923
- - Goal 3: [Specific measurable goal]
924
-
925
- ## User Stories
926
- ### Core Features
927
- 1. **User Registration & Authentication**
928
- - As a user, I want to create an account so I can access personalized features
929
- - As a user, I want to log in securely so my data is protected
930
- - As a user, I want to reset my password if I forget it
931
-
932
- 2. **Main Application Features**
933
- - As a user, I want to [core feature 1] so I can [benefit]
934
- - As a user, I want to [core feature 2] so I can [benefit]
935
- - As a user, I want to [core feature 3] so I can [benefit]
936
-
937
- 3. **User Interface**
938
- - As a user, I want a responsive design so I can use the app on any device
939
- - As a user, I want intuitive navigation so I can easily find features
940
-
941
- ## Technical Requirements
942
- ### Frontend
943
- - Framework: React/Vue/Angular or vanilla JavaScript
944
- - Styling: CSS framework (Tailwind, Bootstrap, etc.)
945
- - State Management: Redux/Vuex/Context API
946
- - Build Tools: Webpack/Vite
947
- - Testing: Jest/Vitest for unit tests
948
-
949
- ### Backend
950
- - Runtime: Node.js/Python/Java
951
- - Database: PostgreSQL/MySQL/MongoDB
952
- - API: RESTful API or GraphQL
953
- - Authentication: JWT tokens
954
- - Testing: Integration and unit tests
955
-
956
- ### Infrastructure
957
- - Hosting: Cloud provider (AWS, Azure, GCP)
958
- - CI/CD: GitHub Actions/GitLab CI
959
- - Monitoring: Application monitoring tools
960
- - Security: HTTPS, input validation, rate limiting
961
-
962
- ## Success Metrics
963
- - User engagement metrics
964
- - Performance benchmarks (load time < 2s)
965
- - Error rates < 1%
966
- - User satisfaction scores
967
-
968
- ## Timeline
969
- - Phase 1: Core functionality (4-6 weeks)
970
- - Phase 2: Advanced features (2-4 weeks)
971
- - Phase 3: Polish and launch (2 weeks)
972
-
973
- ## Constraints & Assumptions
974
- - Budget constraints
975
- - Technical limitations
976
- - Team size and expertise
977
- - Timeline constraints`
978
- },
979
- {
980
- id: 'api',
981
- name: 'REST API',
982
- description: 'Template for REST API development projects',
983
- category: 'backend',
984
- content: `# Product Requirements Document - REST API
985
-
986
- ## Overview
987
- **API Name:** [Your API Name]
988
- **Version:** v1.0
989
- **Date:** ${new Date().toISOString().split('T')[0]}
990
- **Author:** [Your Name]
991
-
992
- ## Executive Summary
993
- Description of the API's purpose, target users, and primary use cases.
994
-
995
- ## API Goals
996
- - Goal 1: Provide secure data access
997
- - Goal 2: Ensure scalable architecture
998
- - Goal 3: Maintain high availability (99.9% uptime)
999
-
1000
- ## Functional Requirements
1001
- ### Core Endpoints
1002
- 1. **Authentication Endpoints**
1003
- - POST /api/auth/login - User authentication
1004
- - POST /api/auth/logout - User logout
1005
- - POST /api/auth/refresh - Token refresh
1006
- - POST /api/auth/register - User registration
1007
-
1008
- 2. **Data Management Endpoints**
1009
- - GET /api/resources - List resources with pagination
1010
- - GET /api/resources/{id} - Get specific resource
1011
- - POST /api/resources - Create new resource
1012
- - PUT /api/resources/{id} - Update existing resource
1013
- - DELETE /api/resources/{id} - Delete resource
1014
-
1015
- 3. **Administrative Endpoints**
1016
- - GET /api/admin/users - Manage users (admin only)
1017
- - GET /api/admin/analytics - System analytics
1018
- - POST /api/admin/backup - Trigger system backup
1019
-
1020
- ## Technical Requirements
1021
- ### API Design
1022
- - RESTful architecture following OpenAPI 3.0 specification
1023
- - JSON request/response format
1024
- - Consistent error response format
1025
- - API versioning strategy
1026
-
1027
- ### Authentication & Security
1028
- - JWT token-based authentication
1029
- - Role-based access control (RBAC)
1030
- - Rate limiting (100 requests/minute per user)
1031
- - Input validation and sanitization
1032
- - HTTPS enforcement
1033
-
1034
- ### Database
1035
- - Database type: [PostgreSQL/MongoDB/MySQL]
1036
- - Connection pooling
1037
- - Database migrations
1038
- - Backup and recovery procedures
1039
-
1040
- ### Performance Requirements
1041
- - Response time: < 200ms for 95% of requests
1042
- - Throughput: 1000+ requests/second
1043
- - Concurrent users: 10,000+
1044
- - Database query optimization
1045
-
1046
- ### Documentation
1047
- - Auto-generated API documentation (Swagger/OpenAPI)
1048
- - Code examples for common use cases
1049
- - SDK development for major languages
1050
- - Postman collection for testing
1051
-
1052
- ## Error Handling
1053
- - Standardized error codes and messages
1054
- - Proper HTTP status codes
1055
- - Detailed error logging
1056
- - Graceful degradation strategies
1057
-
1058
- ## Testing Strategy
1059
- - Unit tests (80%+ coverage)
1060
- - Integration tests for all endpoints
1061
- - Load testing and performance testing
1062
- - Security testing (OWASP compliance)
1063
-
1064
- ## Monitoring & Logging
1065
- - Application performance monitoring
1066
- - Error tracking and alerting
1067
- - Access logs and audit trails
1068
- - Health check endpoints
1069
-
1070
- ## Deployment
1071
- - Containerized deployment (Docker)
1072
- - CI/CD pipeline setup
1073
- - Environment management (dev, staging, prod)
1074
- - Blue-green deployment strategy
1075
-
1076
- ## Success Metrics
1077
- - API uptime > 99.9%
1078
- - Average response time < 200ms
1079
- - Zero critical security vulnerabilities
1080
- - Developer adoption metrics`
1081
- },
1082
- {
1083
- id: 'mobile-app',
1084
- name: 'Mobile Application',
1085
- description: 'Template for mobile app development projects (iOS/Android)',
1086
- category: 'mobile',
1087
- content: `# Product Requirements Document - Mobile Application
1088
-
1089
- ## Overview
1090
- **App Name:** [Your App Name]
1091
- **Platform:** iOS / Android / Cross-platform
1092
- **Version:** 1.0
1093
- **Date:** ${new Date().toISOString().split('T')[0]}
1094
- **Author:** [Your Name]
1095
-
1096
- ## Executive Summary
1097
- Brief description of the mobile app's purpose, target audience, and key value proposition.
1098
-
1099
- ## Product Goals
1100
- - Goal 1: [Specific user engagement goal]
1101
- - Goal 2: [Specific functionality goal]
1102
- - Goal 3: [Specific performance goal]
1103
-
1104
- ## User Stories
1105
- ### Core Features
1106
- 1. **Onboarding & Authentication**
1107
- - As a new user, I want a simple onboarding process
1108
- - As a user, I want to sign up with email or social media
1109
- - As a user, I want biometric authentication for security
1110
-
1111
- 2. **Main App Features**
1112
- - As a user, I want [core feature 1] accessible from home screen
1113
- - As a user, I want [core feature 2] to work offline
1114
- - As a user, I want to sync data across devices
1115
-
1116
- 3. **User Experience**
1117
- - As a user, I want intuitive navigation patterns
1118
- - As a user, I want fast loading times
1119
- - As a user, I want accessibility features
1120
-
1121
- ## Technical Requirements
1122
- ### Mobile Development
1123
- - **Cross-platform:** React Native / Flutter / Xamarin
1124
- - **Native:** Swift (iOS) / Kotlin (Android)
1125
- - **State Management:** Redux / MobX / Provider
1126
- - **Navigation:** React Navigation / Flutter Navigation
1127
-
1128
- ### Backend Integration
1129
- - REST API or GraphQL integration
1130
- - Real-time features (WebSockets/Push notifications)
1131
- - Offline data synchronization
1132
- - Background processing
1133
-
1134
- ### Device Features
1135
- - Camera and photo library access
1136
- - GPS location services
1137
- - Push notifications
1138
- - Biometric authentication
1139
- - Device storage
1140
-
1141
- ### Performance Requirements
1142
- - App launch time < 3 seconds
1143
- - Screen transition animations < 300ms
1144
- - Memory usage optimization
1145
- - Battery usage optimization
1146
-
1147
- ## Platform-Specific Considerations
1148
- ### iOS Requirements
1149
- - iOS 13.0+ minimum version
1150
- - App Store guidelines compliance
1151
- - iOS design guidelines (Human Interface Guidelines)
1152
- - TestFlight beta testing
1153
-
1154
- ### Android Requirements
1155
- - Android 8.0+ (API level 26) minimum
1156
- - Google Play Store guidelines
1157
- - Material Design guidelines
1158
- - Google Play Console testing
1159
-
1160
- ## User Interface Design
1161
- - Responsive design for different screen sizes
1162
- - Dark mode support
1163
- - Accessibility compliance (WCAG 2.1)
1164
- - Consistent design system
1165
-
1166
- ## Security & Privacy
1167
- - Secure data storage (Keychain/Keystore)
1168
- - API communication encryption
1169
- - Privacy policy compliance (GDPR/CCPA)
1170
- - App security best practices
1171
-
1172
- ## Testing Strategy
1173
- - Unit testing (80%+ coverage)
1174
- - UI/E2E testing (Detox/Appium)
1175
- - Device testing on multiple screen sizes
1176
- - Performance testing
1177
- - Security testing
1178
-
1179
- ## App Store Deployment
1180
- - App store optimization (ASO)
1181
- - App icons and screenshots
1182
- - Store listing content
1183
- - Release management strategy
1184
-
1185
- ## Analytics & Monitoring
1186
- - User analytics (Firebase/Analytics)
1187
- - Crash reporting (Crashlytics/Sentry)
1188
- - Performance monitoring
1189
- - User feedback collection
1190
-
1191
- ## Success Metrics
1192
- - App store ratings > 4.0
1193
- - User retention rates
1194
- - Daily/Monthly active users
1195
- - App performance metrics
1196
- - Conversion rates`
1197
- },
1198
- {
1199
- id: 'data-analysis',
1200
- name: 'Data Analysis Project',
1201
- description: 'Template for data analysis and visualization projects',
1202
- category: 'data',
1203
- content: `# Product Requirements Document - Data Analysis Project
1204
-
1205
- ## Overview
1206
- **Project Name:** [Your Analysis Project]
1207
- **Analysis Type:** [Descriptive/Predictive/Prescriptive]
1208
- **Date:** ${new Date().toISOString().split('T')[0]}
1209
- **Author:** [Your Name]
1210
-
1211
- ## Executive Summary
1212
- Description of the business problem, data sources, and expected insights.
1213
-
1214
- ## Project Goals
1215
- - Goal 1: [Specific business question to answer]
1216
- - Goal 2: [Specific prediction to make]
1217
- - Goal 3: [Specific recommendation to provide]
1218
-
1219
- ## Business Requirements
1220
- ### Key Questions
1221
- 1. What patterns exist in the current data?
1222
- 2. What factors influence [target variable]?
1223
- 3. What predictions can be made for [future outcome]?
1224
- 4. What recommendations can improve [business metric]?
1225
-
1226
- ### Success Criteria
1227
- - Actionable insights for stakeholders
1228
- - Statistical significance in findings
1229
- - Reproducible analysis pipeline
1230
- - Clear visualization and reporting
1231
-
1232
- ## Data Requirements
1233
- ### Data Sources
1234
- 1. **Primary Data**
1235
- - Source: [Database/API/Files]
1236
- - Format: [CSV/JSON/SQL]
1237
- - Size: [Volume estimate]
1238
- - Update frequency: [Real-time/Daily/Monthly]
1239
-
1240
- 2. **External Data**
1241
- - Third-party APIs
1242
- - Public datasets
1243
- - Market research data
1244
-
1245
- ### Data Quality Requirements
1246
- - Data completeness (< 5% missing values)
1247
- - Data accuracy validation
1248
- - Data consistency checks
1249
- - Historical data availability
1250
-
1251
- ## Technical Requirements
1252
- ### Data Pipeline
1253
- - Data extraction and ingestion
1254
- - Data cleaning and preprocessing
1255
- - Data transformation and feature engineering
1256
- - Data validation and quality checks
1257
-
1258
- ### Analysis Tools
1259
- - **Programming:** Python/R/SQL
1260
- - **Libraries:** pandas, numpy, scikit-learn, matplotlib
1261
- - **Visualization:** Tableau, PowerBI, or custom dashboards
1262
- - **Version Control:** Git for code and DVC for data
1263
-
1264
- ### Computing Resources
1265
- - Local development environment
1266
- - Cloud computing (AWS/GCP/Azure) if needed
1267
- - Database access and permissions
1268
- - Storage requirements
1269
-
1270
- ## Analysis Methodology
1271
- ### Data Exploration
1272
- 1. Descriptive statistics and data profiling
1273
- 2. Data visualization and pattern identification
1274
- 3. Correlation analysis
1275
- 4. Outlier detection and handling
1276
-
1277
- ### Statistical Analysis
1278
- 1. Hypothesis formulation
1279
- 2. Statistical testing
1280
- 3. Confidence intervals
1281
- 4. Effect size calculations
1282
-
1283
- ### Machine Learning (if applicable)
1284
- 1. Feature selection and engineering
1285
- 2. Model selection and training
1286
- 3. Cross-validation and evaluation
1287
- 4. Model interpretation and explainability
1288
-
1289
- ## Deliverables
1290
- ### Reports
1291
- - Executive summary for stakeholders
1292
- - Technical analysis report
1293
- - Data quality report
1294
- - Methodology documentation
1295
-
1296
- ### Visualizations
1297
- - Interactive dashboards
1298
- - Static charts and graphs
1299
- - Data story presentations
1300
- - Key findings infographics
1301
-
1302
- ### Code & Documentation
1303
- - Reproducible analysis scripts
1304
- - Data pipeline code
1305
- - Documentation and comments
1306
- - Testing and validation code
1307
-
1308
- ## Timeline
1309
- - Phase 1: Data collection and exploration (2 weeks)
1310
- - Phase 2: Analysis and modeling (3 weeks)
1311
- - Phase 3: Reporting and visualization (1 week)
1312
- - Phase 4: Stakeholder presentation (1 week)
1313
-
1314
- ## Risks & Assumptions
1315
- - Data availability and quality risks
1316
- - Technical complexity assumptions
1317
- - Resource and timeline constraints
1318
- - Stakeholder engagement assumptions
1319
-
1320
- ## Success Metrics
1321
- - Stakeholder satisfaction with insights
1322
- - Accuracy of predictions (if applicable)
1323
- - Business impact of recommendations
1324
- - Reproducibility of results`
1325
- }
1326
- ];
1327
-
1328
- res.json({
1329
- templates,
1330
- timestamp: new Date().toISOString()
1331
- });
1332
-
1333
- } catch (error) {
1334
- console.error('PRD templates error:', error);
1335
- res.status(500).json({
1336
- error: 'Failed to get PRD templates',
1337
- message: error.message
1338
- });
1339
- }
1340
- });
1341
-
1342
- /**
1343
- * POST /api/taskmaster/apply-template/:projectName
1344
- * Apply a PRD template to create a new PRD file
1345
- */
1346
- router.post('/apply-template/:projectName', async (req, res) => {
1347
- try {
1348
- const { projectName } = req.params;
1349
- const { templateId, fileName = 'prd.txt', customizations = {} } = req.body;
1350
-
1351
- if (!templateId) {
1352
- return res.status(400).json({
1353
- error: 'Missing required parameter',
1354
- message: 'templateId is required'
1355
- });
1356
- }
1357
-
1358
- // Get project path
1359
- let projectPath;
1360
- try {
1361
- projectPath = await extractProjectDirectory(projectName);
1362
- } catch (error) {
1363
- return res.status(404).json({
1364
- error: 'Project not found',
1365
- message: `Project "${projectName}" does not exist`
1366
- });
1367
- }
1368
-
1369
- // Get the template content (this would normally fetch from the templates list)
1370
- const templates = await getAvailableTemplates();
1371
- const template = templates.find(t => t.id === templateId);
1372
-
1373
- if (!template) {
1374
- return res.status(404).json({
1375
- error: 'Template not found',
1376
- message: `Template "${templateId}" does not exist`
1377
- });
1378
- }
1379
-
1380
- // Apply customizations to template content
1381
- let content = template.content;
1382
-
1383
- // Replace placeholders with customizations
1384
- for (const [key, value] of Object.entries(customizations)) {
1385
- const placeholder = `[${key}]`;
1386
- content = content.replace(new RegExp(placeholder.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'), 'g'), value);
1387
- }
1388
-
1389
- // Ensure .taskmaster/docs directory exists
1390
- const docsDir = path.join(projectPath, '.taskmaster', 'docs');
1391
- try {
1392
- await fsPromises.mkdir(docsDir, { recursive: true });
1393
- } catch (error) {
1394
- console.error('Failed to create docs directory:', error);
1395
- }
1396
-
1397
- const filePath = path.join(docsDir, fileName);
1398
-
1399
- // Write the template content to the file
1400
- try {
1401
- await fsPromises.writeFile(filePath, content, 'utf8');
1402
-
1403
- res.json({
1404
- projectName,
1405
- projectPath,
1406
- templateId,
1407
- templateName: template.name,
1408
- fileName,
1409
- filePath: filePath,
1410
- message: 'PRD template applied successfully',
1411
- timestamp: new Date().toISOString()
1412
- });
1413
-
1414
- } catch (writeError) {
1415
- console.error('Failed to write PRD template:', writeError);
1416
- return res.status(500).json({
1417
- error: 'Failed to write PRD template',
1418
- message: writeError.message
1419
- });
1420
- }
1421
-
1422
- } catch (error) {
1423
- console.error('Apply template error:', error);
1424
- res.status(500).json({
1425
- error: 'Failed to apply PRD template',
1426
- message: error.message
1427
- });
1428
- }
1429
- });
1430
-
1431
- // Helper function to get available templates
1432
- async function getAvailableTemplates() {
1433
- // This could be extended to read from files or database
1434
- return [
1435
- {
1436
- id: 'web-app',
1437
- name: 'Web Application',
1438
- description: 'Template for web application projects',
1439
- category: 'web',
1440
- content: `# Product Requirements Document - Web Application
1441
-
1442
- ## Overview
1443
- **Product Name:** [Your App Name]
1444
- **Version:** 1.0
1445
- **Date:** ${new Date().toISOString().split('T')[0]}
1446
- **Author:** [Your Name]
1447
-
1448
- ## Executive Summary
1449
- Brief description of what this web application will do and why it's needed.
1450
-
1451
- ## User Stories
1452
- 1. As a user, I want [feature] so I can [benefit]
1453
- 2. As a user, I want [feature] so I can [benefit]
1454
- 3. As a user, I want [feature] so I can [benefit]
1455
-
1456
- ## Technical Requirements
1457
- - Frontend framework
1458
- - Backend services
1459
- - Database requirements
1460
- - Security considerations
1461
-
1462
- ## Success Metrics
1463
- - User engagement metrics
1464
- - Performance benchmarks
1465
- - Business objectives`
1466
- },
1467
- // Add other templates here if needed
1468
- ];
1469
- }
1470
-
1471
- export default router;
1
+ /**
2
+ * TASKMASTER API ROUTES
3
+ * ====================
4
+ *
5
+ * This module provides API endpoints for TaskMaster integration including:
6
+ * - .taskmaster folder detection in project directories
7
+ * - MCP server configuration detection
8
+ * - TaskMaster state and metadata management
9
+ */
10
+
11
+ import express from 'express';
12
+ import fs from 'fs';
13
+ import path from 'path';
14
+ import { promises as fsPromises } from 'fs';
15
+ import { spawn } from 'child_process';
16
+ import { extractProjectDirectory } from '../projects.js';
17
+ import { detectTaskMasterMCPServer } from '../utils/mcp-detector.js';
18
+ import { broadcastTaskMasterProjectUpdate, broadcastTaskMasterTasksUpdate } from '../utils/taskmaster-websocket.js';
19
+
20
+ const router = express.Router();
21
+
22
+ /**
23
+ * Check if TaskMaster CLI is installed globally
24
+ * @returns {Promise<Object>} Installation status result
25
+ */
26
+ async function checkTaskMasterInstallation() {
27
+ return new Promise((resolve) => {
28
+ // Check if task-master command is available
29
+ const child = spawn('which', ['task-master'], {
30
+ stdio: ['ignore', 'pipe', 'pipe'],
31
+ shell: true
32
+ });
33
+
34
+ let output = '';
35
+ let errorOutput = '';
36
+
37
+ child.stdout.on('data', (data) => {
38
+ output += data.toString();
39
+ });
40
+
41
+ child.stderr.on('data', (data) => {
42
+ errorOutput += data.toString();
43
+ });
44
+
45
+ child.on('close', (code) => {
46
+ if (code === 0 && output.trim()) {
47
+ // TaskMaster is installed, get version
48
+ const versionChild = spawn('task-master', ['--version'], {
49
+ stdio: ['ignore', 'pipe', 'pipe'],
50
+ shell: true
51
+ });
52
+
53
+ let versionOutput = '';
54
+
55
+ versionChild.stdout.on('data', (data) => {
56
+ versionOutput += data.toString();
57
+ });
58
+
59
+ versionChild.on('close', (versionCode) => {
60
+ resolve({
61
+ isInstalled: true,
62
+ installPath: output.trim(),
63
+ version: versionCode === 0 ? versionOutput.trim() : 'unknown',
64
+ reason: null
65
+ });
66
+ });
67
+
68
+ versionChild.on('error', () => {
69
+ resolve({
70
+ isInstalled: true,
71
+ installPath: output.trim(),
72
+ version: 'unknown',
73
+ reason: null
74
+ });
75
+ });
76
+ } else {
77
+ resolve({
78
+ isInstalled: false,
79
+ installPath: null,
80
+ version: null,
81
+ reason: 'TaskMaster CLI not found in PATH'
82
+ });
83
+ }
84
+ });
85
+
86
+ child.on('error', (error) => {
87
+ resolve({
88
+ isInstalled: false,
89
+ installPath: null,
90
+ version: null,
91
+ reason: `Error checking installation: ${error.message}`
92
+ });
93
+ });
94
+ });
95
+ }
96
+
97
+ // API Routes
98
+
99
+ /**
100
+ * GET /api/taskmaster/installation-status
101
+ * Check if TaskMaster CLI is installed on the system
102
+ */
103
+ router.get('/installation-status', async (req, res) => {
104
+ try {
105
+ const installationStatus = await checkTaskMasterInstallation();
106
+
107
+ // Also check for MCP server configuration
108
+ const mcpStatus = await detectTaskMasterMCPServer();
109
+
110
+ res.json({
111
+ success: true,
112
+ installation: installationStatus,
113
+ mcpServer: mcpStatus,
114
+ isReady: installationStatus.isInstalled && mcpStatus.hasMCPServer
115
+ });
116
+ } catch (error) {
117
+ console.error('Error checking TaskMaster installation:', error);
118
+ res.status(500).json({
119
+ success: false,
120
+ error: 'Failed to check TaskMaster installation status',
121
+ installation: {
122
+ isInstalled: false,
123
+ reason: `Server error: ${error.message}`
124
+ },
125
+ mcpServer: {
126
+ hasMCPServer: false,
127
+ reason: `Server error: ${error.message}`
128
+ },
129
+ isReady: false
130
+ });
131
+ }
132
+ });
133
+
134
+ /**
135
+ * GET /api/taskmaster/tasks/:projectName
136
+ * Load actual tasks from .taskmaster/tasks/tasks.json
137
+ */
138
+ router.get('/tasks/:projectName', async (req, res) => {
139
+ try {
140
+ const { projectName } = req.params;
141
+
142
+ // Get project path
143
+ let projectPath;
144
+ try {
145
+ projectPath = await extractProjectDirectory(projectName);
146
+ } catch (error) {
147
+ return res.status(404).json({
148
+ error: 'Project not found',
149
+ message: `Project "${projectName}" does not exist`
150
+ });
151
+ }
152
+
153
+ const taskMasterPath = path.join(projectPath, '.taskmaster');
154
+ const tasksFilePath = path.join(taskMasterPath, 'tasks', 'tasks.json');
155
+
156
+ // Check if tasks file exists
157
+ try {
158
+ await fsPromises.access(tasksFilePath);
159
+ } catch (error) {
160
+ return res.json({
161
+ projectName,
162
+ tasks: [],
163
+ message: 'No tasks.json file found'
164
+ });
165
+ }
166
+
167
+ // Read and parse tasks file
168
+ try {
169
+ const tasksContent = await fsPromises.readFile(tasksFilePath, 'utf8');
170
+ const tasksData = JSON.parse(tasksContent);
171
+
172
+ let tasks = [];
173
+ let currentTag = 'master';
174
+
175
+ // Handle both tagged and legacy formats
176
+ if (Array.isArray(tasksData)) {
177
+ // Legacy format
178
+ tasks = tasksData;
179
+ } else if (tasksData.tasks) {
180
+ // Simple format with tasks array
181
+ tasks = tasksData.tasks;
182
+ } else {
183
+ // Tagged format - get tasks from current tag or master
184
+ if (tasksData[currentTag] && tasksData[currentTag].tasks) {
185
+ tasks = tasksData[currentTag].tasks;
186
+ } else if (tasksData.master && tasksData.master.tasks) {
187
+ tasks = tasksData.master.tasks;
188
+ } else {
189
+ // Get tasks from first available tag
190
+ const firstTag = Object.keys(tasksData).find(key =>
191
+ tasksData[key].tasks && Array.isArray(tasksData[key].tasks)
192
+ );
193
+ if (firstTag) {
194
+ tasks = tasksData[firstTag].tasks;
195
+ currentTag = firstTag;
196
+ }
197
+ }
198
+ }
199
+
200
+ // Transform tasks to ensure all have required fields
201
+ const transformedTasks = tasks.map(task => ({
202
+ id: task.id,
203
+ title: task.title || 'Untitled Task',
204
+ description: task.description || '',
205
+ status: task.status || 'pending',
206
+ priority: task.priority || 'medium',
207
+ dependencies: task.dependencies || [],
208
+ createdAt: task.createdAt || task.created || new Date().toISOString(),
209
+ updatedAt: task.updatedAt || task.updated || new Date().toISOString(),
210
+ details: task.details || '',
211
+ testStrategy: task.testStrategy || task.test_strategy || '',
212
+ subtasks: task.subtasks || []
213
+ }));
214
+
215
+ res.json({
216
+ projectName,
217
+ projectPath,
218
+ tasks: transformedTasks,
219
+ currentTag,
220
+ totalTasks: transformedTasks.length,
221
+ tasksByStatus: {
222
+ pending: transformedTasks.filter(t => t.status === 'pending').length,
223
+ 'in-progress': transformedTasks.filter(t => t.status === 'in-progress').length,
224
+ done: transformedTasks.filter(t => t.status === 'done').length,
225
+ review: transformedTasks.filter(t => t.status === 'review').length,
226
+ deferred: transformedTasks.filter(t => t.status === 'deferred').length,
227
+ cancelled: transformedTasks.filter(t => t.status === 'cancelled').length
228
+ },
229
+ timestamp: new Date().toISOString()
230
+ });
231
+
232
+ } catch (parseError) {
233
+ console.error('Failed to parse tasks.json:', parseError);
234
+ return res.status(500).json({
235
+ error: 'Failed to parse tasks file',
236
+ message: parseError.message
237
+ });
238
+ }
239
+
240
+ } catch (error) {
241
+ console.error('TaskMaster tasks loading error:', error);
242
+ res.status(500).json({
243
+ error: 'Failed to load TaskMaster tasks',
244
+ message: error.message
245
+ });
246
+ }
247
+ });
248
+
249
+ /**
250
+ * GET /api/taskmaster/prd/:projectName
251
+ * List all PRD files in the project's .taskmaster/docs directory
252
+ */
253
+ router.get('/prd/:projectName', async (req, res) => {
254
+ try {
255
+ const { projectName } = req.params;
256
+
257
+ // Get project path
258
+ let projectPath;
259
+ try {
260
+ projectPath = await extractProjectDirectory(projectName);
261
+ } catch (error) {
262
+ return res.status(404).json({
263
+ error: 'Project not found',
264
+ message: `Project "${projectName}" does not exist`
265
+ });
266
+ }
267
+
268
+ const docsPath = path.join(projectPath, '.taskmaster', 'docs');
269
+
270
+ // Check if docs directory exists
271
+ try {
272
+ await fsPromises.access(docsPath, fs.constants.R_OK);
273
+ } catch (error) {
274
+ return res.json({
275
+ projectName,
276
+ prdFiles: [],
277
+ message: 'No .taskmaster/docs directory found'
278
+ });
279
+ }
280
+
281
+ // Read directory and filter for PRD files
282
+ try {
283
+ const files = await fsPromises.readdir(docsPath);
284
+ const prdFiles = [];
285
+
286
+ for (const file of files) {
287
+ const filePath = path.join(docsPath, file);
288
+ const stats = await fsPromises.stat(filePath);
289
+
290
+ if (stats.isFile() && (file.endsWith('.txt') || file.endsWith('.md'))) {
291
+ prdFiles.push({
292
+ name: file,
293
+ path: path.relative(projectPath, filePath),
294
+ size: stats.size,
295
+ modified: stats.mtime.toISOString(),
296
+ created: stats.birthtime.toISOString()
297
+ });
298
+ }
299
+ }
300
+
301
+ res.json({
302
+ projectName,
303
+ projectPath,
304
+ prdFiles: prdFiles.sort((a, b) => new Date(b.modified) - new Date(a.modified)),
305
+ timestamp: new Date().toISOString()
306
+ });
307
+
308
+ } catch (readError) {
309
+ console.error('Error reading docs directory:', readError);
310
+ return res.status(500).json({
311
+ error: 'Failed to read PRD files',
312
+ message: readError.message
313
+ });
314
+ }
315
+
316
+ } catch (error) {
317
+ console.error('PRD list error:', error);
318
+ res.status(500).json({
319
+ error: 'Failed to list PRD files',
320
+ message: error.message
321
+ });
322
+ }
323
+ });
324
+
325
+ /**
326
+ * POST /api/taskmaster/prd/:projectName
327
+ * Create or update a PRD file in the project's .taskmaster/docs directory
328
+ */
329
+ router.post('/prd/:projectName', async (req, res) => {
330
+ try {
331
+ const { projectName } = req.params;
332
+ const { fileName, content } = req.body;
333
+
334
+ if (!fileName || !content) {
335
+ return res.status(400).json({
336
+ error: 'Missing required fields',
337
+ message: 'fileName and content are required'
338
+ });
339
+ }
340
+
341
+ // Validate filename
342
+ if (!fileName.match(/^[\w\-. ]+\.(txt|md)$/)) {
343
+ return res.status(400).json({
344
+ error: 'Invalid filename',
345
+ message: 'Filename must end with .txt or .md and contain only alphanumeric characters, spaces, dots, and dashes'
346
+ });
347
+ }
348
+
349
+ // Get project path
350
+ let projectPath;
351
+ try {
352
+ projectPath = await extractProjectDirectory(projectName);
353
+ } catch (error) {
354
+ return res.status(404).json({
355
+ error: 'Project not found',
356
+ message: `Project "${projectName}" does not exist`
357
+ });
358
+ }
359
+
360
+ const docsPath = path.join(projectPath, '.taskmaster', 'docs');
361
+ const filePath = path.join(docsPath, fileName);
362
+
363
+ // Ensure docs directory exists
364
+ try {
365
+ await fsPromises.mkdir(docsPath, { recursive: true });
366
+ } catch (error) {
367
+ console.error('Failed to create docs directory:', error);
368
+ return res.status(500).json({
369
+ error: 'Failed to create directory',
370
+ message: error.message
371
+ });
372
+ }
373
+
374
+ // Write the PRD file
375
+ try {
376
+ await fsPromises.writeFile(filePath, content, 'utf8');
377
+
378
+ // Get file stats
379
+ const stats = await fsPromises.stat(filePath);
380
+
381
+ res.json({
382
+ projectName,
383
+ projectPath,
384
+ fileName,
385
+ filePath: path.relative(projectPath, filePath),
386
+ size: stats.size,
387
+ created: stats.birthtime.toISOString(),
388
+ modified: stats.mtime.toISOString(),
389
+ message: 'PRD file saved successfully',
390
+ timestamp: new Date().toISOString()
391
+ });
392
+
393
+ } catch (writeError) {
394
+ console.error('Failed to write PRD file:', writeError);
395
+ return res.status(500).json({
396
+ error: 'Failed to write PRD file',
397
+ message: writeError.message
398
+ });
399
+ }
400
+
401
+ } catch (error) {
402
+ console.error('PRD create/update error:', error);
403
+ res.status(500).json({
404
+ error: 'Failed to create/update PRD file',
405
+ message: error.message
406
+ });
407
+ }
408
+ });
409
+
410
+ /**
411
+ * GET /api/taskmaster/prd/:projectName/:fileName
412
+ * Get content of a specific PRD file
413
+ */
414
+ router.get('/prd/:projectName/:fileName', async (req, res) => {
415
+ try {
416
+ const { projectName, fileName } = req.params;
417
+
418
+ // Get project path
419
+ let projectPath;
420
+ try {
421
+ projectPath = await extractProjectDirectory(projectName);
422
+ } catch (error) {
423
+ return res.status(404).json({
424
+ error: 'Project not found',
425
+ message: `Project "${projectName}" does not exist`
426
+ });
427
+ }
428
+
429
+ const filePath = path.join(projectPath, '.taskmaster', 'docs', fileName);
430
+
431
+ // Check if file exists
432
+ try {
433
+ await fsPromises.access(filePath, fs.constants.R_OK);
434
+ } catch (error) {
435
+ return res.status(404).json({
436
+ error: 'PRD file not found',
437
+ message: `File "${fileName}" does not exist`
438
+ });
439
+ }
440
+
441
+ // Read file content
442
+ try {
443
+ const content = await fsPromises.readFile(filePath, 'utf8');
444
+ const stats = await fsPromises.stat(filePath);
445
+
446
+ res.json({
447
+ projectName,
448
+ projectPath,
449
+ fileName,
450
+ filePath: path.relative(projectPath, filePath),
451
+ content,
452
+ size: stats.size,
453
+ created: stats.birthtime.toISOString(),
454
+ modified: stats.mtime.toISOString(),
455
+ timestamp: new Date().toISOString()
456
+ });
457
+
458
+ } catch (readError) {
459
+ console.error('Failed to read PRD file:', readError);
460
+ return res.status(500).json({
461
+ error: 'Failed to read PRD file',
462
+ message: readError.message
463
+ });
464
+ }
465
+
466
+ } catch (error) {
467
+ console.error('PRD read error:', error);
468
+ res.status(500).json({
469
+ error: 'Failed to read PRD file',
470
+ message: error.message
471
+ });
472
+ }
473
+ });
474
+
475
+ /**
476
+ * POST /api/taskmaster/init/:projectName
477
+ * Initialize TaskMaster in a project
478
+ */
479
+ router.post('/init/:projectName', async (req, res) => {
480
+ try {
481
+ const { projectName } = req.params;
482
+
483
+ // Get project path
484
+ let projectPath;
485
+ try {
486
+ projectPath = await extractProjectDirectory(projectName);
487
+ } catch (error) {
488
+ return res.status(404).json({
489
+ error: 'Project not found',
490
+ message: `Project "${projectName}" does not exist`
491
+ });
492
+ }
493
+
494
+ // Check if TaskMaster is already initialized
495
+ const taskMasterPath = path.join(projectPath, '.taskmaster');
496
+ try {
497
+ await fsPromises.access(taskMasterPath, fs.constants.F_OK);
498
+ return res.status(400).json({
499
+ error: 'TaskMaster already initialized',
500
+ message: 'TaskMaster is already configured for this project'
501
+ });
502
+ } catch (error) {
503
+ // Directory doesn't exist, we can proceed
504
+ }
505
+
506
+ // Run taskmaster init command
507
+ const initProcess = spawn('npx', ['task-master', 'init'], {
508
+ cwd: projectPath,
509
+ stdio: ['pipe', 'pipe', 'pipe']
510
+ });
511
+
512
+ let stdout = '';
513
+ let stderr = '';
514
+
515
+ initProcess.stdout.on('data', (data) => {
516
+ stdout += data.toString();
517
+ });
518
+
519
+ initProcess.stderr.on('data', (data) => {
520
+ stderr += data.toString();
521
+ });
522
+
523
+ initProcess.on('close', (code) => {
524
+ if (code === 0) {
525
+ // Broadcast TaskMaster project update via WebSocket
526
+ if (req.app.locals.wss) {
527
+ broadcastTaskMasterProjectUpdate(
528
+ req.app.locals.wss,
529
+ projectName,
530
+ { hasTaskmaster: true, status: 'initialized' }
531
+ );
532
+ }
533
+
534
+ res.json({
535
+ projectName,
536
+ projectPath,
537
+ message: 'TaskMaster initialized successfully',
538
+ output: stdout,
539
+ timestamp: new Date().toISOString()
540
+ });
541
+ } else {
542
+ console.error('TaskMaster init failed:', stderr);
543
+ res.status(500).json({
544
+ error: 'Failed to initialize TaskMaster',
545
+ message: stderr || stdout,
546
+ code
547
+ });
548
+ }
549
+ });
550
+
551
+ // Send 'yes' responses to automated prompts
552
+ initProcess.stdin.write('yes\n');
553
+ initProcess.stdin.end();
554
+
555
+ } catch (error) {
556
+ console.error('TaskMaster init error:', error);
557
+ res.status(500).json({
558
+ error: 'Failed to initialize TaskMaster',
559
+ message: error.message
560
+ });
561
+ }
562
+ });
563
+
564
+ /**
565
+ * POST /api/taskmaster/add-task/:projectName
566
+ * Add a new task to the project
567
+ */
568
+ router.post('/add-task/:projectName', async (req, res) => {
569
+ try {
570
+ const { projectName } = req.params;
571
+ const { prompt, title, description, priority = 'medium', dependencies } = req.body;
572
+
573
+ if (!prompt && (!title || !description)) {
574
+ return res.status(400).json({
575
+ error: 'Missing required parameters',
576
+ message: 'Either "prompt" or both "title" and "description" are required'
577
+ });
578
+ }
579
+
580
+ // Get project path
581
+ let projectPath;
582
+ try {
583
+ projectPath = await extractProjectDirectory(projectName);
584
+ } catch (error) {
585
+ return res.status(404).json({
586
+ error: 'Project not found',
587
+ message: `Project "${projectName}" does not exist`
588
+ });
589
+ }
590
+
591
+ // Build the task-master add-task command
592
+ const args = ['task-master-ai', 'add-task'];
593
+
594
+ if (prompt) {
595
+ args.push('--prompt', prompt);
596
+ args.push('--research'); // Use research for AI-generated tasks
597
+ } else {
598
+ args.push('--prompt', `Create a task titled "${title}" with description: ${description}`);
599
+ }
600
+
601
+ if (priority) {
602
+ args.push('--priority', priority);
603
+ }
604
+
605
+ if (dependencies) {
606
+ args.push('--dependencies', dependencies);
607
+ }
608
+
609
+ // Run task-master add-task command
610
+ const addTaskProcess = spawn('npx', args, {
611
+ cwd: projectPath,
612
+ stdio: ['pipe', 'pipe', 'pipe']
613
+ });
614
+
615
+ let stdout = '';
616
+ let stderr = '';
617
+
618
+ addTaskProcess.stdout.on('data', (data) => {
619
+ stdout += data.toString();
620
+ });
621
+
622
+ addTaskProcess.stderr.on('data', (data) => {
623
+ stderr += data.toString();
624
+ });
625
+
626
+ addTaskProcess.on('close', (code) => {
627
+ console.log('Add task process completed with code:', code);
628
+ console.log('Stdout:', stdout);
629
+ console.log('Stderr:', stderr);
630
+
631
+ if (code === 0) {
632
+ // Broadcast task update via WebSocket
633
+ if (req.app.locals.wss) {
634
+ broadcastTaskMasterTasksUpdate(
635
+ req.app.locals.wss,
636
+ projectName
637
+ );
638
+ }
639
+
640
+ res.json({
641
+ projectName,
642
+ projectPath,
643
+ message: 'Task added successfully',
644
+ output: stdout,
645
+ timestamp: new Date().toISOString()
646
+ });
647
+ } else {
648
+ console.error('Add task failed:', stderr);
649
+ res.status(500).json({
650
+ error: 'Failed to add task',
651
+ message: stderr || stdout,
652
+ code
653
+ });
654
+ }
655
+ });
656
+
657
+ addTaskProcess.stdin.end();
658
+
659
+ } catch (error) {
660
+ console.error('Add task error:', error);
661
+ res.status(500).json({
662
+ error: 'Failed to add task',
663
+ message: error.message
664
+ });
665
+ }
666
+ });
667
+
668
+ /**
669
+ * PUT /api/taskmaster/update-task/:projectName/:taskId
670
+ * Update a specific task using TaskMaster CLI
671
+ */
672
+ router.put('/update-task/:projectName/:taskId', async (req, res) => {
673
+ try {
674
+ const { projectName, taskId } = req.params;
675
+ const { title, description, status, priority, details } = req.body;
676
+
677
+ // Get project path
678
+ let projectPath;
679
+ try {
680
+ projectPath = await extractProjectDirectory(projectName);
681
+ } catch (error) {
682
+ return res.status(404).json({
683
+ error: 'Project not found',
684
+ message: `Project "${projectName}" does not exist`
685
+ });
686
+ }
687
+
688
+ // If only updating status, use set-status command
689
+ if (status && Object.keys(req.body).length === 1) {
690
+ const setStatusProcess = spawn('npx', ['task-master-ai', 'set-status', `--id=${taskId}`, `--status=${status}`], {
691
+ cwd: projectPath,
692
+ stdio: ['pipe', 'pipe', 'pipe']
693
+ });
694
+
695
+ let stdout = '';
696
+ let stderr = '';
697
+
698
+ setStatusProcess.stdout.on('data', (data) => {
699
+ stdout += data.toString();
700
+ });
701
+
702
+ setStatusProcess.stderr.on('data', (data) => {
703
+ stderr += data.toString();
704
+ });
705
+
706
+ setStatusProcess.on('close', (code) => {
707
+ if (code === 0) {
708
+ // Broadcast task update via WebSocket
709
+ if (req.app.locals.wss) {
710
+ broadcastTaskMasterTasksUpdate(req.app.locals.wss, projectName);
711
+ }
712
+
713
+ res.json({
714
+ projectName,
715
+ projectPath,
716
+ taskId,
717
+ message: 'Task status updated successfully',
718
+ output: stdout,
719
+ timestamp: new Date().toISOString()
720
+ });
721
+ } else {
722
+ console.error('Set task status failed:', stderr);
723
+ res.status(500).json({
724
+ error: 'Failed to update task status',
725
+ message: stderr || stdout,
726
+ code
727
+ });
728
+ }
729
+ });
730
+
731
+ setStatusProcess.stdin.end();
732
+ } else {
733
+ // For other updates, use update-task command with a prompt describing the changes
734
+ const updates = [];
735
+ if (title) updates.push(`title: "${title}"`);
736
+ if (description) updates.push(`description: "${description}"`);
737
+ if (priority) updates.push(`priority: "${priority}"`);
738
+ if (details) updates.push(`details: "${details}"`);
739
+
740
+ const prompt = `Update task with the following changes: ${updates.join(', ')}`;
741
+
742
+ const updateProcess = spawn('npx', ['task-master-ai', 'update-task', `--id=${taskId}`, `--prompt=${prompt}`], {
743
+ cwd: projectPath,
744
+ stdio: ['pipe', 'pipe', 'pipe']
745
+ });
746
+
747
+ let stdout = '';
748
+ let stderr = '';
749
+
750
+ updateProcess.stdout.on('data', (data) => {
751
+ stdout += data.toString();
752
+ });
753
+
754
+ updateProcess.stderr.on('data', (data) => {
755
+ stderr += data.toString();
756
+ });
757
+
758
+ updateProcess.on('close', (code) => {
759
+ if (code === 0) {
760
+ // Broadcast task update via WebSocket
761
+ if (req.app.locals.wss) {
762
+ broadcastTaskMasterTasksUpdate(req.app.locals.wss, projectName);
763
+ }
764
+
765
+ res.json({
766
+ projectName,
767
+ projectPath,
768
+ taskId,
769
+ message: 'Task updated successfully',
770
+ output: stdout,
771
+ timestamp: new Date().toISOString()
772
+ });
773
+ } else {
774
+ console.error('Update task failed:', stderr);
775
+ res.status(500).json({
776
+ error: 'Failed to update task',
777
+ message: stderr || stdout,
778
+ code
779
+ });
780
+ }
781
+ });
782
+
783
+ updateProcess.stdin.end();
784
+ }
785
+
786
+ } catch (error) {
787
+ console.error('Update task error:', error);
788
+ res.status(500).json({
789
+ error: 'Failed to update task',
790
+ message: error.message
791
+ });
792
+ }
793
+ });
794
+
795
+ /**
796
+ * POST /api/taskmaster/parse-prd/:projectName
797
+ * Parse a PRD file to generate tasks
798
+ */
799
+ router.post('/parse-prd/:projectName', async (req, res) => {
800
+ try {
801
+ const { projectName } = req.params;
802
+ const { fileName = 'prd.txt', numTasks, append = false } = req.body;
803
+
804
+ // Get project path
805
+ let projectPath;
806
+ try {
807
+ projectPath = await extractProjectDirectory(projectName);
808
+ } catch (error) {
809
+ return res.status(404).json({
810
+ error: 'Project not found',
811
+ message: `Project "${projectName}" does not exist`
812
+ });
813
+ }
814
+
815
+ const prdPath = path.join(projectPath, '.taskmaster', 'docs', fileName);
816
+
817
+ // Check if PRD file exists
818
+ try {
819
+ await fsPromises.access(prdPath, fs.constants.F_OK);
820
+ } catch (error) {
821
+ return res.status(404).json({
822
+ error: 'PRD file not found',
823
+ message: `File "${fileName}" does not exist in .taskmaster/docs/`
824
+ });
825
+ }
826
+
827
+ // Build the command args
828
+ const args = ['task-master-ai', 'parse-prd', prdPath];
829
+
830
+ if (numTasks) {
831
+ args.push('--num-tasks', numTasks.toString());
832
+ }
833
+
834
+ if (append) {
835
+ args.push('--append');
836
+ }
837
+
838
+ args.push('--research'); // Use research for better PRD parsing
839
+
840
+ // Run task-master parse-prd command
841
+ const parsePRDProcess = spawn('npx', args, {
842
+ cwd: projectPath,
843
+ stdio: ['pipe', 'pipe', 'pipe']
844
+ });
845
+
846
+ let stdout = '';
847
+ let stderr = '';
848
+
849
+ parsePRDProcess.stdout.on('data', (data) => {
850
+ stdout += data.toString();
851
+ });
852
+
853
+ parsePRDProcess.stderr.on('data', (data) => {
854
+ stderr += data.toString();
855
+ });
856
+
857
+ parsePRDProcess.on('close', (code) => {
858
+ if (code === 0) {
859
+ // Broadcast task update via WebSocket
860
+ if (req.app.locals.wss) {
861
+ broadcastTaskMasterTasksUpdate(
862
+ req.app.locals.wss,
863
+ projectName
864
+ );
865
+ }
866
+
867
+ res.json({
868
+ projectName,
869
+ projectPath,
870
+ prdFile: fileName,
871
+ message: 'PRD parsed and tasks generated successfully',
872
+ output: stdout,
873
+ timestamp: new Date().toISOString()
874
+ });
875
+ } else {
876
+ console.error('Parse PRD failed:', stderr);
877
+ res.status(500).json({
878
+ error: 'Failed to parse PRD',
879
+ message: stderr || stdout,
880
+ code
881
+ });
882
+ }
883
+ });
884
+
885
+ parsePRDProcess.stdin.end();
886
+
887
+ } catch (error) {
888
+ console.error('Parse PRD error:', error);
889
+ res.status(500).json({
890
+ error: 'Failed to parse PRD',
891
+ message: error.message
892
+ });
893
+ }
894
+ });
895
+
896
+ /**
897
+ * GET /api/taskmaster/prd-templates
898
+ * Get available PRD templates
899
+ */
900
+ router.get('/prd-templates', async (req, res) => {
901
+ try {
902
+ // Return built-in templates
903
+ const templates = [
904
+ {
905
+ id: 'web-app',
906
+ name: 'Web Application',
907
+ description: 'Template for web application projects with frontend and backend components',
908
+ category: 'web',
909
+ content: `# Product Requirements Document - Web Application
910
+
911
+ ## Overview
912
+ **Product Name:** [Your App Name]
913
+ **Version:** 1.0
914
+ **Date:** ${new Date().toISOString().split('T')[0]}
915
+ **Author:** [Your Name]
916
+
917
+ ## Executive Summary
918
+ Brief description of what this web application will do and why it's needed.
919
+
920
+ ## Product Goals
921
+ - Goal 1: [Specific measurable goal]
922
+ - Goal 2: [Specific measurable goal]
923
+ - Goal 3: [Specific measurable goal]
924
+
925
+ ## User Stories
926
+ ### Core Features
927
+ 1. **User Registration & Authentication**
928
+ - As a user, I want to create an account so I can access personalized features
929
+ - As a user, I want to log in securely so my data is protected
930
+ - As a user, I want to reset my password if I forget it
931
+
932
+ 2. **Main Application Features**
933
+ - As a user, I want to [core feature 1] so I can [benefit]
934
+ - As a user, I want to [core feature 2] so I can [benefit]
935
+ - As a user, I want to [core feature 3] so I can [benefit]
936
+
937
+ 3. **User Interface**
938
+ - As a user, I want a responsive design so I can use the app on any device
939
+ - As a user, I want intuitive navigation so I can easily find features
940
+
941
+ ## Technical Requirements
942
+ ### Frontend
943
+ - Framework: React/Vue/Angular or vanilla JavaScript
944
+ - Styling: CSS framework (Tailwind, Bootstrap, etc.)
945
+ - State Management: Redux/Vuex/Context API
946
+ - Build Tools: Webpack/Vite
947
+ - Testing: Jest/Vitest for unit tests
948
+
949
+ ### Backend
950
+ - Runtime: Node.js/Python/Java
951
+ - Database: PostgreSQL/MySQL/MongoDB
952
+ - API: RESTful API or GraphQL
953
+ - Authentication: JWT tokens
954
+ - Testing: Integration and unit tests
955
+
956
+ ### Infrastructure
957
+ - Hosting: Cloud provider (AWS, Azure, GCP)
958
+ - CI/CD: GitHub Actions/GitLab CI
959
+ - Monitoring: Application monitoring tools
960
+ - Security: HTTPS, input validation, rate limiting
961
+
962
+ ## Success Metrics
963
+ - User engagement metrics
964
+ - Performance benchmarks (load time < 2s)
965
+ - Error rates < 1%
966
+ - User satisfaction scores
967
+
968
+ ## Timeline
969
+ - Phase 1: Core functionality (4-6 weeks)
970
+ - Phase 2: Advanced features (2-4 weeks)
971
+ - Phase 3: Polish and launch (2 weeks)
972
+
973
+ ## Constraints & Assumptions
974
+ - Budget constraints
975
+ - Technical limitations
976
+ - Team size and expertise
977
+ - Timeline constraints`
978
+ },
979
+ {
980
+ id: 'api',
981
+ name: 'REST API',
982
+ description: 'Template for REST API development projects',
983
+ category: 'backend',
984
+ content: `# Product Requirements Document - REST API
985
+
986
+ ## Overview
987
+ **API Name:** [Your API Name]
988
+ **Version:** v1.0
989
+ **Date:** ${new Date().toISOString().split('T')[0]}
990
+ **Author:** [Your Name]
991
+
992
+ ## Executive Summary
993
+ Description of the API's purpose, target users, and primary use cases.
994
+
995
+ ## API Goals
996
+ - Goal 1: Provide secure data access
997
+ - Goal 2: Ensure scalable architecture
998
+ - Goal 3: Maintain high availability (99.9% uptime)
999
+
1000
+ ## Functional Requirements
1001
+ ### Core Endpoints
1002
+ 1. **Authentication Endpoints**
1003
+ - POST /api/auth/login - User authentication
1004
+ - POST /api/auth/logout - User logout
1005
+ - POST /api/auth/refresh - Token refresh
1006
+ - POST /api/auth/register - User registration
1007
+
1008
+ 2. **Data Management Endpoints**
1009
+ - GET /api/resources - List resources with pagination
1010
+ - GET /api/resources/{id} - Get specific resource
1011
+ - POST /api/resources - Create new resource
1012
+ - PUT /api/resources/{id} - Update existing resource
1013
+ - DELETE /api/resources/{id} - Delete resource
1014
+
1015
+ 3. **Administrative Endpoints**
1016
+ - GET /api/admin/users - Manage users (admin only)
1017
+ - GET /api/admin/analytics - System analytics
1018
+ - POST /api/admin/backup - Trigger system backup
1019
+
1020
+ ## Technical Requirements
1021
+ ### API Design
1022
+ - RESTful architecture following OpenAPI 3.0 specification
1023
+ - JSON request/response format
1024
+ - Consistent error response format
1025
+ - API versioning strategy
1026
+
1027
+ ### Authentication & Security
1028
+ - JWT token-based authentication
1029
+ - Role-based access control (RBAC)
1030
+ - Rate limiting (100 requests/minute per user)
1031
+ - Input validation and sanitization
1032
+ - HTTPS enforcement
1033
+
1034
+ ### Database
1035
+ - Database type: [PostgreSQL/MongoDB/MySQL]
1036
+ - Connection pooling
1037
+ - Database migrations
1038
+ - Backup and recovery procedures
1039
+
1040
+ ### Performance Requirements
1041
+ - Response time: < 200ms for 95% of requests
1042
+ - Throughput: 1000+ requests/second
1043
+ - Concurrent users: 10,000+
1044
+ - Database query optimization
1045
+
1046
+ ### Documentation
1047
+ - Auto-generated API documentation (Swagger/OpenAPI)
1048
+ - Code examples for common use cases
1049
+ - SDK development for major languages
1050
+ - Postman collection for testing
1051
+
1052
+ ## Error Handling
1053
+ - Standardized error codes and messages
1054
+ - Proper HTTP status codes
1055
+ - Detailed error logging
1056
+ - Graceful degradation strategies
1057
+
1058
+ ## Testing Strategy
1059
+ - Unit tests (80%+ coverage)
1060
+ - Integration tests for all endpoints
1061
+ - Load testing and performance testing
1062
+ - Security testing (OWASP compliance)
1063
+
1064
+ ## Monitoring & Logging
1065
+ - Application performance monitoring
1066
+ - Error tracking and alerting
1067
+ - Access logs and audit trails
1068
+ - Health check endpoints
1069
+
1070
+ ## Deployment
1071
+ - Containerized deployment (Docker)
1072
+ - CI/CD pipeline setup
1073
+ - Environment management (dev, staging, prod)
1074
+ - Blue-green deployment strategy
1075
+
1076
+ ## Success Metrics
1077
+ - API uptime > 99.9%
1078
+ - Average response time < 200ms
1079
+ - Zero critical security vulnerabilities
1080
+ - Developer adoption metrics`
1081
+ },
1082
+ {
1083
+ id: 'mobile-app',
1084
+ name: 'Mobile Application',
1085
+ description: 'Template for mobile app development projects (iOS/Android)',
1086
+ category: 'mobile',
1087
+ content: `# Product Requirements Document - Mobile Application
1088
+
1089
+ ## Overview
1090
+ **App Name:** [Your App Name]
1091
+ **Platform:** iOS / Android / Cross-platform
1092
+ **Version:** 1.0
1093
+ **Date:** ${new Date().toISOString().split('T')[0]}
1094
+ **Author:** [Your Name]
1095
+
1096
+ ## Executive Summary
1097
+ Brief description of the mobile app's purpose, target audience, and key value proposition.
1098
+
1099
+ ## Product Goals
1100
+ - Goal 1: [Specific user engagement goal]
1101
+ - Goal 2: [Specific functionality goal]
1102
+ - Goal 3: [Specific performance goal]
1103
+
1104
+ ## User Stories
1105
+ ### Core Features
1106
+ 1. **Onboarding & Authentication**
1107
+ - As a new user, I want a simple onboarding process
1108
+ - As a user, I want to sign up with email or social media
1109
+ - As a user, I want biometric authentication for security
1110
+
1111
+ 2. **Main App Features**
1112
+ - As a user, I want [core feature 1] accessible from home screen
1113
+ - As a user, I want [core feature 2] to work offline
1114
+ - As a user, I want to sync data across devices
1115
+
1116
+ 3. **User Experience**
1117
+ - As a user, I want intuitive navigation patterns
1118
+ - As a user, I want fast loading times
1119
+ - As a user, I want accessibility features
1120
+
1121
+ ## Technical Requirements
1122
+ ### Mobile Development
1123
+ - **Cross-platform:** React Native / Flutter / Xamarin
1124
+ - **Native:** Swift (iOS) / Kotlin (Android)
1125
+ - **State Management:** Redux / MobX / Provider
1126
+ - **Navigation:** React Navigation / Flutter Navigation
1127
+
1128
+ ### Backend Integration
1129
+ - REST API or GraphQL integration
1130
+ - Real-time features (WebSockets/Push notifications)
1131
+ - Offline data synchronization
1132
+ - Background processing
1133
+
1134
+ ### Device Features
1135
+ - Camera and photo library access
1136
+ - GPS location services
1137
+ - Push notifications
1138
+ - Biometric authentication
1139
+ - Device storage
1140
+
1141
+ ### Performance Requirements
1142
+ - App launch time < 3 seconds
1143
+ - Screen transition animations < 300ms
1144
+ - Memory usage optimization
1145
+ - Battery usage optimization
1146
+
1147
+ ## Platform-Specific Considerations
1148
+ ### iOS Requirements
1149
+ - iOS 13.0+ minimum version
1150
+ - App Store guidelines compliance
1151
+ - iOS design guidelines (Human Interface Guidelines)
1152
+ - TestFlight beta testing
1153
+
1154
+ ### Android Requirements
1155
+ - Android 8.0+ (API level 26) minimum
1156
+ - Google Play Store guidelines
1157
+ - Material Design guidelines
1158
+ - Google Play Console testing
1159
+
1160
+ ## User Interface Design
1161
+ - Responsive design for different screen sizes
1162
+ - Dark mode support
1163
+ - Accessibility compliance (WCAG 2.1)
1164
+ - Consistent design system
1165
+
1166
+ ## Security & Privacy
1167
+ - Secure data storage (Keychain/Keystore)
1168
+ - API communication encryption
1169
+ - Privacy policy compliance (GDPR/CCPA)
1170
+ - App security best practices
1171
+
1172
+ ## Testing Strategy
1173
+ - Unit testing (80%+ coverage)
1174
+ - UI/E2E testing (Detox/Appium)
1175
+ - Device testing on multiple screen sizes
1176
+ - Performance testing
1177
+ - Security testing
1178
+
1179
+ ## App Store Deployment
1180
+ - App store optimization (ASO)
1181
+ - App icons and screenshots
1182
+ - Store listing content
1183
+ - Release management strategy
1184
+
1185
+ ## Analytics & Monitoring
1186
+ - User analytics (Firebase/Analytics)
1187
+ - Crash reporting (Crashlytics/Sentry)
1188
+ - Performance monitoring
1189
+ - User feedback collection
1190
+
1191
+ ## Success Metrics
1192
+ - App store ratings > 4.0
1193
+ - User retention rates
1194
+ - Daily/Monthly active users
1195
+ - App performance metrics
1196
+ - Conversion rates`
1197
+ },
1198
+ {
1199
+ id: 'data-analysis',
1200
+ name: 'Data Analysis Project',
1201
+ description: 'Template for data analysis and visualization projects',
1202
+ category: 'data',
1203
+ content: `# Product Requirements Document - Data Analysis Project
1204
+
1205
+ ## Overview
1206
+ **Project Name:** [Your Analysis Project]
1207
+ **Analysis Type:** [Descriptive/Predictive/Prescriptive]
1208
+ **Date:** ${new Date().toISOString().split('T')[0]}
1209
+ **Author:** [Your Name]
1210
+
1211
+ ## Executive Summary
1212
+ Description of the business problem, data sources, and expected insights.
1213
+
1214
+ ## Project Goals
1215
+ - Goal 1: [Specific business question to answer]
1216
+ - Goal 2: [Specific prediction to make]
1217
+ - Goal 3: [Specific recommendation to provide]
1218
+
1219
+ ## Business Requirements
1220
+ ### Key Questions
1221
+ 1. What patterns exist in the current data?
1222
+ 2. What factors influence [target variable]?
1223
+ 3. What predictions can be made for [future outcome]?
1224
+ 4. What recommendations can improve [business metric]?
1225
+
1226
+ ### Success Criteria
1227
+ - Actionable insights for stakeholders
1228
+ - Statistical significance in findings
1229
+ - Reproducible analysis pipeline
1230
+ - Clear visualization and reporting
1231
+
1232
+ ## Data Requirements
1233
+ ### Data Sources
1234
+ 1. **Primary Data**
1235
+ - Source: [Database/API/Files]
1236
+ - Format: [CSV/JSON/SQL]
1237
+ - Size: [Volume estimate]
1238
+ - Update frequency: [Real-time/Daily/Monthly]
1239
+
1240
+ 2. **External Data**
1241
+ - Third-party APIs
1242
+ - Public datasets
1243
+ - Market research data
1244
+
1245
+ ### Data Quality Requirements
1246
+ - Data completeness (< 5% missing values)
1247
+ - Data accuracy validation
1248
+ - Data consistency checks
1249
+ - Historical data availability
1250
+
1251
+ ## Technical Requirements
1252
+ ### Data Pipeline
1253
+ - Data extraction and ingestion
1254
+ - Data cleaning and preprocessing
1255
+ - Data transformation and feature engineering
1256
+ - Data validation and quality checks
1257
+
1258
+ ### Analysis Tools
1259
+ - **Programming:** Python/R/SQL
1260
+ - **Libraries:** pandas, numpy, scikit-learn, matplotlib
1261
+ - **Visualization:** Tableau, PowerBI, or custom dashboards
1262
+ - **Version Control:** Git for code and DVC for data
1263
+
1264
+ ### Computing Resources
1265
+ - Local development environment
1266
+ - Cloud computing (AWS/GCP/Azure) if needed
1267
+ - Database access and permissions
1268
+ - Storage requirements
1269
+
1270
+ ## Analysis Methodology
1271
+ ### Data Exploration
1272
+ 1. Descriptive statistics and data profiling
1273
+ 2. Data visualization and pattern identification
1274
+ 3. Correlation analysis
1275
+ 4. Outlier detection and handling
1276
+
1277
+ ### Statistical Analysis
1278
+ 1. Hypothesis formulation
1279
+ 2. Statistical testing
1280
+ 3. Confidence intervals
1281
+ 4. Effect size calculations
1282
+
1283
+ ### Machine Learning (if applicable)
1284
+ 1. Feature selection and engineering
1285
+ 2. Model selection and training
1286
+ 3. Cross-validation and evaluation
1287
+ 4. Model interpretation and explainability
1288
+
1289
+ ## Deliverables
1290
+ ### Reports
1291
+ - Executive summary for stakeholders
1292
+ - Technical analysis report
1293
+ - Data quality report
1294
+ - Methodology documentation
1295
+
1296
+ ### Visualizations
1297
+ - Interactive dashboards
1298
+ - Static charts and graphs
1299
+ - Data story presentations
1300
+ - Key findings infographics
1301
+
1302
+ ### Code & Documentation
1303
+ - Reproducible analysis scripts
1304
+ - Data pipeline code
1305
+ - Documentation and comments
1306
+ - Testing and validation code
1307
+
1308
+ ## Timeline
1309
+ - Phase 1: Data collection and exploration (2 weeks)
1310
+ - Phase 2: Analysis and modeling (3 weeks)
1311
+ - Phase 3: Reporting and visualization (1 week)
1312
+ - Phase 4: Stakeholder presentation (1 week)
1313
+
1314
+ ## Risks & Assumptions
1315
+ - Data availability and quality risks
1316
+ - Technical complexity assumptions
1317
+ - Resource and timeline constraints
1318
+ - Stakeholder engagement assumptions
1319
+
1320
+ ## Success Metrics
1321
+ - Stakeholder satisfaction with insights
1322
+ - Accuracy of predictions (if applicable)
1323
+ - Business impact of recommendations
1324
+ - Reproducibility of results`
1325
+ }
1326
+ ];
1327
+
1328
+ res.json({
1329
+ templates,
1330
+ timestamp: new Date().toISOString()
1331
+ });
1332
+
1333
+ } catch (error) {
1334
+ console.error('PRD templates error:', error);
1335
+ res.status(500).json({
1336
+ error: 'Failed to get PRD templates',
1337
+ message: error.message
1338
+ });
1339
+ }
1340
+ });
1341
+
1342
+ /**
1343
+ * POST /api/taskmaster/apply-template/:projectName
1344
+ * Apply a PRD template to create a new PRD file
1345
+ */
1346
+ router.post('/apply-template/:projectName', async (req, res) => {
1347
+ try {
1348
+ const { projectName } = req.params;
1349
+ const { templateId, fileName = 'prd.txt', customizations = {} } = req.body;
1350
+
1351
+ if (!templateId) {
1352
+ return res.status(400).json({
1353
+ error: 'Missing required parameter',
1354
+ message: 'templateId is required'
1355
+ });
1356
+ }
1357
+
1358
+ // Get project path
1359
+ let projectPath;
1360
+ try {
1361
+ projectPath = await extractProjectDirectory(projectName);
1362
+ } catch (error) {
1363
+ return res.status(404).json({
1364
+ error: 'Project not found',
1365
+ message: `Project "${projectName}" does not exist`
1366
+ });
1367
+ }
1368
+
1369
+ // Get the template content (this would normally fetch from the templates list)
1370
+ const templates = await getAvailableTemplates();
1371
+ const template = templates.find(t => t.id === templateId);
1372
+
1373
+ if (!template) {
1374
+ return res.status(404).json({
1375
+ error: 'Template not found',
1376
+ message: `Template "${templateId}" does not exist`
1377
+ });
1378
+ }
1379
+
1380
+ // Apply customizations to template content
1381
+ let content = template.content;
1382
+
1383
+ // Replace placeholders with customizations
1384
+ for (const [key, value] of Object.entries(customizations)) {
1385
+ const placeholder = `[${key}]`;
1386
+ content = content.replace(new RegExp(placeholder.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'), 'g'), value);
1387
+ }
1388
+
1389
+ // Ensure .taskmaster/docs directory exists
1390
+ const docsDir = path.join(projectPath, '.taskmaster', 'docs');
1391
+ try {
1392
+ await fsPromises.mkdir(docsDir, { recursive: true });
1393
+ } catch (error) {
1394
+ console.error('Failed to create docs directory:', error);
1395
+ }
1396
+
1397
+ const filePath = path.join(docsDir, fileName);
1398
+
1399
+ // Write the template content to the file
1400
+ try {
1401
+ await fsPromises.writeFile(filePath, content, 'utf8');
1402
+
1403
+ res.json({
1404
+ projectName,
1405
+ projectPath,
1406
+ templateId,
1407
+ templateName: template.name,
1408
+ fileName,
1409
+ filePath: filePath,
1410
+ message: 'PRD template applied successfully',
1411
+ timestamp: new Date().toISOString()
1412
+ });
1413
+
1414
+ } catch (writeError) {
1415
+ console.error('Failed to write PRD template:', writeError);
1416
+ return res.status(500).json({
1417
+ error: 'Failed to write PRD template',
1418
+ message: writeError.message
1419
+ });
1420
+ }
1421
+
1422
+ } catch (error) {
1423
+ console.error('Apply template error:', error);
1424
+ res.status(500).json({
1425
+ error: 'Failed to apply PRD template',
1426
+ message: error.message
1427
+ });
1428
+ }
1429
+ });
1430
+
1431
+ // Helper function to get available templates
1432
+ async function getAvailableTemplates() {
1433
+ // This could be extended to read from files or database
1434
+ return [
1435
+ {
1436
+ id: 'web-app',
1437
+ name: 'Web Application',
1438
+ description: 'Template for web application projects',
1439
+ category: 'web',
1440
+ content: `# Product Requirements Document - Web Application
1441
+
1442
+ ## Overview
1443
+ **Product Name:** [Your App Name]
1444
+ **Version:** 1.0
1445
+ **Date:** ${new Date().toISOString().split('T')[0]}
1446
+ **Author:** [Your Name]
1447
+
1448
+ ## Executive Summary
1449
+ Brief description of what this web application will do and why it's needed.
1450
+
1451
+ ## User Stories
1452
+ 1. As a user, I want [feature] so I can [benefit]
1453
+ 2. As a user, I want [feature] so I can [benefit]
1454
+ 3. As a user, I want [feature] so I can [benefit]
1455
+
1456
+ ## Technical Requirements
1457
+ - Frontend framework
1458
+ - Backend services
1459
+ - Database requirements
1460
+ - Security considerations
1461
+
1462
+ ## Success Metrics
1463
+ - User engagement metrics
1464
+ - Performance benchmarks
1465
+ - Business objectives`
1466
+ },
1467
+ // Add other templates here if needed
1468
+ ];
1469
+ }
1470
+
1471
+ export default router;