@cloudcli-ai/cloudcli 1.30.0 → 1.31.1

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 (238) hide show
  1. package/README.md +1 -1
  2. package/dist/assets/index-B37ufcoi.js +1262 -0
  3. package/dist/assets/{index-DI22MZMb.css → index-DF8TTVHl.css} +1 -1
  4. package/dist/index.html +2 -2
  5. package/dist-server/server/index.js +115 -955
  6. package/dist-server/server/index.js.map +1 -1
  7. package/dist-server/server/middleware/auth.js +1 -1
  8. package/dist-server/server/middleware/auth.js.map +1 -1
  9. package/dist-server/server/modules/database/connection.js +125 -0
  10. package/dist-server/server/modules/database/connection.js.map +1 -0
  11. package/dist-server/server/modules/database/index.js +13 -0
  12. package/dist-server/server/modules/database/index.js.map +1 -0
  13. package/dist-server/server/modules/database/init-db.js +18 -0
  14. package/dist-server/server/modules/database/init-db.js.map +1 -0
  15. package/dist-server/server/modules/database/migrations.js +370 -0
  16. package/dist-server/server/modules/database/migrations.js.map +1 -0
  17. package/dist-server/server/modules/database/repositories/api-keys.js +72 -0
  18. package/dist-server/server/modules/database/repositories/api-keys.js.map +1 -0
  19. package/dist-server/server/modules/database/repositories/app-config.js +47 -0
  20. package/dist-server/server/modules/database/repositories/app-config.js.map +1 -0
  21. package/dist-server/server/modules/database/repositories/credentials.js +68 -0
  22. package/dist-server/server/modules/database/repositories/credentials.js.map +1 -0
  23. package/dist-server/server/modules/database/repositories/github-tokens.js +54 -0
  24. package/dist-server/server/modules/database/repositories/github-tokens.js.map +1 -0
  25. package/dist-server/server/modules/database/repositories/notification-preferences.js +72 -0
  26. package/dist-server/server/modules/database/repositories/notification-preferences.js.map +1 -0
  27. package/dist-server/server/modules/database/repositories/projects.db.integration.test.js +64 -0
  28. package/dist-server/server/modules/database/repositories/projects.db.integration.test.js.map +1 -0
  29. package/dist-server/server/modules/database/repositories/projects.db.js +160 -0
  30. package/dist-server/server/modules/database/repositories/projects.db.js.map +1 -0
  31. package/dist-server/server/modules/database/repositories/push-subscriptions.js +49 -0
  32. package/dist-server/server/modules/database/repositories/push-subscriptions.js.map +1 -0
  33. package/dist-server/server/modules/database/repositories/scan-state.db.js +31 -0
  34. package/dist-server/server/modules/database/repositories/scan-state.db.js.map +1 -0
  35. package/dist-server/server/modules/database/repositories/sessions.db.js +109 -0
  36. package/dist-server/server/modules/database/repositories/sessions.db.js.map +1 -0
  37. package/dist-server/server/modules/database/repositories/users.js +88 -0
  38. package/dist-server/server/modules/database/repositories/users.js.map +1 -0
  39. package/dist-server/server/modules/database/repositories/vapid-keys.js +38 -0
  40. package/dist-server/server/modules/database/repositories/vapid-keys.js.map +1 -0
  41. package/dist-server/server/modules/database/schema.js +143 -0
  42. package/dist-server/server/modules/database/schema.js.map +1 -0
  43. package/dist-server/server/modules/projects/index.js +4 -0
  44. package/dist-server/server/modules/projects/index.js.map +1 -0
  45. package/dist-server/server/modules/projects/projects.routes.js +188 -0
  46. package/dist-server/server/modules/projects/projects.routes.js.map +1 -0
  47. package/dist-server/server/modules/projects/services/project-clone.service.js +219 -0
  48. package/dist-server/server/modules/projects/services/project-clone.service.js.map +1 -0
  49. package/dist-server/server/modules/projects/services/project-delete.service.js +65 -0
  50. package/dist-server/server/modules/projects/services/project-delete.service.js.map +1 -0
  51. package/dist-server/server/modules/projects/services/project-management.service.js +93 -0
  52. package/dist-server/server/modules/projects/services/project-management.service.js.map +1 -0
  53. package/dist-server/server/modules/projects/services/project-star.service.js +60 -0
  54. package/dist-server/server/modules/projects/services/project-star.service.js.map +1 -0
  55. package/dist-server/server/modules/projects/services/projects-has-taskmaster.service.js +167 -0
  56. package/dist-server/server/modules/projects/services/projects-has-taskmaster.service.js.map +1 -0
  57. package/dist-server/server/modules/projects/services/projects-with-sessions-fetch.service.js +169 -0
  58. package/dist-server/server/modules/projects/services/projects-with-sessions-fetch.service.js.map +1 -0
  59. package/dist-server/server/modules/projects/tests/project-clone.service.test.js +126 -0
  60. package/dist-server/server/modules/projects/tests/project-clone.service.test.js.map +1 -0
  61. package/dist-server/server/modules/projects/tests/project-management.service.test.js +85 -0
  62. package/dist-server/server/modules/projects/tests/project-management.service.test.js.map +1 -0
  63. package/dist-server/server/modules/projects/tests/project-star.service.test.js +95 -0
  64. package/dist-server/server/modules/projects/tests/project-star.service.test.js.map +1 -0
  65. package/dist-server/server/modules/projects/tests/projects-has-taskmaster.service.test.js +87 -0
  66. package/dist-server/server/modules/projects/tests/projects-has-taskmaster.service.test.js.map +1 -0
  67. package/dist-server/server/modules/providers/index.js +4 -0
  68. package/dist-server/server/modules/providers/index.js.map +1 -0
  69. package/dist-server/server/modules/providers/list/claude/claude-session-synchronizer.provider.js +63 -0
  70. package/dist-server/server/modules/providers/list/claude/claude-session-synchronizer.provider.js.map +1 -0
  71. package/dist-server/server/modules/providers/list/claude/claude-sessions.provider.js +144 -7
  72. package/dist-server/server/modules/providers/list/claude/claude-sessions.provider.js.map +1 -1
  73. package/dist-server/server/modules/providers/list/claude/claude.provider.js +2 -0
  74. package/dist-server/server/modules/providers/list/claude/claude.provider.js.map +1 -1
  75. package/dist-server/server/modules/providers/list/codex/codex-session-synchronizer.provider.js +71 -0
  76. package/dist-server/server/modules/providers/list/codex/codex-session-synchronizer.provider.js.map +1 -0
  77. package/dist-server/server/modules/providers/list/codex/codex-sessions.provider.js +225 -13
  78. package/dist-server/server/modules/providers/list/codex/codex-sessions.provider.js.map +1 -1
  79. package/dist-server/server/modules/providers/list/codex/codex.provider.js +2 -0
  80. package/dist-server/server/modules/providers/list/codex/codex.provider.js.map +1 -1
  81. package/dist-server/server/modules/providers/list/cursor/cursor-session-synchronizer.provider.js +127 -0
  82. package/dist-server/server/modules/providers/list/cursor/cursor-session-synchronizer.provider.js.map +1 -0
  83. package/dist-server/server/modules/providers/list/cursor/cursor.provider.js +2 -0
  84. package/dist-server/server/modules/providers/list/cursor/cursor.provider.js.map +1 -1
  85. package/dist-server/server/modules/providers/list/gemini/gemini-session-synchronizer.provider.js +296 -0
  86. package/dist-server/server/modules/providers/list/gemini/gemini-session-synchronizer.provider.js.map +1 -0
  87. package/dist-server/server/modules/providers/list/gemini/gemini-sessions.provider.js +277 -10
  88. package/dist-server/server/modules/providers/list/gemini/gemini-sessions.provider.js.map +1 -1
  89. package/dist-server/server/modules/providers/list/gemini/gemini.provider.js +2 -0
  90. package/dist-server/server/modules/providers/list/gemini/gemini.provider.js.map +1 -1
  91. package/dist-server/server/modules/providers/provider.routes.js +172 -0
  92. package/dist-server/server/modules/providers/provider.routes.js.map +1 -1
  93. package/dist-server/server/modules/providers/services/session-conversations-search.service.js +868 -0
  94. package/dist-server/server/modules/providers/services/session-conversations-search.service.js.map +1 -0
  95. package/dist-server/server/modules/providers/services/session-synchronizer.service.js +56 -0
  96. package/dist-server/server/modules/providers/services/session-synchronizer.service.js.map +1 -0
  97. package/dist-server/server/modules/providers/services/sessions-watcher.service.js +234 -0
  98. package/dist-server/server/modules/providers/services/sessions-watcher.service.js.map +1 -0
  99. package/dist-server/server/modules/providers/services/sessions.service.js +78 -3
  100. package/dist-server/server/modules/providers/services/sessions.service.js.map +1 -1
  101. package/dist-server/server/modules/providers/shared/base/abstract.provider.js.map +1 -1
  102. package/dist-server/server/modules/websocket/index.js +3 -0
  103. package/dist-server/server/modules/websocket/index.js.map +1 -0
  104. package/dist-server/server/modules/websocket/services/chat-websocket.service.js +188 -0
  105. package/dist-server/server/modules/websocket/services/chat-websocket.service.js.map +1 -0
  106. package/dist-server/server/modules/websocket/services/plugin-websocket-proxy.service.js +52 -0
  107. package/dist-server/server/modules/websocket/services/plugin-websocket-proxy.service.js.map +1 -0
  108. package/dist-server/server/modules/websocket/services/shell-websocket.service.js +334 -0
  109. package/dist-server/server/modules/websocket/services/shell-websocket.service.js.map +1 -0
  110. package/dist-server/server/modules/websocket/services/websocket-auth.service.js +32 -0
  111. package/dist-server/server/modules/websocket/services/websocket-auth.service.js.map +1 -0
  112. package/dist-server/server/modules/websocket/services/websocket-server.service.js +36 -0
  113. package/dist-server/server/modules/websocket/services/websocket-server.service.js.map +1 -0
  114. package/dist-server/server/modules/websocket/services/websocket-state.service.js +14 -0
  115. package/dist-server/server/modules/websocket/services/websocket-state.service.js.map +1 -0
  116. package/dist-server/server/modules/websocket/services/websocket-writer.service.js +32 -0
  117. package/dist-server/server/modules/websocket/services/websocket-writer.service.js.map +1 -0
  118. package/dist-server/server/routes/agent.js +10 -17
  119. package/dist-server/server/routes/agent.js.map +1 -1
  120. package/dist-server/server/routes/auth.js +3 -1
  121. package/dist-server/server/routes/auth.js.map +1 -1
  122. package/dist-server/server/routes/commands.js +1 -1
  123. package/dist-server/server/routes/commands.js.map +1 -1
  124. package/dist-server/server/routes/gemini.js +2 -2
  125. package/dist-server/server/routes/gemini.js.map +1 -1
  126. package/dist-server/server/routes/git.js +33 -29
  127. package/dist-server/server/routes/git.js.map +1 -1
  128. package/dist-server/server/routes/settings.js +1 -1
  129. package/dist-server/server/routes/settings.js.map +1 -1
  130. package/dist-server/server/routes/taskmaster.js +97 -110
  131. package/dist-server/server/routes/taskmaster.js.map +1 -1
  132. package/dist-server/server/routes/user.js +1 -1
  133. package/dist-server/server/routes/user.js.map +1 -1
  134. package/dist-server/server/services/notification-orchestrator.js +2 -2
  135. package/dist-server/server/services/notification-orchestrator.js.map +1 -1
  136. package/dist-server/server/services/vapid-keys.js +2 -1
  137. package/dist-server/server/services/vapid-keys.js.map +1 -1
  138. package/dist-server/server/shared/types.js +0 -1
  139. package/dist-server/server/shared/types.js.map +1 -1
  140. package/dist-server/server/shared/utils.js +408 -7
  141. package/dist-server/server/shared/utils.js.map +1 -1
  142. package/dist-server/server/utils/taskmaster-websocket.js +18 -12
  143. package/dist-server/server/utils/taskmaster-websocket.js.map +1 -1
  144. package/dist-server/shared/modelConstants.js +2 -1
  145. package/dist-server/shared/modelConstants.js.map +1 -1
  146. package/package.json +3 -1
  147. package/server/index.js +146 -1012
  148. package/server/middleware/auth.js +1 -1
  149. package/server/modules/database/connection.ts +143 -0
  150. package/server/modules/database/index.ts +12 -0
  151. package/server/modules/database/init-db.ts +17 -0
  152. package/server/modules/database/migrations.ts +442 -0
  153. package/server/modules/database/repositories/api-keys.ts +119 -0
  154. package/server/modules/database/repositories/app-config.ts +53 -0
  155. package/server/modules/database/repositories/credentials.ts +106 -0
  156. package/server/modules/database/repositories/github-tokens.ts +100 -0
  157. package/server/modules/database/repositories/notification-preferences.ts +103 -0
  158. package/server/modules/database/repositories/projects.db.integration.test.ts +72 -0
  159. package/server/modules/database/repositories/projects.db.ts +183 -0
  160. package/server/modules/database/repositories/push-subscriptions.ts +80 -0
  161. package/server/modules/database/repositories/scan-state.db.ts +42 -0
  162. package/server/modules/database/repositories/sessions.db.ts +174 -0
  163. package/server/modules/database/repositories/users.ts +140 -0
  164. package/server/modules/database/repositories/vapid-keys.ts +57 -0
  165. package/server/modules/database/schema.ts +152 -0
  166. package/server/modules/projects/index.ts +6 -0
  167. package/server/modules/projects/projects.routes.ts +247 -0
  168. package/server/modules/projects/services/project-clone.service.ts +321 -0
  169. package/server/modules/projects/services/project-delete.service.ts +75 -0
  170. package/server/modules/projects/services/project-management.service.ts +150 -0
  171. package/server/modules/projects/services/project-star.service.ts +78 -0
  172. package/server/modules/projects/services/projects-has-taskmaster.service.ts +248 -0
  173. package/server/modules/projects/services/projects-with-sessions-fetch.service.ts +285 -0
  174. package/server/modules/projects/tests/project-clone.service.test.ts +183 -0
  175. package/server/modules/projects/tests/project-management.service.test.ts +117 -0
  176. package/server/modules/projects/tests/project-star.service.test.ts +123 -0
  177. package/server/modules/projects/tests/projects-has-taskmaster.service.test.ts +105 -0
  178. package/server/modules/providers/index.ts +4 -0
  179. package/server/modules/providers/list/claude/claude-session-synchronizer.provider.ts +110 -0
  180. package/server/modules/providers/list/claude/claude-sessions.provider.ts +182 -13
  181. package/server/modules/providers/list/claude/claude.provider.ts +3 -1
  182. package/server/modules/providers/list/codex/codex-session-synchronizer.provider.ts +119 -0
  183. package/server/modules/providers/list/codex/codex-sessions.provider.ts +262 -17
  184. package/server/modules/providers/list/codex/codex.provider.ts +3 -1
  185. package/server/modules/providers/list/cursor/cursor-session-synchronizer.provider.ts +176 -0
  186. package/server/modules/providers/list/cursor/cursor.provider.ts +3 -1
  187. package/server/modules/providers/list/gemini/gemini-session-synchronizer.provider.ts +401 -0
  188. package/server/modules/providers/list/gemini/gemini-sessions.provider.ts +327 -13
  189. package/server/modules/providers/list/gemini/gemini.provider.ts +3 -1
  190. package/server/modules/providers/provider.routes.ts +220 -12
  191. package/server/modules/providers/services/session-conversations-search.service.ts +1167 -0
  192. package/server/modules/providers/services/session-synchronizer.service.ts +74 -0
  193. package/server/modules/providers/services/sessions-watcher.service.ts +283 -0
  194. package/server/modules/providers/services/sessions.service.ts +89 -4
  195. package/server/modules/providers/shared/base/abstract.provider.ts +8 -1
  196. package/server/modules/websocket/README.md +267 -0
  197. package/server/modules/websocket/index.ts +2 -0
  198. package/server/modules/websocket/services/chat-websocket.service.ts +271 -0
  199. package/server/modules/websocket/services/plugin-websocket-proxy.service.ts +65 -0
  200. package/server/modules/websocket/services/shell-websocket.service.ts +453 -0
  201. package/server/modules/websocket/services/websocket-auth.service.ts +54 -0
  202. package/server/modules/websocket/services/websocket-server.service.ts +58 -0
  203. package/server/modules/websocket/services/websocket-state.service.ts +16 -0
  204. package/server/modules/websocket/services/websocket-writer.service.ts +38 -0
  205. package/server/routes/agent.js +11 -16
  206. package/server/routes/auth.js +4 -2
  207. package/server/routes/commands.js +1 -1
  208. package/server/routes/gemini.js +3 -2
  209. package/server/routes/git.js +33 -28
  210. package/server/routes/settings.js +1 -1
  211. package/server/routes/taskmaster.js +108 -111
  212. package/server/routes/user.js +1 -1
  213. package/server/services/notification-orchestrator.js +3 -2
  214. package/server/services/vapid-keys.js +2 -1
  215. package/server/shared/interfaces.ts +39 -1
  216. package/server/shared/types.ts +185 -30
  217. package/server/shared/utils.ts +485 -9
  218. package/server/utils/taskmaster-websocket.js +19 -13
  219. package/shared/modelConstants.js +2 -1
  220. package/dist/assets/index-RX-W_g_Q.js +0 -1262
  221. package/dist-server/server/database/db.js +0 -535
  222. package/dist-server/server/database/db.js.map +0 -1
  223. package/dist-server/server/database/schema.js +0 -97
  224. package/dist-server/server/database/schema.js.map +0 -1
  225. package/dist-server/server/projects.js +0 -2325
  226. package/dist-server/server/projects.js.map +0 -1
  227. package/dist-server/server/routes/codex.js +0 -18
  228. package/dist-server/server/routes/codex.js.map +0 -1
  229. package/dist-server/server/routes/messages.js +0 -56
  230. package/dist-server/server/routes/messages.js.map +0 -1
  231. package/dist-server/server/routes/projects.js +0 -505
  232. package/dist-server/server/routes/projects.js.map +0 -1
  233. package/server/database/db.js +0 -593
  234. package/server/database/schema.js +0 -102
  235. package/server/projects.js +0 -2555
  236. package/server/routes/codex.js +0 -19
  237. package/server/routes/messages.js +0 -61
  238. package/server/routes/projects.js +0 -548
@@ -13,10 +13,25 @@ import fs from 'fs';
13
13
  import path from 'path';
14
14
  import { promises as fsPromises } from 'fs';
15
15
  import { spawn } from 'child_process';
16
- import { extractProjectDirectory } from '../projects.js';
16
+ import { projectsDb } from '../modules/database/index.js';
17
17
  import { detectTaskMasterMCPServer } from '../utils/mcp-detector.js';
18
18
  import { broadcastTaskMasterProjectUpdate, broadcastTaskMasterTasksUpdate } from '../utils/taskmaster-websocket.js';
19
19
 
20
+ /**
21
+ * Resolve the absolute project directory from a DB-assigned `projectId`.
22
+ *
23
+ * TaskMaster routes used to accept a Claude-encoded folder name (`projectName`)
24
+ * and derive the path from JSONL history. After the projectId migration the
25
+ * only identifier we accept is the primary key of the `projects` table, so
26
+ * every handler calls this helper and 404s when the id is unknown.
27
+ */
28
+ async function resolveProjectPathFromId(projectId) {
29
+ if (!projectId) {
30
+ return null;
31
+ }
32
+ return projectsDb.getProjectPathById(projectId);
33
+ }
34
+
20
35
  const router = express.Router();
21
36
 
22
37
  /**
@@ -132,21 +147,22 @@ router.get('/installation-status', async (req, res) => {
132
147
  });
133
148
 
134
149
  /**
135
- * GET /api/taskmaster/tasks/:projectName
150
+ * GET /api/taskmaster/tasks/:projectId
136
151
  * Load actual tasks from .taskmaster/tasks/tasks.json
152
+ *
153
+ * `projectId` is the DB primary key of the project; the folder is resolved via
154
+ * the projects table rather than extracted from Claude JSONL history.
137
155
  */
138
- router.get('/tasks/:projectName', async (req, res) => {
156
+ router.get('/tasks/:projectId', async (req, res) => {
139
157
  try {
140
- const { projectName } = req.params;
141
-
142
- // Get project path
143
- let projectPath;
144
- try {
145
- projectPath = await extractProjectDirectory(projectName);
146
- } catch (error) {
158
+ const { projectId } = req.params;
159
+
160
+ // Get project path via the DB; the legacy JSONL-based resolver is gone.
161
+ const projectPath = await resolveProjectPathFromId(projectId);
162
+ if (!projectPath) {
147
163
  return res.status(404).json({
148
164
  error: 'Project not found',
149
- message: `Project "${projectName}" does not exist`
165
+ message: `Project "${projectId}" does not exist`
150
166
  });
151
167
  }
152
168
 
@@ -158,7 +174,7 @@ router.get('/tasks/:projectName', async (req, res) => {
158
174
  await fsPromises.access(tasksFilePath);
159
175
  } catch (error) {
160
176
  return res.json({
161
- projectName,
177
+ projectId,
162
178
  tasks: [],
163
179
  message: 'No tasks.json file found'
164
180
  });
@@ -213,7 +229,7 @@ router.get('/tasks/:projectName', async (req, res) => {
213
229
  }));
214
230
 
215
231
  res.json({
216
- projectName,
232
+ projectId,
217
233
  projectPath,
218
234
  tasks: transformedTasks,
219
235
  currentTag,
@@ -247,21 +263,19 @@ router.get('/tasks/:projectName', async (req, res) => {
247
263
  });
248
264
 
249
265
  /**
250
- * GET /api/taskmaster/prd/:projectName
266
+ * GET /api/taskmaster/prd/:projectId
251
267
  * List all PRD files in the project's .taskmaster/docs directory
252
268
  */
253
- router.get('/prd/:projectName', async (req, res) => {
269
+ router.get('/prd/:projectId', async (req, res) => {
254
270
  try {
255
- const { projectName } = req.params;
256
-
257
- // Get project path
258
- let projectPath;
259
- try {
260
- projectPath = await extractProjectDirectory(projectName);
261
- } catch (error) {
271
+ const { projectId } = req.params;
272
+
273
+ // projectId projectPath lookup through the DB (post-migration).
274
+ const projectPath = await resolveProjectPathFromId(projectId);
275
+ if (!projectPath) {
262
276
  return res.status(404).json({
263
277
  error: 'Project not found',
264
- message: `Project "${projectName}" does not exist`
278
+ message: `Project "${projectId}" does not exist`
265
279
  });
266
280
  }
267
281
 
@@ -272,7 +286,7 @@ router.get('/prd/:projectName', async (req, res) => {
272
286
  await fsPromises.access(docsPath, fs.constants.R_OK);
273
287
  } catch (error) {
274
288
  return res.json({
275
- projectName,
289
+ projectId,
276
290
  prdFiles: [],
277
291
  message: 'No .taskmaster/docs directory found'
278
292
  });
@@ -299,7 +313,7 @@ router.get('/prd/:projectName', async (req, res) => {
299
313
  }
300
314
 
301
315
  res.json({
302
- projectName,
316
+ projectId,
303
317
  projectPath,
304
318
  prdFiles: prdFiles.sort((a, b) => new Date(b.modified) - new Date(a.modified)),
305
319
  timestamp: new Date().toISOString()
@@ -323,12 +337,12 @@ router.get('/prd/:projectName', async (req, res) => {
323
337
  });
324
338
 
325
339
  /**
326
- * POST /api/taskmaster/prd/:projectName
340
+ * POST /api/taskmaster/prd/:projectId
327
341
  * Create or update a PRD file in the project's .taskmaster/docs directory
328
342
  */
329
- router.post('/prd/:projectName', async (req, res) => {
343
+ router.post('/prd/:projectId', async (req, res) => {
330
344
  try {
331
- const { projectName } = req.params;
345
+ const { projectId } = req.params;
332
346
  const { fileName, content } = req.body;
333
347
 
334
348
  if (!fileName || !content) {
@@ -346,14 +360,12 @@ router.post('/prd/:projectName', async (req, res) => {
346
360
  });
347
361
  }
348
362
 
349
- // Get project path
350
- let projectPath;
351
- try {
352
- projectPath = await extractProjectDirectory(projectName);
353
- } catch (error) {
363
+ // Resolve the project folder through the DB using the projectId param.
364
+ const projectPath = await resolveProjectPathFromId(projectId);
365
+ if (!projectPath) {
354
366
  return res.status(404).json({
355
367
  error: 'Project not found',
356
- message: `Project "${projectName}" does not exist`
368
+ message: `Project "${projectId}" does not exist`
357
369
  });
358
370
  }
359
371
 
@@ -379,7 +391,7 @@ router.post('/prd/:projectName', async (req, res) => {
379
391
  const stats = await fsPromises.stat(filePath);
380
392
 
381
393
  res.json({
382
- projectName,
394
+ projectId,
383
395
  projectPath,
384
396
  fileName,
385
397
  filePath: path.relative(projectPath, filePath),
@@ -408,21 +420,18 @@ router.post('/prd/:projectName', async (req, res) => {
408
420
  });
409
421
 
410
422
  /**
411
- * GET /api/taskmaster/prd/:projectName/:fileName
423
+ * GET /api/taskmaster/prd/:projectId/:fileName
412
424
  * Get content of a specific PRD file
413
425
  */
414
- router.get('/prd/:projectName/:fileName', async (req, res) => {
426
+ router.get('/prd/:projectId/:fileName', async (req, res) => {
415
427
  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) {
428
+ const { projectId, fileName } = req.params;
429
+
430
+ const projectPath = await resolveProjectPathFromId(projectId);
431
+ if (!projectPath) {
423
432
  return res.status(404).json({
424
433
  error: 'Project not found',
425
- message: `Project "${projectName}" does not exist`
434
+ message: `Project "${projectId}" does not exist`
426
435
  });
427
436
  }
428
437
 
@@ -444,7 +453,7 @@ router.get('/prd/:projectName/:fileName', async (req, res) => {
444
453
  const stats = await fsPromises.stat(filePath);
445
454
 
446
455
  res.json({
447
- projectName,
456
+ projectId,
448
457
  projectPath,
449
458
  fileName,
450
459
  filePath: path.relative(projectPath, filePath),
@@ -473,21 +482,18 @@ router.get('/prd/:projectName/:fileName', async (req, res) => {
473
482
  });
474
483
 
475
484
  /**
476
- * POST /api/taskmaster/init/:projectName
485
+ * POST /api/taskmaster/init/:projectId
477
486
  * Initialize TaskMaster in a project
478
487
  */
479
- router.post('/init/:projectName', async (req, res) => {
488
+ router.post('/init/:projectId', async (req, res) => {
480
489
  try {
481
- const { projectName } = req.params;
482
-
483
- // Get project path
484
- let projectPath;
485
- try {
486
- projectPath = await extractProjectDirectory(projectName);
487
- } catch (error) {
490
+ const { projectId } = req.params;
491
+
492
+ const projectPath = await resolveProjectPathFromId(projectId);
493
+ if (!projectPath) {
488
494
  return res.status(404).json({
489
495
  error: 'Project not found',
490
- message: `Project "${projectName}" does not exist`
496
+ message: `Project "${projectId}" does not exist`
491
497
  });
492
498
  }
493
499
 
@@ -522,17 +528,19 @@ router.post('/init/:projectName', async (req, res) => {
522
528
 
523
529
  initProcess.on('close', (code) => {
524
530
  if (code === 0) {
525
- // Broadcast TaskMaster project update via WebSocket
531
+ // Broadcast TaskMaster project update via WebSocket. The
532
+ // WebSocket payload keeps using `projectId` so the frontend
533
+ // can match notifications against the current selection.
526
534
  if (req.app.locals.wss) {
527
535
  broadcastTaskMasterProjectUpdate(
528
- req.app.locals.wss,
529
- projectName,
536
+ req.app.locals.wss,
537
+ projectId,
530
538
  { hasTaskmaster: true, status: 'initialized' }
531
539
  );
532
540
  }
533
541
 
534
542
  res.json({
535
- projectName,
543
+ projectId,
536
544
  projectPath,
537
545
  message: 'TaskMaster initialized successfully',
538
546
  output: stdout,
@@ -562,12 +570,12 @@ router.post('/init/:projectName', async (req, res) => {
562
570
  });
563
571
 
564
572
  /**
565
- * POST /api/taskmaster/add-task/:projectName
573
+ * POST /api/taskmaster/add-task/:projectId
566
574
  * Add a new task to the project
567
575
  */
568
- router.post('/add-task/:projectName', async (req, res) => {
576
+ router.post('/add-task/:projectId', async (req, res) => {
569
577
  try {
570
- const { projectName } = req.params;
578
+ const { projectId } = req.params;
571
579
  const { prompt, title, description, priority = 'medium', dependencies } = req.body;
572
580
 
573
581
  if (!prompt && (!title || !description)) {
@@ -576,15 +584,12 @@ router.post('/add-task/:projectName', async (req, res) => {
576
584
  message: 'Either "prompt" or both "title" and "description" are required'
577
585
  });
578
586
  }
579
-
580
- // Get project path
581
- let projectPath;
582
- try {
583
- projectPath = await extractProjectDirectory(projectName);
584
- } catch (error) {
587
+
588
+ const projectPath = await resolveProjectPathFromId(projectId);
589
+ if (!projectPath) {
585
590
  return res.status(404).json({
586
591
  error: 'Project not found',
587
- message: `Project "${projectName}" does not exist`
592
+ message: `Project "${projectId}" does not exist`
588
593
  });
589
594
  }
590
595
 
@@ -629,16 +634,17 @@ router.post('/add-task/:projectName', async (req, res) => {
629
634
  console.log('Stderr:', stderr);
630
635
 
631
636
  if (code === 0) {
632
- // Broadcast task update via WebSocket
637
+ // Broadcast task update via WebSocket using the projectId so
638
+ // clients subscribed to this project get notified immediately.
633
639
  if (req.app.locals.wss) {
634
640
  broadcastTaskMasterTasksUpdate(
635
- req.app.locals.wss,
636
- projectName
641
+ req.app.locals.wss,
642
+ projectId
637
643
  );
638
644
  }
639
645
 
640
646
  res.json({
641
- projectName,
647
+ projectId,
642
648
  projectPath,
643
649
  message: 'Task added successfully',
644
650
  output: stdout,
@@ -666,22 +672,19 @@ router.post('/add-task/:projectName', async (req, res) => {
666
672
  });
667
673
 
668
674
  /**
669
- * PUT /api/taskmaster/update-task/:projectName/:taskId
675
+ * PUT /api/taskmaster/update-task/:projectId/:taskId
670
676
  * Update a specific task using TaskMaster CLI
671
677
  */
672
- router.put('/update-task/:projectName/:taskId', async (req, res) => {
678
+ router.put('/update-task/:projectId/:taskId', async (req, res) => {
673
679
  try {
674
- const { projectName, taskId } = req.params;
680
+ const { projectId, taskId } = req.params;
675
681
  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
+
683
+ const projectPath = await resolveProjectPathFromId(projectId);
684
+ if (!projectPath) {
682
685
  return res.status(404).json({
683
686
  error: 'Project not found',
684
- message: `Project "${projectName}" does not exist`
687
+ message: `Project "${projectId}" does not exist`
685
688
  });
686
689
  }
687
690
 
@@ -707,11 +710,11 @@ router.put('/update-task/:projectName/:taskId', async (req, res) => {
707
710
  if (code === 0) {
708
711
  // Broadcast task update via WebSocket
709
712
  if (req.app.locals.wss) {
710
- broadcastTaskMasterTasksUpdate(req.app.locals.wss, projectName);
713
+ broadcastTaskMasterTasksUpdate(req.app.locals.wss, projectId);
711
714
  }
712
715
 
713
716
  res.json({
714
- projectName,
717
+ projectId,
715
718
  projectPath,
716
719
  taskId,
717
720
  message: 'Task status updated successfully',
@@ -759,11 +762,11 @@ router.put('/update-task/:projectName/:taskId', async (req, res) => {
759
762
  if (code === 0) {
760
763
  // Broadcast task update via WebSocket
761
764
  if (req.app.locals.wss) {
762
- broadcastTaskMasterTasksUpdate(req.app.locals.wss, projectName);
765
+ broadcastTaskMasterTasksUpdate(req.app.locals.wss, projectId);
763
766
  }
764
767
 
765
768
  res.json({
766
- projectName,
769
+ projectId,
767
770
  projectPath,
768
771
  taskId,
769
772
  message: 'Task updated successfully',
@@ -793,22 +796,19 @@ router.put('/update-task/:projectName/:taskId', async (req, res) => {
793
796
  });
794
797
 
795
798
  /**
796
- * POST /api/taskmaster/parse-prd/:projectName
799
+ * POST /api/taskmaster/parse-prd/:projectId
797
800
  * Parse a PRD file to generate tasks
798
801
  */
799
- router.post('/parse-prd/:projectName', async (req, res) => {
802
+ router.post('/parse-prd/:projectId', async (req, res) => {
800
803
  try {
801
- const { projectName } = req.params;
804
+ const { projectId } = req.params;
802
805
  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) {
806
+
807
+ const projectPath = await resolveProjectPathFromId(projectId);
808
+ if (!projectPath) {
809
809
  return res.status(404).json({
810
810
  error: 'Project not found',
811
- message: `Project "${projectName}" does not exist`
811
+ message: `Project "${projectId}" does not exist`
812
812
  });
813
813
  }
814
814
 
@@ -859,13 +859,13 @@ router.post('/parse-prd/:projectName', async (req, res) => {
859
859
  // Broadcast task update via WebSocket
860
860
  if (req.app.locals.wss) {
861
861
  broadcastTaskMasterTasksUpdate(
862
- req.app.locals.wss,
863
- projectName
862
+ req.app.locals.wss,
863
+ projectId
864
864
  );
865
865
  }
866
866
 
867
867
  res.json({
868
- projectName,
868
+ projectId,
869
869
  projectPath,
870
870
  prdFile: fileName,
871
871
  message: 'PRD parsed and tasks generated successfully',
@@ -1340,12 +1340,12 @@ Description of the business problem, data sources, and expected insights.
1340
1340
  });
1341
1341
 
1342
1342
  /**
1343
- * POST /api/taskmaster/apply-template/:projectName
1343
+ * POST /api/taskmaster/apply-template/:projectId
1344
1344
  * Apply a PRD template to create a new PRD file
1345
1345
  */
1346
- router.post('/apply-template/:projectName', async (req, res) => {
1346
+ router.post('/apply-template/:projectId', async (req, res) => {
1347
1347
  try {
1348
- const { projectName } = req.params;
1348
+ const { projectId } = req.params;
1349
1349
  const { templateId, fileName = 'prd.txt', customizations = {} } = req.body;
1350
1350
 
1351
1351
  if (!templateId) {
@@ -1355,14 +1355,11 @@ router.post('/apply-template/:projectName', async (req, res) => {
1355
1355
  });
1356
1356
  }
1357
1357
 
1358
- // Get project path
1359
- let projectPath;
1360
- try {
1361
- projectPath = await extractProjectDirectory(projectName);
1362
- } catch (error) {
1358
+ const projectPath = await resolveProjectPathFromId(projectId);
1359
+ if (!projectPath) {
1363
1360
  return res.status(404).json({
1364
1361
  error: 'Project not found',
1365
- message: `Project "${projectName}" does not exist`
1362
+ message: `Project "${projectId}" does not exist`
1366
1363
  });
1367
1364
  }
1368
1365
 
@@ -1401,7 +1398,7 @@ router.post('/apply-template/:projectName', async (req, res) => {
1401
1398
  await fsPromises.writeFile(filePath, content, 'utf8');
1402
1399
 
1403
1400
  res.json({
1404
- projectName,
1401
+ projectId,
1405
1402
  projectPath,
1406
1403
  templateId,
1407
1404
  templateName: template.name,
@@ -1,5 +1,5 @@
1
1
  import express from 'express';
2
- import { userDb } from '../database/db.js';
2
+ import { userDb } from '../modules/database/index.js';
3
3
  import { authenticateToken } from '../middleware/auth.js';
4
4
  import { getSystemGitConfig } from '../utils/gitConfig.js';
5
5
  import { spawn } from 'child_process';
@@ -1,5 +1,6 @@
1
1
  import webPush from 'web-push';
2
- import { notificationPreferencesDb, pushSubscriptionsDb, sessionNamesDb } from '../database/db.js';
2
+
3
+ import { notificationPreferencesDb, pushSubscriptionsDb, sessionsDb } from '../modules/database/index.js';
3
4
 
4
5
  const KIND_TO_PREF_KEY = {
5
6
  action_required: 'actionRequired',
@@ -107,7 +108,7 @@ function resolveSessionName(event) {
107
108
  return null;
108
109
  }
109
110
 
110
- return normalizeSessionName(sessionNamesDb.getName(event.sessionId, event.provider));
111
+ return normalizeSessionName(sessionsDb.getSessionName(event.sessionId, event.provider));
111
112
  }
112
113
 
113
114
  function buildPushBody(event) {
@@ -1,7 +1,8 @@
1
1
  import webPush from 'web-push';
2
- import { db } from '../database/db.js';
2
+ import { getConnection } from '../modules/database/connection.js';
3
3
 
4
4
  let cachedKeys = null;
5
+ const db = getConnection();
5
6
 
6
7
  function ensureVapidKeys() {
7
8
  if (cachedKeys) return cachedKeys;
@@ -9,6 +9,7 @@ import type {
9
9
  UpsertProviderMcpServerInput,
10
10
  } from '@/shared/types.js';
11
11
 
12
+ //----------------- PROVIDER CONTRACT INTERFACES ------------
12
13
  /**
13
14
  * Main provider contract for CLI and SDK integrations.
14
15
  *
@@ -20,11 +21,16 @@ export interface IProvider {
20
21
  readonly mcp: IProviderMcp;
21
22
  readonly auth: IProviderAuth;
22
23
  readonly sessions: IProviderSessions;
24
+ readonly sessionSynchronizer: IProviderSessionSynchronizer;
23
25
  }
24
26
 
25
-
27
+ // ---------------------------
28
+ //----------------- PROVIDER AUTH INTERFACE ------------
26
29
  /**
27
30
  * Auth contract for one provider.
31
+ *
32
+ * Implementations should return a complete installation/authentication status
33
+ * without throwing for normal "not installed" or "not authenticated" states.
28
34
  */
29
35
  export interface IProviderAuth {
30
36
  /**
@@ -33,8 +39,13 @@ export interface IProviderAuth {
33
39
  getStatus(): Promise<ProviderAuthStatus>;
34
40
  }
35
41
 
42
+ // ---------------------------
43
+ //----------------- PROVIDER MCP INTERFACE ------------
36
44
  /**
37
45
  * MCP contract for one provider.
46
+ *
47
+ * Implementations must map provider-native MCP config formats to shared
48
+ * `ProviderMcpServer` records used by routes and frontend state.
38
49
  */
39
50
  export interface IProviderMcp {
40
51
  listServers(options?: { workspacePath?: string }): Promise<Record<McpScope, ProviderMcpServer[]>>;
@@ -45,10 +56,37 @@ export interface IProviderMcp {
45
56
  ): Promise<{ removed: boolean; provider: LLMProvider; name: string; scope: McpScope }>;
46
57
  }
47
58
 
59
+ // ---------------------------
60
+ //----------------- PROVIDER SESSION INTERFACE ------------
48
61
  /**
49
62
  * Session/history contract for one provider.
63
+ *
64
+ * Implementations normalize provider-specific events and message history into
65
+ * shared transport shapes consumed by API routes and realtime streams.
50
66
  */
51
67
  export interface IProviderSessions {
52
68
  normalizeMessage(raw: unknown, sessionId: string | null): NormalizedMessage[];
53
69
  fetchHistory(sessionId: string, options?: FetchHistoryOptions): Promise<FetchHistoryResult>;
54
70
  }
71
+
72
+ // ---------------------------
73
+ //----------------- PROVIDER SESSION SYNCHRONIZER INTERFACE ------------
74
+ /**
75
+ * Session indexing contract for one provider.
76
+ *
77
+ * Implementations scan provider-specific session artifacts on disk and upsert
78
+ * normalized session metadata into the database. The service layer uses this
79
+ * interface for both full rescans and single-file incremental sync triggered
80
+ * by filesystem watcher events.
81
+ */
82
+ export interface IProviderSessionSynchronizer {
83
+ /**
84
+ * Scans provider session artifacts and upserts discovered sessions into DB.
85
+ */
86
+ synchronize(since?: Date): Promise<number>;
87
+
88
+ /**
89
+ * Parses and upserts one provider artifact file without running a full scan.
90
+ */
91
+ synchronizeFile(filePath: string): Promise<string | null>;
92
+ }