@cloudcli-ai/cloudcli 1.29.5 → 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.
- package/README.de.md +1 -1
- package/README.ja.md +1 -1
- package/README.ko.md +1 -1
- package/README.md +1 -1
- package/README.ru.md +1 -1
- package/README.tr.md +252 -0
- package/README.zh-CN.md +1 -1
- package/dist/assets/index-DF8TTVHl.css +32 -0
- package/dist/assets/index-DbZAcc9z.js +1262 -0
- package/dist/index.html +2 -2
- package/dist-server/server/claude-sdk.js +13 -8
- package/dist-server/server/claude-sdk.js.map +1 -1
- package/dist-server/server/cursor-cli.js +7 -7
- package/dist-server/server/cursor-cli.js.map +1 -1
- package/dist-server/server/gemini-cli.js +5 -5
- package/dist-server/server/gemini-cli.js.map +1 -1
- package/dist-server/server/gemini-response-handler.js +2 -2
- package/dist-server/server/gemini-response-handler.js.map +1 -1
- package/dist-server/server/index.js +139 -977
- package/dist-server/server/index.js.map +1 -1
- package/dist-server/server/middleware/auth.js +1 -1
- package/dist-server/server/middleware/auth.js.map +1 -1
- package/dist-server/server/modules/database/connection.js +125 -0
- package/dist-server/server/modules/database/connection.js.map +1 -0
- package/dist-server/server/modules/database/index.js +13 -0
- package/dist-server/server/modules/database/index.js.map +1 -0
- package/dist-server/server/modules/database/init-db.js +18 -0
- package/dist-server/server/modules/database/init-db.js.map +1 -0
- package/dist-server/server/modules/database/migrations.js +370 -0
- package/dist-server/server/modules/database/migrations.js.map +1 -0
- package/dist-server/server/modules/database/repositories/api-keys.js +72 -0
- package/dist-server/server/modules/database/repositories/api-keys.js.map +1 -0
- package/dist-server/server/modules/database/repositories/app-config.js +47 -0
- package/dist-server/server/modules/database/repositories/app-config.js.map +1 -0
- package/dist-server/server/modules/database/repositories/credentials.js +68 -0
- package/dist-server/server/modules/database/repositories/credentials.js.map +1 -0
- package/dist-server/server/modules/database/repositories/github-tokens.js +54 -0
- package/dist-server/server/modules/database/repositories/github-tokens.js.map +1 -0
- package/dist-server/server/modules/database/repositories/notification-preferences.js +72 -0
- package/dist-server/server/modules/database/repositories/notification-preferences.js.map +1 -0
- package/dist-server/server/modules/database/repositories/projects.db.integration.test.js +64 -0
- package/dist-server/server/modules/database/repositories/projects.db.integration.test.js.map +1 -0
- package/dist-server/server/modules/database/repositories/projects.db.js +160 -0
- package/dist-server/server/modules/database/repositories/projects.db.js.map +1 -0
- package/dist-server/server/modules/database/repositories/push-subscriptions.js +49 -0
- package/dist-server/server/modules/database/repositories/push-subscriptions.js.map +1 -0
- package/dist-server/server/modules/database/repositories/scan-state.db.js +31 -0
- package/dist-server/server/modules/database/repositories/scan-state.db.js.map +1 -0
- package/dist-server/server/modules/database/repositories/sessions.db.js +109 -0
- package/dist-server/server/modules/database/repositories/sessions.db.js.map +1 -0
- package/dist-server/server/modules/database/repositories/users.js +88 -0
- package/dist-server/server/modules/database/repositories/users.js.map +1 -0
- package/dist-server/server/modules/database/repositories/vapid-keys.js +38 -0
- package/dist-server/server/modules/database/repositories/vapid-keys.js.map +1 -0
- package/dist-server/server/modules/database/schema.js +143 -0
- package/dist-server/server/modules/database/schema.js.map +1 -0
- package/dist-server/server/modules/projects/index.js +4 -0
- package/dist-server/server/modules/projects/index.js.map +1 -0
- package/dist-server/server/modules/projects/projects.routes.js +188 -0
- package/dist-server/server/modules/projects/projects.routes.js.map +1 -0
- package/dist-server/server/modules/projects/services/project-clone.service.js +219 -0
- package/dist-server/server/modules/projects/services/project-clone.service.js.map +1 -0
- package/dist-server/server/modules/projects/services/project-delete.service.js +65 -0
- package/dist-server/server/modules/projects/services/project-delete.service.js.map +1 -0
- package/dist-server/server/modules/projects/services/project-management.service.js +93 -0
- package/dist-server/server/modules/projects/services/project-management.service.js.map +1 -0
- package/dist-server/server/modules/projects/services/project-star.service.js +60 -0
- package/dist-server/server/modules/projects/services/project-star.service.js.map +1 -0
- package/dist-server/server/modules/projects/services/projects-has-taskmaster.service.js +167 -0
- package/dist-server/server/modules/projects/services/projects-has-taskmaster.service.js.map +1 -0
- package/dist-server/server/modules/projects/services/projects-with-sessions-fetch.service.js +169 -0
- package/dist-server/server/modules/projects/services/projects-with-sessions-fetch.service.js.map +1 -0
- package/dist-server/server/modules/projects/tests/project-clone.service.test.js +126 -0
- package/dist-server/server/modules/projects/tests/project-clone.service.test.js.map +1 -0
- package/dist-server/server/modules/projects/tests/project-management.service.test.js +85 -0
- package/dist-server/server/modules/projects/tests/project-management.service.test.js.map +1 -0
- package/dist-server/server/modules/projects/tests/project-star.service.test.js +95 -0
- package/dist-server/server/modules/projects/tests/project-star.service.test.js.map +1 -0
- package/dist-server/server/modules/projects/tests/projects-has-taskmaster.service.test.js +87 -0
- package/dist-server/server/modules/projects/tests/projects-has-taskmaster.service.test.js.map +1 -0
- package/dist-server/server/modules/providers/index.js +4 -0
- package/dist-server/server/modules/providers/index.js.map +1 -0
- package/dist-server/server/modules/providers/list/claude/claude-auth.provider.js +103 -0
- package/dist-server/server/modules/providers/list/claude/claude-auth.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/claude/claude-mcp.provider.js +103 -0
- package/dist-server/server/modules/providers/list/claude/claude-mcp.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/claude/claude-session-synchronizer.provider.js +63 -0
- package/dist-server/server/modules/providers/list/claude/claude-session-synchronizer.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/claude/claude-sessions.provider.js +403 -0
- package/dist-server/server/modules/providers/list/claude/claude-sessions.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/claude/claude.provider.js +15 -0
- package/dist-server/server/modules/providers/list/claude/claude.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/codex/codex-auth.provider.js +84 -0
- package/dist-server/server/modules/providers/list/codex/codex-auth.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/codex/codex-mcp.provider.js +107 -0
- package/dist-server/server/modules/providers/list/codex/codex-mcp.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/codex/codex-session-synchronizer.provider.js +71 -0
- package/dist-server/server/modules/providers/list/codex/codex-session-synchronizer.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/codex/codex-sessions.provider.js +494 -0
- package/dist-server/server/modules/providers/list/codex/codex-sessions.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/codex/codex.provider.js +15 -0
- package/dist-server/server/modules/providers/list/codex/codex.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/cursor/cursor-auth.provider.js +118 -0
- package/dist-server/server/modules/providers/list/cursor/cursor-auth.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/cursor/cursor-mcp.provider.js +80 -0
- package/dist-server/server/modules/providers/list/cursor/cursor-mcp.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/cursor/cursor-session-synchronizer.provider.js +127 -0
- package/dist-server/server/modules/providers/list/cursor/cursor-session-synchronizer.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/cursor/cursor-sessions.provider.js +369 -0
- package/dist-server/server/modules/providers/list/cursor/cursor-sessions.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/cursor/cursor.provider.js +15 -0
- package/dist-server/server/modules/providers/list/cursor/cursor.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/gemini/gemini-auth.provider.js +131 -0
- package/dist-server/server/modules/providers/list/gemini/gemini-auth.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/gemini/gemini-mcp.provider.js +82 -0
- package/dist-server/server/modules/providers/list/gemini/gemini-mcp.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/gemini/gemini-session-synchronizer.provider.js +296 -0
- package/dist-server/server/modules/providers/list/gemini/gemini-session-synchronizer.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/gemini/gemini-sessions.provider.js +474 -0
- package/dist-server/server/modules/providers/list/gemini/gemini-sessions.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/gemini/gemini.provider.js +15 -0
- package/dist-server/server/modules/providers/list/gemini/gemini.provider.js.map +1 -0
- package/dist-server/server/modules/providers/provider.registry.js +31 -0
- package/dist-server/server/modules/providers/provider.registry.js.map +1 -0
- package/dist-server/server/modules/providers/provider.routes.js +331 -0
- package/dist-server/server/modules/providers/provider.routes.js.map +1 -0
- package/dist-server/server/modules/providers/services/mcp.service.js +69 -0
- package/dist-server/server/modules/providers/services/mcp.service.js.map +1 -0
- package/dist-server/server/modules/providers/services/provider-auth.service.js +25 -0
- package/dist-server/server/modules/providers/services/provider-auth.service.js.map +1 -0
- package/dist-server/server/modules/providers/services/session-conversations-search.service.js +868 -0
- package/dist-server/server/modules/providers/services/session-conversations-search.service.js.map +1 -0
- package/dist-server/server/modules/providers/services/session-synchronizer.service.js +56 -0
- package/dist-server/server/modules/providers/services/session-synchronizer.service.js.map +1 -0
- package/dist-server/server/modules/providers/services/sessions-watcher.service.js +234 -0
- package/dist-server/server/modules/providers/services/sessions-watcher.service.js.map +1 -0
- package/dist-server/server/modules/providers/services/sessions.service.js +104 -0
- package/dist-server/server/modules/providers/services/sessions.service.js.map +1 -0
- package/dist-server/server/modules/providers/shared/base/abstract.provider.js +14 -0
- package/dist-server/server/modules/providers/shared/base/abstract.provider.js.map +1 -0
- package/dist-server/server/modules/providers/shared/mcp/mcp.provider.js +102 -0
- package/dist-server/server/modules/providers/shared/mcp/mcp.provider.js.map +1 -0
- package/dist-server/server/modules/providers/tests/mcp.test.js +250 -0
- package/dist-server/server/modules/providers/tests/mcp.test.js.map +1 -0
- package/dist-server/server/modules/websocket/index.js +3 -0
- package/dist-server/server/modules/websocket/index.js.map +1 -0
- package/dist-server/server/modules/websocket/services/chat-websocket.service.js +188 -0
- package/dist-server/server/modules/websocket/services/chat-websocket.service.js.map +1 -0
- package/dist-server/server/modules/websocket/services/plugin-websocket-proxy.service.js +52 -0
- package/dist-server/server/modules/websocket/services/plugin-websocket-proxy.service.js.map +1 -0
- package/dist-server/server/modules/websocket/services/shell-websocket.service.js +334 -0
- package/dist-server/server/modules/websocket/services/shell-websocket.service.js.map +1 -0
- package/dist-server/server/modules/websocket/services/websocket-auth.service.js +32 -0
- package/dist-server/server/modules/websocket/services/websocket-auth.service.js.map +1 -0
- package/dist-server/server/modules/websocket/services/websocket-server.service.js +36 -0
- package/dist-server/server/modules/websocket/services/websocket-server.service.js.map +1 -0
- package/dist-server/server/modules/websocket/services/websocket-state.service.js +14 -0
- package/dist-server/server/modules/websocket/services/websocket-state.service.js.map +1 -0
- package/dist-server/server/modules/websocket/services/websocket-writer.service.js +32 -0
- package/dist-server/server/modules/websocket/services/websocket-writer.service.js.map +1 -0
- package/dist-server/server/openai-codex.js +5 -5
- package/dist-server/server/openai-codex.js.map +1 -1
- package/dist-server/server/routes/agent.js +10 -17
- package/dist-server/server/routes/agent.js.map +1 -1
- package/dist-server/server/routes/auth.js +3 -1
- package/dist-server/server/routes/auth.js.map +1 -1
- package/dist-server/server/routes/commands.js +1 -45
- package/dist-server/server/routes/commands.js.map +1 -1
- package/dist-server/server/routes/cursor.js +9 -489
- package/dist-server/server/routes/cursor.js.map +1 -1
- package/dist-server/server/routes/gemini.js +2 -2
- package/dist-server/server/routes/gemini.js.map +1 -1
- package/dist-server/server/routes/git.js +33 -29
- package/dist-server/server/routes/git.js.map +1 -1
- package/dist-server/server/routes/mcp-utils.js +1 -18
- package/dist-server/server/routes/mcp-utils.js.map +1 -1
- package/dist-server/server/routes/settings.js +11 -1
- package/dist-server/server/routes/settings.js.map +1 -1
- package/dist-server/server/routes/taskmaster.js +97 -569
- package/dist-server/server/routes/taskmaster.js.map +1 -1
- package/dist-server/server/routes/user.js +1 -1
- package/dist-server/server/routes/user.js.map +1 -1
- package/dist-server/server/services/notification-orchestrator.js +2 -2
- package/dist-server/server/services/notification-orchestrator.js.map +1 -1
- package/dist-server/server/services/vapid-keys.js +2 -1
- package/dist-server/server/services/vapid-keys.js.map +1 -1
- package/dist-server/server/shared/interfaces.js +2 -0
- package/dist-server/server/shared/interfaces.js.map +1 -0
- package/dist-server/server/shared/types.js +2 -0
- package/dist-server/server/shared/types.js.map +1 -0
- package/dist-server/server/shared/utils.js +551 -0
- package/dist-server/server/shared/utils.js.map +1 -0
- package/dist-server/server/utils/mcp-detector.js +0 -49
- package/dist-server/server/utils/mcp-detector.js.map +1 -1
- package/dist-server/server/utils/taskmaster-websocket.js +18 -12
- package/dist-server/server/utils/taskmaster-websocket.js.map +1 -1
- package/dist-server/shared/modelConstants.js +3 -1
- package/dist-server/shared/modelConstants.js.map +1 -1
- package/package.json +7 -2
- package/server/claude-sdk.js +14 -8
- package/server/cursor-cli.js +7 -7
- package/server/gemini-cli.js +5 -5
- package/server/gemini-response-handler.js +2 -2
- package/server/index.js +173 -1035
- package/server/middleware/auth.js +1 -1
- package/server/modules/database/connection.ts +143 -0
- package/server/modules/database/index.ts +12 -0
- package/server/modules/database/init-db.ts +17 -0
- package/server/modules/database/migrations.ts +442 -0
- package/server/modules/database/repositories/api-keys.ts +119 -0
- package/server/modules/database/repositories/app-config.ts +53 -0
- package/server/modules/database/repositories/credentials.ts +106 -0
- package/server/modules/database/repositories/github-tokens.ts +100 -0
- package/server/modules/database/repositories/notification-preferences.ts +103 -0
- package/server/modules/database/repositories/projects.db.integration.test.ts +72 -0
- package/server/modules/database/repositories/projects.db.ts +183 -0
- package/server/modules/database/repositories/push-subscriptions.ts +80 -0
- package/server/modules/database/repositories/scan-state.db.ts +42 -0
- package/server/modules/database/repositories/sessions.db.ts +174 -0
- package/server/modules/database/repositories/users.ts +140 -0
- package/server/modules/database/repositories/vapid-keys.ts +57 -0
- package/server/modules/database/schema.ts +152 -0
- package/server/modules/projects/index.ts +6 -0
- package/server/modules/projects/projects.routes.ts +247 -0
- package/server/modules/projects/services/project-clone.service.ts +321 -0
- package/server/modules/projects/services/project-delete.service.ts +75 -0
- package/server/modules/projects/services/project-management.service.ts +150 -0
- package/server/modules/projects/services/project-star.service.ts +78 -0
- package/server/modules/projects/services/projects-has-taskmaster.service.ts +248 -0
- package/server/modules/projects/services/projects-with-sessions-fetch.service.ts +285 -0
- package/server/modules/projects/tests/project-clone.service.test.ts +183 -0
- package/server/modules/projects/tests/project-management.service.test.ts +117 -0
- package/server/modules/projects/tests/project-star.service.test.ts +123 -0
- package/server/modules/projects/tests/projects-has-taskmaster.service.test.ts +105 -0
- package/server/modules/providers/index.ts +4 -0
- package/server/modules/providers/list/claude/claude-auth.provider.ts +123 -0
- package/server/modules/providers/list/claude/claude-mcp.provider.ts +135 -0
- package/server/modules/providers/list/claude/claude-session-synchronizer.provider.ts +110 -0
- package/server/modules/providers/list/claude/claude-sessions.provider.ts +475 -0
- package/server/modules/providers/list/claude/claude.provider.ts +17 -0
- package/server/modules/providers/list/codex/codex-auth.provider.ts +100 -0
- package/server/modules/providers/list/codex/codex-mcp.provider.ts +135 -0
- package/server/modules/providers/list/codex/codex-session-synchronizer.provider.ts +119 -0
- package/server/modules/providers/list/codex/codex-sessions.provider.ts +564 -0
- package/server/modules/providers/list/codex/codex.provider.ts +17 -0
- package/server/modules/providers/list/cursor/cursor-auth.provider.ts +143 -0
- package/server/modules/providers/list/cursor/cursor-mcp.provider.ts +108 -0
- package/server/modules/providers/list/cursor/cursor-session-synchronizer.provider.ts +176 -0
- package/server/modules/providers/list/cursor/cursor-sessions.provider.ts +421 -0
- package/server/modules/providers/list/cursor/cursor.provider.ts +17 -0
- package/server/modules/providers/list/gemini/gemini-auth.provider.ts +151 -0
- package/server/modules/providers/list/gemini/gemini-mcp.provider.ts +110 -0
- package/server/modules/providers/list/gemini/gemini-session-synchronizer.provider.ts +401 -0
- package/server/modules/providers/list/gemini/gemini-sessions.provider.ts +541 -0
- package/server/modules/providers/list/gemini/gemini.provider.ts +17 -0
- package/server/modules/providers/provider.registry.ts +36 -0
- package/server/modules/providers/provider.routes.ts +425 -0
- package/server/modules/providers/services/mcp.service.ts +94 -0
- package/server/modules/providers/services/provider-auth.service.ts +26 -0
- package/server/modules/providers/services/session-conversations-search.service.ts +1167 -0
- package/server/modules/providers/services/session-synchronizer.service.ts +74 -0
- package/server/modules/providers/services/sessions-watcher.service.ts +283 -0
- package/server/modules/providers/services/sessions.service.ts +130 -0
- package/server/modules/providers/shared/base/abstract.provider.ts +27 -0
- package/server/modules/providers/shared/mcp/mcp.provider.ts +151 -0
- package/server/modules/providers/tests/mcp.test.ts +293 -0
- package/server/modules/websocket/README.md +267 -0
- package/server/modules/websocket/index.ts +2 -0
- package/server/modules/websocket/services/chat-websocket.service.ts +271 -0
- package/server/modules/websocket/services/plugin-websocket-proxy.service.ts +65 -0
- package/server/modules/websocket/services/shell-websocket.service.ts +453 -0
- package/server/modules/websocket/services/websocket-auth.service.ts +54 -0
- package/server/modules/websocket/services/websocket-server.service.ts +58 -0
- package/server/modules/websocket/services/websocket-state.service.ts +16 -0
- package/server/modules/websocket/services/websocket-writer.service.ts +38 -0
- package/server/openai-codex.js +5 -5
- package/server/routes/agent.js +11 -16
- package/server/routes/auth.js +4 -2
- package/server/routes/commands.js +1 -50
- package/server/routes/cursor.js +15 -527
- package/server/routes/gemini.js +3 -2
- package/server/routes/git.js +33 -28
- package/server/routes/mcp-utils.js +2 -19
- package/server/routes/settings.js +11 -1
- package/server/routes/taskmaster.js +107 -602
- package/server/routes/user.js +1 -1
- package/server/services/notification-orchestrator.js +3 -2
- package/server/services/vapid-keys.js +2 -1
- package/server/shared/interfaces.ts +92 -0
- package/server/shared/types.ts +327 -0
- package/server/shared/utils.ts +669 -0
- package/server/tsconfig.json +6 -3
- package/server/utils/mcp-detector.js +0 -51
- package/server/utils/taskmaster-websocket.js +19 -13
- package/shared/modelConstants.js +3 -1
- package/dist/assets/index-BBAE1OJ_.css +0 -32
- package/dist/assets/index-Ci1GOyV7.js +0 -1262
- package/dist-server/server/database/db.js +0 -535
- package/dist-server/server/database/db.js.map +0 -1
- package/dist-server/server/database/schema.js +0 -97
- package/dist-server/server/database/schema.js.map +0 -1
- package/dist-server/server/projects.js +0 -2325
- package/dist-server/server/projects.js.map +0 -1
- package/dist-server/server/providers/claude/adapter.js +0 -266
- package/dist-server/server/providers/claude/adapter.js.map +0 -1
- package/dist-server/server/providers/claude/status.js +0 -121
- package/dist-server/server/providers/claude/status.js.map +0 -1
- package/dist-server/server/providers/codex/adapter.js +0 -232
- package/dist-server/server/providers/codex/adapter.js.map +0 -1
- package/dist-server/server/providers/codex/status.js +0 -70
- package/dist-server/server/providers/codex/status.js.map +0 -1
- package/dist-server/server/providers/cursor/adapter.js +0 -342
- package/dist-server/server/providers/cursor/adapter.js.map +0 -1
- package/dist-server/server/providers/cursor/status.js +0 -118
- package/dist-server/server/providers/cursor/status.js.map +0 -1
- package/dist-server/server/providers/gemini/adapter.js +0 -174
- package/dist-server/server/providers/gemini/adapter.js.map +0 -1
- package/dist-server/server/providers/gemini/status.js +0 -104
- package/dist-server/server/providers/gemini/status.js.map +0 -1
- package/dist-server/server/providers/registry.js +0 -58
- package/dist-server/server/providers/registry.js.map +0 -1
- package/dist-server/server/providers/types.js +0 -117
- package/dist-server/server/providers/types.js.map +0 -1
- package/dist-server/server/providers/utils.js +0 -28
- package/dist-server/server/providers/utils.js.map +0 -1
- package/dist-server/server/routes/cli-auth.js +0 -25
- package/dist-server/server/routes/cli-auth.js.map +0 -1
- package/dist-server/server/routes/codex.js +0 -294
- package/dist-server/server/routes/codex.js.map +0 -1
- package/dist-server/server/routes/mcp.js +0 -480
- package/dist-server/server/routes/mcp.js.map +0 -1
- package/dist-server/server/routes/messages.js +0 -56
- package/dist-server/server/routes/messages.js.map +0 -1
- package/dist-server/server/routes/projects.js +0 -505
- package/dist-server/server/routes/projects.js.map +0 -1
- package/server/database/db.js +0 -593
- package/server/database/schema.js +0 -102
- package/server/projects.js +0 -2555
- package/server/providers/claude/adapter.js +0 -278
- package/server/providers/claude/status.js +0 -136
- package/server/providers/codex/adapter.js +0 -248
- package/server/providers/codex/status.js +0 -78
- package/server/providers/cursor/adapter.js +0 -348
- package/server/providers/cursor/status.js +0 -128
- package/server/providers/gemini/adapter.js +0 -186
- package/server/providers/gemini/status.js +0 -111
- package/server/providers/registry.js +0 -67
- package/server/providers/types.js +0 -132
- package/server/providers/utils.js +0 -29
- package/server/routes/cli-auth.js +0 -27
- package/server/routes/codex.js +0 -329
- package/server/routes/mcp.js +0 -552
- package/server/routes/messages.js +0 -61
- package/server/routes/projects.js +0 -548
|
@@ -12,14 +12,23 @@ import fs from 'fs';
|
|
|
12
12
|
import path from 'path';
|
|
13
13
|
import { promises as fsPromises } from 'fs';
|
|
14
14
|
import { spawn } from 'child_process';
|
|
15
|
-
import {
|
|
16
|
-
import { dirname } from 'path';
|
|
17
|
-
import os from 'os';
|
|
18
|
-
import { extractProjectDirectory } from '../projects.js';
|
|
15
|
+
import { projectsDb } from '../modules/database/index.js';
|
|
19
16
|
import { detectTaskMasterMCPServer } from '../utils/mcp-detector.js';
|
|
20
17
|
import { broadcastTaskMasterProjectUpdate, broadcastTaskMasterTasksUpdate } from '../utils/taskmaster-websocket.js';
|
|
21
|
-
|
|
22
|
-
|
|
18
|
+
/**
|
|
19
|
+
* Resolve the absolute project directory from a DB-assigned `projectId`.
|
|
20
|
+
*
|
|
21
|
+
* TaskMaster routes used to accept a Claude-encoded folder name (`projectName`)
|
|
22
|
+
* and derive the path from JSONL history. After the projectId migration the
|
|
23
|
+
* only identifier we accept is the primary key of the `projects` table, so
|
|
24
|
+
* every handler calls this helper and 404s when the id is unknown.
|
|
25
|
+
*/
|
|
26
|
+
async function resolveProjectPathFromId(projectId) {
|
|
27
|
+
if (!projectId) {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
return projectsDb.getProjectPathById(projectId);
|
|
31
|
+
}
|
|
23
32
|
const router = express.Router();
|
|
24
33
|
/**
|
|
25
34
|
* Check if TaskMaster CLI is installed globally
|
|
@@ -87,131 +96,6 @@ async function checkTaskMasterInstallation() {
|
|
|
87
96
|
});
|
|
88
97
|
});
|
|
89
98
|
}
|
|
90
|
-
/**
|
|
91
|
-
* Detect .taskmaster folder presence in a given project directory
|
|
92
|
-
* @param {string} projectPath - Absolute path to project directory
|
|
93
|
-
* @returns {Promise<Object>} Detection result with status and metadata
|
|
94
|
-
*/
|
|
95
|
-
async function detectTaskMasterFolder(projectPath) {
|
|
96
|
-
try {
|
|
97
|
-
const taskMasterPath = path.join(projectPath, '.taskmaster');
|
|
98
|
-
// Check if .taskmaster directory exists
|
|
99
|
-
try {
|
|
100
|
-
const stats = await fsPromises.stat(taskMasterPath);
|
|
101
|
-
if (!stats.isDirectory()) {
|
|
102
|
-
return {
|
|
103
|
-
hasTaskmaster: false,
|
|
104
|
-
reason: '.taskmaster exists but is not a directory'
|
|
105
|
-
};
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
catch (error) {
|
|
109
|
-
if (error.code === 'ENOENT') {
|
|
110
|
-
return {
|
|
111
|
-
hasTaskmaster: false,
|
|
112
|
-
reason: '.taskmaster directory not found'
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
|
-
throw error;
|
|
116
|
-
}
|
|
117
|
-
// Check for key TaskMaster files
|
|
118
|
-
const keyFiles = [
|
|
119
|
-
'tasks/tasks.json',
|
|
120
|
-
'config.json'
|
|
121
|
-
];
|
|
122
|
-
const fileStatus = {};
|
|
123
|
-
let hasEssentialFiles = true;
|
|
124
|
-
for (const file of keyFiles) {
|
|
125
|
-
const filePath = path.join(taskMasterPath, file);
|
|
126
|
-
try {
|
|
127
|
-
await fsPromises.access(filePath, fs.constants.R_OK);
|
|
128
|
-
fileStatus[file] = true;
|
|
129
|
-
}
|
|
130
|
-
catch (error) {
|
|
131
|
-
fileStatus[file] = false;
|
|
132
|
-
if (file === 'tasks/tasks.json') {
|
|
133
|
-
hasEssentialFiles = false;
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
// Parse tasks.json if it exists for metadata
|
|
138
|
-
let taskMetadata = null;
|
|
139
|
-
if (fileStatus['tasks/tasks.json']) {
|
|
140
|
-
try {
|
|
141
|
-
const tasksPath = path.join(taskMasterPath, 'tasks/tasks.json');
|
|
142
|
-
const tasksContent = await fsPromises.readFile(tasksPath, 'utf8');
|
|
143
|
-
const tasksData = JSON.parse(tasksContent);
|
|
144
|
-
// Handle both tagged and legacy formats
|
|
145
|
-
let tasks = [];
|
|
146
|
-
if (tasksData.tasks) {
|
|
147
|
-
// Legacy format
|
|
148
|
-
tasks = tasksData.tasks;
|
|
149
|
-
}
|
|
150
|
-
else {
|
|
151
|
-
// Tagged format - get tasks from all tags
|
|
152
|
-
Object.values(tasksData).forEach(tagData => {
|
|
153
|
-
if (tagData.tasks) {
|
|
154
|
-
tasks = tasks.concat(tagData.tasks);
|
|
155
|
-
}
|
|
156
|
-
});
|
|
157
|
-
}
|
|
158
|
-
// Calculate task statistics
|
|
159
|
-
const stats = tasks.reduce((acc, task) => {
|
|
160
|
-
acc.total++;
|
|
161
|
-
acc[task.status] = (acc[task.status] || 0) + 1;
|
|
162
|
-
// Count subtasks
|
|
163
|
-
if (task.subtasks) {
|
|
164
|
-
task.subtasks.forEach(subtask => {
|
|
165
|
-
acc.subtotalTasks++;
|
|
166
|
-
acc.subtasks = acc.subtasks || {};
|
|
167
|
-
acc.subtasks[subtask.status] = (acc.subtasks[subtask.status] || 0) + 1;
|
|
168
|
-
});
|
|
169
|
-
}
|
|
170
|
-
return acc;
|
|
171
|
-
}, {
|
|
172
|
-
total: 0,
|
|
173
|
-
subtotalTasks: 0,
|
|
174
|
-
pending: 0,
|
|
175
|
-
'in-progress': 0,
|
|
176
|
-
done: 0,
|
|
177
|
-
review: 0,
|
|
178
|
-
deferred: 0,
|
|
179
|
-
cancelled: 0,
|
|
180
|
-
subtasks: {}
|
|
181
|
-
});
|
|
182
|
-
taskMetadata = {
|
|
183
|
-
taskCount: stats.total,
|
|
184
|
-
subtaskCount: stats.subtotalTasks,
|
|
185
|
-
completed: stats.done || 0,
|
|
186
|
-
pending: stats.pending || 0,
|
|
187
|
-
inProgress: stats['in-progress'] || 0,
|
|
188
|
-
review: stats.review || 0,
|
|
189
|
-
completionPercentage: stats.total > 0 ? Math.round((stats.done / stats.total) * 100) : 0,
|
|
190
|
-
lastModified: (await fsPromises.stat(tasksPath)).mtime.toISOString()
|
|
191
|
-
};
|
|
192
|
-
}
|
|
193
|
-
catch (parseError) {
|
|
194
|
-
console.warn('Failed to parse tasks.json:', parseError.message);
|
|
195
|
-
taskMetadata = { error: 'Failed to parse tasks.json' };
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
return {
|
|
199
|
-
hasTaskmaster: true,
|
|
200
|
-
hasEssentialFiles,
|
|
201
|
-
files: fileStatus,
|
|
202
|
-
metadata: taskMetadata,
|
|
203
|
-
path: taskMasterPath
|
|
204
|
-
};
|
|
205
|
-
}
|
|
206
|
-
catch (error) {
|
|
207
|
-
console.error('Error detecting TaskMaster folder:', error);
|
|
208
|
-
return {
|
|
209
|
-
hasTaskmaster: false,
|
|
210
|
-
reason: `Error checking directory: ${error.message}`
|
|
211
|
-
};
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
// MCP detection is now handled by the centralized utility
|
|
215
99
|
// API Routes
|
|
216
100
|
/**
|
|
217
101
|
* GET /api/taskmaster/installation-status
|
|
@@ -247,294 +131,21 @@ router.get('/installation-status', async (req, res) => {
|
|
|
247
131
|
}
|
|
248
132
|
});
|
|
249
133
|
/**
|
|
250
|
-
* GET /api/taskmaster/
|
|
251
|
-
* Detect TaskMaster configuration for a specific project
|
|
252
|
-
*/
|
|
253
|
-
router.get('/detect/:projectName', async (req, res) => {
|
|
254
|
-
try {
|
|
255
|
-
const { projectName } = req.params;
|
|
256
|
-
// Use the existing extractProjectDirectory function to get actual project path
|
|
257
|
-
let projectPath;
|
|
258
|
-
try {
|
|
259
|
-
projectPath = await extractProjectDirectory(projectName);
|
|
260
|
-
}
|
|
261
|
-
catch (error) {
|
|
262
|
-
console.error('Error extracting project directory:', error);
|
|
263
|
-
return res.status(404).json({
|
|
264
|
-
error: 'Project path not found',
|
|
265
|
-
projectName,
|
|
266
|
-
message: error.message
|
|
267
|
-
});
|
|
268
|
-
}
|
|
269
|
-
// Verify the project path exists
|
|
270
|
-
try {
|
|
271
|
-
await fsPromises.access(projectPath, fs.constants.R_OK);
|
|
272
|
-
}
|
|
273
|
-
catch (error) {
|
|
274
|
-
return res.status(404).json({
|
|
275
|
-
error: 'Project path not accessible',
|
|
276
|
-
projectPath,
|
|
277
|
-
projectName,
|
|
278
|
-
message: error.message
|
|
279
|
-
});
|
|
280
|
-
}
|
|
281
|
-
// Run detection in parallel
|
|
282
|
-
const [taskMasterResult, mcpResult] = await Promise.all([
|
|
283
|
-
detectTaskMasterFolder(projectPath),
|
|
284
|
-
detectTaskMasterMCPServer()
|
|
285
|
-
]);
|
|
286
|
-
// Determine overall status
|
|
287
|
-
let status = 'not-configured';
|
|
288
|
-
if (taskMasterResult.hasTaskmaster && taskMasterResult.hasEssentialFiles) {
|
|
289
|
-
if (mcpResult.hasMCPServer && mcpResult.isConfigured) {
|
|
290
|
-
status = 'fully-configured';
|
|
291
|
-
}
|
|
292
|
-
else {
|
|
293
|
-
status = 'taskmaster-only';
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
else if (mcpResult.hasMCPServer && mcpResult.isConfigured) {
|
|
297
|
-
status = 'mcp-only';
|
|
298
|
-
}
|
|
299
|
-
const responseData = {
|
|
300
|
-
projectName,
|
|
301
|
-
projectPath,
|
|
302
|
-
status,
|
|
303
|
-
taskmaster: taskMasterResult,
|
|
304
|
-
mcp: mcpResult,
|
|
305
|
-
timestamp: new Date().toISOString()
|
|
306
|
-
};
|
|
307
|
-
res.json(responseData);
|
|
308
|
-
}
|
|
309
|
-
catch (error) {
|
|
310
|
-
console.error('TaskMaster detection error:', error);
|
|
311
|
-
res.status(500).json({
|
|
312
|
-
error: 'Failed to detect TaskMaster configuration',
|
|
313
|
-
message: error.message
|
|
314
|
-
});
|
|
315
|
-
}
|
|
316
|
-
});
|
|
317
|
-
/**
|
|
318
|
-
* GET /api/taskmaster/detect-all
|
|
319
|
-
* Detect TaskMaster configuration for all known projects
|
|
320
|
-
* This endpoint works with the existing projects system
|
|
321
|
-
*/
|
|
322
|
-
router.get('/detect-all', async (req, res) => {
|
|
323
|
-
try {
|
|
324
|
-
// Import getProjects from the projects module
|
|
325
|
-
const { getProjects } = await import('../projects.js');
|
|
326
|
-
const projects = await getProjects();
|
|
327
|
-
// Run detection for all projects in parallel
|
|
328
|
-
const detectionPromises = projects.map(async (project) => {
|
|
329
|
-
try {
|
|
330
|
-
// Use the project's fullPath if available, otherwise extract the directory
|
|
331
|
-
let projectPath;
|
|
332
|
-
if (project.fullPath) {
|
|
333
|
-
projectPath = project.fullPath;
|
|
334
|
-
}
|
|
335
|
-
else {
|
|
336
|
-
try {
|
|
337
|
-
projectPath = await extractProjectDirectory(project.name);
|
|
338
|
-
}
|
|
339
|
-
catch (error) {
|
|
340
|
-
throw new Error(`Failed to extract project directory: ${error.message}`);
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
const [taskMasterResult, mcpResult] = await Promise.all([
|
|
344
|
-
detectTaskMasterFolder(projectPath),
|
|
345
|
-
detectTaskMasterMCPServer()
|
|
346
|
-
]);
|
|
347
|
-
// Determine status
|
|
348
|
-
let status = 'not-configured';
|
|
349
|
-
if (taskMasterResult.hasTaskmaster && taskMasterResult.hasEssentialFiles) {
|
|
350
|
-
if (mcpResult.hasMCPServer && mcpResult.isConfigured) {
|
|
351
|
-
status = 'fully-configured';
|
|
352
|
-
}
|
|
353
|
-
else {
|
|
354
|
-
status = 'taskmaster-only';
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
else if (mcpResult.hasMCPServer && mcpResult.isConfigured) {
|
|
358
|
-
status = 'mcp-only';
|
|
359
|
-
}
|
|
360
|
-
return {
|
|
361
|
-
projectName: project.name,
|
|
362
|
-
displayName: project.displayName,
|
|
363
|
-
projectPath,
|
|
364
|
-
status,
|
|
365
|
-
taskmaster: taskMasterResult,
|
|
366
|
-
mcp: mcpResult
|
|
367
|
-
};
|
|
368
|
-
}
|
|
369
|
-
catch (error) {
|
|
370
|
-
return {
|
|
371
|
-
projectName: project.name,
|
|
372
|
-
displayName: project.displayName,
|
|
373
|
-
status: 'error',
|
|
374
|
-
error: error.message
|
|
375
|
-
};
|
|
376
|
-
}
|
|
377
|
-
});
|
|
378
|
-
const results = await Promise.all(detectionPromises);
|
|
379
|
-
res.json({
|
|
380
|
-
projects: results,
|
|
381
|
-
summary: {
|
|
382
|
-
total: results.length,
|
|
383
|
-
fullyConfigured: results.filter(p => p.status === 'fully-configured').length,
|
|
384
|
-
taskmasterOnly: results.filter(p => p.status === 'taskmaster-only').length,
|
|
385
|
-
mcpOnly: results.filter(p => p.status === 'mcp-only').length,
|
|
386
|
-
notConfigured: results.filter(p => p.status === 'not-configured').length,
|
|
387
|
-
errors: results.filter(p => p.status === 'error').length
|
|
388
|
-
},
|
|
389
|
-
timestamp: new Date().toISOString()
|
|
390
|
-
});
|
|
391
|
-
}
|
|
392
|
-
catch (error) {
|
|
393
|
-
console.error('Bulk TaskMaster detection error:', error);
|
|
394
|
-
res.status(500).json({
|
|
395
|
-
error: 'Failed to detect TaskMaster configuration for projects',
|
|
396
|
-
message: error.message
|
|
397
|
-
});
|
|
398
|
-
}
|
|
399
|
-
});
|
|
400
|
-
/**
|
|
401
|
-
* POST /api/taskmaster/initialize/:projectName
|
|
402
|
-
* Initialize TaskMaster in a project (placeholder for future CLI integration)
|
|
403
|
-
*/
|
|
404
|
-
router.post('/initialize/:projectName', async (req, res) => {
|
|
405
|
-
try {
|
|
406
|
-
const { projectName } = req.params;
|
|
407
|
-
const { rules } = req.body; // Optional rule profiles
|
|
408
|
-
// This will be implemented in a later subtask with CLI integration
|
|
409
|
-
res.status(501).json({
|
|
410
|
-
error: 'TaskMaster initialization not yet implemented',
|
|
411
|
-
message: 'This endpoint will execute task-master init via CLI in a future update',
|
|
412
|
-
projectName,
|
|
413
|
-
rules
|
|
414
|
-
});
|
|
415
|
-
}
|
|
416
|
-
catch (error) {
|
|
417
|
-
console.error('TaskMaster initialization error:', error);
|
|
418
|
-
res.status(500).json({
|
|
419
|
-
error: 'Failed to initialize TaskMaster',
|
|
420
|
-
message: error.message
|
|
421
|
-
});
|
|
422
|
-
}
|
|
423
|
-
});
|
|
424
|
-
/**
|
|
425
|
-
* GET /api/taskmaster/next/:projectName
|
|
426
|
-
* Get the next recommended task using task-master CLI
|
|
427
|
-
*/
|
|
428
|
-
router.get('/next/:projectName', async (req, res) => {
|
|
429
|
-
try {
|
|
430
|
-
const { projectName } = req.params;
|
|
431
|
-
// Get project path
|
|
432
|
-
let projectPath;
|
|
433
|
-
try {
|
|
434
|
-
projectPath = await extractProjectDirectory(projectName);
|
|
435
|
-
}
|
|
436
|
-
catch (error) {
|
|
437
|
-
return res.status(404).json({
|
|
438
|
-
error: 'Project not found',
|
|
439
|
-
message: `Project "${projectName}" does not exist`
|
|
440
|
-
});
|
|
441
|
-
}
|
|
442
|
-
// Try to execute task-master next command
|
|
443
|
-
try {
|
|
444
|
-
const { spawn } = await import('child_process');
|
|
445
|
-
const nextTaskCommand = spawn('task-master', ['next'], {
|
|
446
|
-
cwd: projectPath,
|
|
447
|
-
stdio: ['pipe', 'pipe', 'pipe']
|
|
448
|
-
});
|
|
449
|
-
let stdout = '';
|
|
450
|
-
let stderr = '';
|
|
451
|
-
nextTaskCommand.stdout.on('data', (data) => {
|
|
452
|
-
stdout += data.toString();
|
|
453
|
-
});
|
|
454
|
-
nextTaskCommand.stderr.on('data', (data) => {
|
|
455
|
-
stderr += data.toString();
|
|
456
|
-
});
|
|
457
|
-
await new Promise((resolve, reject) => {
|
|
458
|
-
nextTaskCommand.on('close', (code) => {
|
|
459
|
-
if (code === 0) {
|
|
460
|
-
resolve();
|
|
461
|
-
}
|
|
462
|
-
else {
|
|
463
|
-
reject(new Error(`task-master next failed with code ${code}: ${stderr}`));
|
|
464
|
-
}
|
|
465
|
-
});
|
|
466
|
-
nextTaskCommand.on('error', (error) => {
|
|
467
|
-
reject(error);
|
|
468
|
-
});
|
|
469
|
-
});
|
|
470
|
-
// Parse the output - task-master next usually returns JSON
|
|
471
|
-
let nextTaskData = null;
|
|
472
|
-
if (stdout.trim()) {
|
|
473
|
-
try {
|
|
474
|
-
nextTaskData = JSON.parse(stdout);
|
|
475
|
-
}
|
|
476
|
-
catch (parseError) {
|
|
477
|
-
// If not JSON, treat as plain text
|
|
478
|
-
nextTaskData = { message: stdout.trim() };
|
|
479
|
-
}
|
|
480
|
-
}
|
|
481
|
-
res.json({
|
|
482
|
-
projectName,
|
|
483
|
-
projectPath,
|
|
484
|
-
nextTask: nextTaskData,
|
|
485
|
-
timestamp: new Date().toISOString()
|
|
486
|
-
});
|
|
487
|
-
}
|
|
488
|
-
catch (cliError) {
|
|
489
|
-
console.warn('Failed to execute task-master CLI:', cliError.message);
|
|
490
|
-
// Fallback to loading tasks and finding next one locally
|
|
491
|
-
// Use localhost to bypass proxy for internal server-to-server calls
|
|
492
|
-
const tasksResponse = await fetch(`http://localhost:${process.env.SERVER_PORT || process.env.PORT || '3001'}/api/taskmaster/tasks/${encodeURIComponent(projectName)}`, {
|
|
493
|
-
headers: {
|
|
494
|
-
'Authorization': req.headers.authorization
|
|
495
|
-
}
|
|
496
|
-
});
|
|
497
|
-
if (tasksResponse.ok) {
|
|
498
|
-
const tasksData = await tasksResponse.json();
|
|
499
|
-
const nextTask = tasksData.tasks?.find(task => task.status === 'pending' || task.status === 'in-progress') || null;
|
|
500
|
-
res.json({
|
|
501
|
-
projectName,
|
|
502
|
-
projectPath,
|
|
503
|
-
nextTask,
|
|
504
|
-
fallback: true,
|
|
505
|
-
message: 'Used fallback method (CLI not available)',
|
|
506
|
-
timestamp: new Date().toISOString()
|
|
507
|
-
});
|
|
508
|
-
}
|
|
509
|
-
else {
|
|
510
|
-
throw new Error('Failed to load tasks via fallback method');
|
|
511
|
-
}
|
|
512
|
-
}
|
|
513
|
-
}
|
|
514
|
-
catch (error) {
|
|
515
|
-
console.error('TaskMaster next task error:', error);
|
|
516
|
-
res.status(500).json({
|
|
517
|
-
error: 'Failed to get next task',
|
|
518
|
-
message: error.message
|
|
519
|
-
});
|
|
520
|
-
}
|
|
521
|
-
});
|
|
522
|
-
/**
|
|
523
|
-
* GET /api/taskmaster/tasks/:projectName
|
|
134
|
+
* GET /api/taskmaster/tasks/:projectId
|
|
524
135
|
* Load actual tasks from .taskmaster/tasks/tasks.json
|
|
136
|
+
*
|
|
137
|
+
* `projectId` is the DB primary key of the project; the folder is resolved via
|
|
138
|
+
* the projects table rather than extracted from Claude JSONL history.
|
|
525
139
|
*/
|
|
526
|
-
router.get('/tasks/:
|
|
140
|
+
router.get('/tasks/:projectId', async (req, res) => {
|
|
527
141
|
try {
|
|
528
|
-
const {
|
|
529
|
-
// Get project path
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
projectPath = await extractProjectDirectory(projectName);
|
|
533
|
-
}
|
|
534
|
-
catch (error) {
|
|
142
|
+
const { projectId } = req.params;
|
|
143
|
+
// Get project path via the DB; the legacy JSONL-based resolver is gone.
|
|
144
|
+
const projectPath = await resolveProjectPathFromId(projectId);
|
|
145
|
+
if (!projectPath) {
|
|
535
146
|
return res.status(404).json({
|
|
536
147
|
error: 'Project not found',
|
|
537
|
-
message: `Project "${
|
|
148
|
+
message: `Project "${projectId}" does not exist`
|
|
538
149
|
});
|
|
539
150
|
}
|
|
540
151
|
const taskMasterPath = path.join(projectPath, '.taskmaster');
|
|
@@ -545,7 +156,7 @@ router.get('/tasks/:projectName', async (req, res) => {
|
|
|
545
156
|
}
|
|
546
157
|
catch (error) {
|
|
547
158
|
return res.json({
|
|
548
|
-
|
|
159
|
+
projectId,
|
|
549
160
|
tasks: [],
|
|
550
161
|
message: 'No tasks.json file found'
|
|
551
162
|
});
|
|
@@ -597,7 +208,7 @@ router.get('/tasks/:projectName', async (req, res) => {
|
|
|
597
208
|
subtasks: task.subtasks || []
|
|
598
209
|
}));
|
|
599
210
|
res.json({
|
|
600
|
-
|
|
211
|
+
projectId,
|
|
601
212
|
projectPath,
|
|
602
213
|
tasks: transformedTasks,
|
|
603
214
|
currentTag,
|
|
@@ -630,21 +241,18 @@ router.get('/tasks/:projectName', async (req, res) => {
|
|
|
630
241
|
}
|
|
631
242
|
});
|
|
632
243
|
/**
|
|
633
|
-
* GET /api/taskmaster/prd/:
|
|
244
|
+
* GET /api/taskmaster/prd/:projectId
|
|
634
245
|
* List all PRD files in the project's .taskmaster/docs directory
|
|
635
246
|
*/
|
|
636
|
-
router.get('/prd/:
|
|
247
|
+
router.get('/prd/:projectId', async (req, res) => {
|
|
637
248
|
try {
|
|
638
|
-
const {
|
|
639
|
-
//
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
projectPath = await extractProjectDirectory(projectName);
|
|
643
|
-
}
|
|
644
|
-
catch (error) {
|
|
249
|
+
const { projectId } = req.params;
|
|
250
|
+
// projectId → projectPath lookup through the DB (post-migration).
|
|
251
|
+
const projectPath = await resolveProjectPathFromId(projectId);
|
|
252
|
+
if (!projectPath) {
|
|
645
253
|
return res.status(404).json({
|
|
646
254
|
error: 'Project not found',
|
|
647
|
-
message: `Project "${
|
|
255
|
+
message: `Project "${projectId}" does not exist`
|
|
648
256
|
});
|
|
649
257
|
}
|
|
650
258
|
const docsPath = path.join(projectPath, '.taskmaster', 'docs');
|
|
@@ -654,7 +262,7 @@ router.get('/prd/:projectName', async (req, res) => {
|
|
|
654
262
|
}
|
|
655
263
|
catch (error) {
|
|
656
264
|
return res.json({
|
|
657
|
-
|
|
265
|
+
projectId,
|
|
658
266
|
prdFiles: [],
|
|
659
267
|
message: 'No .taskmaster/docs directory found'
|
|
660
268
|
});
|
|
@@ -677,7 +285,7 @@ router.get('/prd/:projectName', async (req, res) => {
|
|
|
677
285
|
}
|
|
678
286
|
}
|
|
679
287
|
res.json({
|
|
680
|
-
|
|
288
|
+
projectId,
|
|
681
289
|
projectPath,
|
|
682
290
|
prdFiles: prdFiles.sort((a, b) => new Date(b.modified) - new Date(a.modified)),
|
|
683
291
|
timestamp: new Date().toISOString()
|
|
@@ -700,12 +308,12 @@ router.get('/prd/:projectName', async (req, res) => {
|
|
|
700
308
|
}
|
|
701
309
|
});
|
|
702
310
|
/**
|
|
703
|
-
* POST /api/taskmaster/prd/:
|
|
311
|
+
* POST /api/taskmaster/prd/:projectId
|
|
704
312
|
* Create or update a PRD file in the project's .taskmaster/docs directory
|
|
705
313
|
*/
|
|
706
|
-
router.post('/prd/:
|
|
314
|
+
router.post('/prd/:projectId', async (req, res) => {
|
|
707
315
|
try {
|
|
708
|
-
const {
|
|
316
|
+
const { projectId } = req.params;
|
|
709
317
|
const { fileName, content } = req.body;
|
|
710
318
|
if (!fileName || !content) {
|
|
711
319
|
return res.status(400).json({
|
|
@@ -720,15 +328,12 @@ router.post('/prd/:projectName', async (req, res) => {
|
|
|
720
328
|
message: 'Filename must end with .txt or .md and contain only alphanumeric characters, spaces, dots, and dashes'
|
|
721
329
|
});
|
|
722
330
|
}
|
|
723
|
-
//
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
projectPath = await extractProjectDirectory(projectName);
|
|
727
|
-
}
|
|
728
|
-
catch (error) {
|
|
331
|
+
// Resolve the project folder through the DB using the projectId param.
|
|
332
|
+
const projectPath = await resolveProjectPathFromId(projectId);
|
|
333
|
+
if (!projectPath) {
|
|
729
334
|
return res.status(404).json({
|
|
730
335
|
error: 'Project not found',
|
|
731
|
-
message: `Project "${
|
|
336
|
+
message: `Project "${projectId}" does not exist`
|
|
732
337
|
});
|
|
733
338
|
}
|
|
734
339
|
const docsPath = path.join(projectPath, '.taskmaster', 'docs');
|
|
@@ -750,7 +355,7 @@ router.post('/prd/:projectName', async (req, res) => {
|
|
|
750
355
|
// Get file stats
|
|
751
356
|
const stats = await fsPromises.stat(filePath);
|
|
752
357
|
res.json({
|
|
753
|
-
|
|
358
|
+
projectId,
|
|
754
359
|
projectPath,
|
|
755
360
|
fileName,
|
|
756
361
|
filePath: path.relative(projectPath, filePath),
|
|
@@ -778,21 +383,17 @@ router.post('/prd/:projectName', async (req, res) => {
|
|
|
778
383
|
}
|
|
779
384
|
});
|
|
780
385
|
/**
|
|
781
|
-
* GET /api/taskmaster/prd/:
|
|
386
|
+
* GET /api/taskmaster/prd/:projectId/:fileName
|
|
782
387
|
* Get content of a specific PRD file
|
|
783
388
|
*/
|
|
784
|
-
router.get('/prd/:
|
|
389
|
+
router.get('/prd/:projectId/:fileName', async (req, res) => {
|
|
785
390
|
try {
|
|
786
|
-
const {
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
try {
|
|
790
|
-
projectPath = await extractProjectDirectory(projectName);
|
|
791
|
-
}
|
|
792
|
-
catch (error) {
|
|
391
|
+
const { projectId, fileName } = req.params;
|
|
392
|
+
const projectPath = await resolveProjectPathFromId(projectId);
|
|
393
|
+
if (!projectPath) {
|
|
793
394
|
return res.status(404).json({
|
|
794
395
|
error: 'Project not found',
|
|
795
|
-
message: `Project "${
|
|
396
|
+
message: `Project "${projectId}" does not exist`
|
|
796
397
|
});
|
|
797
398
|
}
|
|
798
399
|
const filePath = path.join(projectPath, '.taskmaster', 'docs', fileName);
|
|
@@ -811,7 +412,7 @@ router.get('/prd/:projectName/:fileName', async (req, res) => {
|
|
|
811
412
|
const content = await fsPromises.readFile(filePath, 'utf8');
|
|
812
413
|
const stats = await fsPromises.stat(filePath);
|
|
813
414
|
res.json({
|
|
814
|
-
|
|
415
|
+
projectId,
|
|
815
416
|
projectPath,
|
|
816
417
|
fileName,
|
|
817
418
|
filePath: path.relative(projectPath, filePath),
|
|
@@ -839,77 +440,17 @@ router.get('/prd/:projectName/:fileName', async (req, res) => {
|
|
|
839
440
|
}
|
|
840
441
|
});
|
|
841
442
|
/**
|
|
842
|
-
*
|
|
843
|
-
* Delete a specific PRD file
|
|
844
|
-
*/
|
|
845
|
-
router.delete('/prd/:projectName/:fileName', async (req, res) => {
|
|
846
|
-
try {
|
|
847
|
-
const { projectName, fileName } = req.params;
|
|
848
|
-
// Get project path
|
|
849
|
-
let projectPath;
|
|
850
|
-
try {
|
|
851
|
-
projectPath = await extractProjectDirectory(projectName);
|
|
852
|
-
}
|
|
853
|
-
catch (error) {
|
|
854
|
-
return res.status(404).json({
|
|
855
|
-
error: 'Project not found',
|
|
856
|
-
message: `Project "${projectName}" does not exist`
|
|
857
|
-
});
|
|
858
|
-
}
|
|
859
|
-
const filePath = path.join(projectPath, '.taskmaster', 'docs', fileName);
|
|
860
|
-
// Check if file exists
|
|
861
|
-
try {
|
|
862
|
-
await fsPromises.access(filePath, fs.constants.F_OK);
|
|
863
|
-
}
|
|
864
|
-
catch (error) {
|
|
865
|
-
return res.status(404).json({
|
|
866
|
-
error: 'PRD file not found',
|
|
867
|
-
message: `File "${fileName}" does not exist`
|
|
868
|
-
});
|
|
869
|
-
}
|
|
870
|
-
// Delete the file
|
|
871
|
-
try {
|
|
872
|
-
await fsPromises.unlink(filePath);
|
|
873
|
-
res.json({
|
|
874
|
-
projectName,
|
|
875
|
-
projectPath,
|
|
876
|
-
fileName,
|
|
877
|
-
message: 'PRD file deleted successfully',
|
|
878
|
-
timestamp: new Date().toISOString()
|
|
879
|
-
});
|
|
880
|
-
}
|
|
881
|
-
catch (deleteError) {
|
|
882
|
-
console.error('Failed to delete PRD file:', deleteError);
|
|
883
|
-
return res.status(500).json({
|
|
884
|
-
error: 'Failed to delete PRD file',
|
|
885
|
-
message: deleteError.message
|
|
886
|
-
});
|
|
887
|
-
}
|
|
888
|
-
}
|
|
889
|
-
catch (error) {
|
|
890
|
-
console.error('PRD delete error:', error);
|
|
891
|
-
res.status(500).json({
|
|
892
|
-
error: 'Failed to delete PRD file',
|
|
893
|
-
message: error.message
|
|
894
|
-
});
|
|
895
|
-
}
|
|
896
|
-
});
|
|
897
|
-
/**
|
|
898
|
-
* POST /api/taskmaster/init/:projectName
|
|
443
|
+
* POST /api/taskmaster/init/:projectId
|
|
899
444
|
* Initialize TaskMaster in a project
|
|
900
445
|
*/
|
|
901
|
-
router.post('/init/:
|
|
446
|
+
router.post('/init/:projectId', async (req, res) => {
|
|
902
447
|
try {
|
|
903
|
-
const {
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
try {
|
|
907
|
-
projectPath = await extractProjectDirectory(projectName);
|
|
908
|
-
}
|
|
909
|
-
catch (error) {
|
|
448
|
+
const { projectId } = req.params;
|
|
449
|
+
const projectPath = await resolveProjectPathFromId(projectId);
|
|
450
|
+
if (!projectPath) {
|
|
910
451
|
return res.status(404).json({
|
|
911
452
|
error: 'Project not found',
|
|
912
|
-
message: `Project "${
|
|
453
|
+
message: `Project "${projectId}" does not exist`
|
|
913
454
|
});
|
|
914
455
|
}
|
|
915
456
|
// Check if TaskMaster is already initialized
|
|
@@ -939,12 +480,14 @@ router.post('/init/:projectName', async (req, res) => {
|
|
|
939
480
|
});
|
|
940
481
|
initProcess.on('close', (code) => {
|
|
941
482
|
if (code === 0) {
|
|
942
|
-
// Broadcast TaskMaster project update via WebSocket
|
|
483
|
+
// Broadcast TaskMaster project update via WebSocket. The
|
|
484
|
+
// WebSocket payload keeps using `projectId` so the frontend
|
|
485
|
+
// can match notifications against the current selection.
|
|
943
486
|
if (req.app.locals.wss) {
|
|
944
|
-
broadcastTaskMasterProjectUpdate(req.app.locals.wss,
|
|
487
|
+
broadcastTaskMasterProjectUpdate(req.app.locals.wss, projectId, { hasTaskmaster: true, status: 'initialized' });
|
|
945
488
|
}
|
|
946
489
|
res.json({
|
|
947
|
-
|
|
490
|
+
projectId,
|
|
948
491
|
projectPath,
|
|
949
492
|
message: 'TaskMaster initialized successfully',
|
|
950
493
|
output: stdout,
|
|
@@ -973,12 +516,12 @@ router.post('/init/:projectName', async (req, res) => {
|
|
|
973
516
|
}
|
|
974
517
|
});
|
|
975
518
|
/**
|
|
976
|
-
* POST /api/taskmaster/add-task/:
|
|
519
|
+
* POST /api/taskmaster/add-task/:projectId
|
|
977
520
|
* Add a new task to the project
|
|
978
521
|
*/
|
|
979
|
-
router.post('/add-task/:
|
|
522
|
+
router.post('/add-task/:projectId', async (req, res) => {
|
|
980
523
|
try {
|
|
981
|
-
const {
|
|
524
|
+
const { projectId } = req.params;
|
|
982
525
|
const { prompt, title, description, priority = 'medium', dependencies } = req.body;
|
|
983
526
|
if (!prompt && (!title || !description)) {
|
|
984
527
|
return res.status(400).json({
|
|
@@ -986,15 +529,11 @@ router.post('/add-task/:projectName', async (req, res) => {
|
|
|
986
529
|
message: 'Either "prompt" or both "title" and "description" are required'
|
|
987
530
|
});
|
|
988
531
|
}
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
try {
|
|
992
|
-
projectPath = await extractProjectDirectory(projectName);
|
|
993
|
-
}
|
|
994
|
-
catch (error) {
|
|
532
|
+
const projectPath = await resolveProjectPathFromId(projectId);
|
|
533
|
+
if (!projectPath) {
|
|
995
534
|
return res.status(404).json({
|
|
996
535
|
error: 'Project not found',
|
|
997
|
-
message: `Project "${
|
|
536
|
+
message: `Project "${projectId}" does not exist`
|
|
998
537
|
});
|
|
999
538
|
}
|
|
1000
539
|
// Build the task-master add-task command
|
|
@@ -1030,12 +569,13 @@ router.post('/add-task/:projectName', async (req, res) => {
|
|
|
1030
569
|
console.log('Stdout:', stdout);
|
|
1031
570
|
console.log('Stderr:', stderr);
|
|
1032
571
|
if (code === 0) {
|
|
1033
|
-
// Broadcast task update via WebSocket
|
|
572
|
+
// Broadcast task update via WebSocket using the projectId so
|
|
573
|
+
// clients subscribed to this project get notified immediately.
|
|
1034
574
|
if (req.app.locals.wss) {
|
|
1035
|
-
broadcastTaskMasterTasksUpdate(req.app.locals.wss,
|
|
575
|
+
broadcastTaskMasterTasksUpdate(req.app.locals.wss, projectId);
|
|
1036
576
|
}
|
|
1037
577
|
res.json({
|
|
1038
|
-
|
|
578
|
+
projectId,
|
|
1039
579
|
projectPath,
|
|
1040
580
|
message: 'Task added successfully',
|
|
1041
581
|
output: stdout,
|
|
@@ -1062,22 +602,18 @@ router.post('/add-task/:projectName', async (req, res) => {
|
|
|
1062
602
|
}
|
|
1063
603
|
});
|
|
1064
604
|
/**
|
|
1065
|
-
* PUT /api/taskmaster/update-task/:
|
|
605
|
+
* PUT /api/taskmaster/update-task/:projectId/:taskId
|
|
1066
606
|
* Update a specific task using TaskMaster CLI
|
|
1067
607
|
*/
|
|
1068
|
-
router.put('/update-task/:
|
|
608
|
+
router.put('/update-task/:projectId/:taskId', async (req, res) => {
|
|
1069
609
|
try {
|
|
1070
|
-
const {
|
|
610
|
+
const { projectId, taskId } = req.params;
|
|
1071
611
|
const { title, description, status, priority, details } = req.body;
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
try {
|
|
1075
|
-
projectPath = await extractProjectDirectory(projectName);
|
|
1076
|
-
}
|
|
1077
|
-
catch (error) {
|
|
612
|
+
const projectPath = await resolveProjectPathFromId(projectId);
|
|
613
|
+
if (!projectPath) {
|
|
1078
614
|
return res.status(404).json({
|
|
1079
615
|
error: 'Project not found',
|
|
1080
|
-
message: `Project "${
|
|
616
|
+
message: `Project "${projectId}" does not exist`
|
|
1081
617
|
});
|
|
1082
618
|
}
|
|
1083
619
|
// If only updating status, use set-status command
|
|
@@ -1098,10 +634,10 @@ router.put('/update-task/:projectName/:taskId', async (req, res) => {
|
|
|
1098
634
|
if (code === 0) {
|
|
1099
635
|
// Broadcast task update via WebSocket
|
|
1100
636
|
if (req.app.locals.wss) {
|
|
1101
|
-
broadcastTaskMasterTasksUpdate(req.app.locals.wss,
|
|
637
|
+
broadcastTaskMasterTasksUpdate(req.app.locals.wss, projectId);
|
|
1102
638
|
}
|
|
1103
639
|
res.json({
|
|
1104
|
-
|
|
640
|
+
projectId,
|
|
1105
641
|
projectPath,
|
|
1106
642
|
taskId,
|
|
1107
643
|
message: 'Task status updated successfully',
|
|
@@ -1148,10 +684,10 @@ router.put('/update-task/:projectName/:taskId', async (req, res) => {
|
|
|
1148
684
|
if (code === 0) {
|
|
1149
685
|
// Broadcast task update via WebSocket
|
|
1150
686
|
if (req.app.locals.wss) {
|
|
1151
|
-
broadcastTaskMasterTasksUpdate(req.app.locals.wss,
|
|
687
|
+
broadcastTaskMasterTasksUpdate(req.app.locals.wss, projectId);
|
|
1152
688
|
}
|
|
1153
689
|
res.json({
|
|
1154
|
-
|
|
690
|
+
projectId,
|
|
1155
691
|
projectPath,
|
|
1156
692
|
taskId,
|
|
1157
693
|
message: 'Task updated successfully',
|
|
@@ -1180,22 +716,18 @@ router.put('/update-task/:projectName/:taskId', async (req, res) => {
|
|
|
1180
716
|
}
|
|
1181
717
|
});
|
|
1182
718
|
/**
|
|
1183
|
-
* POST /api/taskmaster/parse-prd/:
|
|
719
|
+
* POST /api/taskmaster/parse-prd/:projectId
|
|
1184
720
|
* Parse a PRD file to generate tasks
|
|
1185
721
|
*/
|
|
1186
|
-
router.post('/parse-prd/:
|
|
722
|
+
router.post('/parse-prd/:projectId', async (req, res) => {
|
|
1187
723
|
try {
|
|
1188
|
-
const {
|
|
724
|
+
const { projectId } = req.params;
|
|
1189
725
|
const { fileName = 'prd.txt', numTasks, append = false } = req.body;
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
try {
|
|
1193
|
-
projectPath = await extractProjectDirectory(projectName);
|
|
1194
|
-
}
|
|
1195
|
-
catch (error) {
|
|
726
|
+
const projectPath = await resolveProjectPathFromId(projectId);
|
|
727
|
+
if (!projectPath) {
|
|
1196
728
|
return res.status(404).json({
|
|
1197
729
|
error: 'Project not found',
|
|
1198
|
-
message: `Project "${
|
|
730
|
+
message: `Project "${projectId}" does not exist`
|
|
1199
731
|
});
|
|
1200
732
|
}
|
|
1201
733
|
const prdPath = path.join(projectPath, '.taskmaster', 'docs', fileName);
|
|
@@ -1235,10 +767,10 @@ router.post('/parse-prd/:projectName', async (req, res) => {
|
|
|
1235
767
|
if (code === 0) {
|
|
1236
768
|
// Broadcast task update via WebSocket
|
|
1237
769
|
if (req.app.locals.wss) {
|
|
1238
|
-
broadcastTaskMasterTasksUpdate(req.app.locals.wss,
|
|
770
|
+
broadcastTaskMasterTasksUpdate(req.app.locals.wss, projectId);
|
|
1239
771
|
}
|
|
1240
772
|
res.json({
|
|
1241
|
-
|
|
773
|
+
projectId,
|
|
1242
774
|
projectPath,
|
|
1243
775
|
prdFile: fileName,
|
|
1244
776
|
message: 'PRD parsed and tasks generated successfully',
|
|
@@ -1710,12 +1242,12 @@ Description of the business problem, data sources, and expected insights.
|
|
|
1710
1242
|
}
|
|
1711
1243
|
});
|
|
1712
1244
|
/**
|
|
1713
|
-
* POST /api/taskmaster/apply-template/:
|
|
1245
|
+
* POST /api/taskmaster/apply-template/:projectId
|
|
1714
1246
|
* Apply a PRD template to create a new PRD file
|
|
1715
1247
|
*/
|
|
1716
|
-
router.post('/apply-template/:
|
|
1248
|
+
router.post('/apply-template/:projectId', async (req, res) => {
|
|
1717
1249
|
try {
|
|
1718
|
-
const {
|
|
1250
|
+
const { projectId } = req.params;
|
|
1719
1251
|
const { templateId, fileName = 'prd.txt', customizations = {} } = req.body;
|
|
1720
1252
|
if (!templateId) {
|
|
1721
1253
|
return res.status(400).json({
|
|
@@ -1723,15 +1255,11 @@ router.post('/apply-template/:projectName', async (req, res) => {
|
|
|
1723
1255
|
message: 'templateId is required'
|
|
1724
1256
|
});
|
|
1725
1257
|
}
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
try {
|
|
1729
|
-
projectPath = await extractProjectDirectory(projectName);
|
|
1730
|
-
}
|
|
1731
|
-
catch (error) {
|
|
1258
|
+
const projectPath = await resolveProjectPathFromId(projectId);
|
|
1259
|
+
if (!projectPath) {
|
|
1732
1260
|
return res.status(404).json({
|
|
1733
1261
|
error: 'Project not found',
|
|
1734
|
-
message: `Project "${
|
|
1262
|
+
message: `Project "${projectId}" does not exist`
|
|
1735
1263
|
});
|
|
1736
1264
|
}
|
|
1737
1265
|
// Get the template content (this would normally fetch from the templates list)
|
|
@@ -1763,7 +1291,7 @@ router.post('/apply-template/:projectName', async (req, res) => {
|
|
|
1763
1291
|
try {
|
|
1764
1292
|
await fsPromises.writeFile(filePath, content, 'utf8');
|
|
1765
1293
|
res.json({
|
|
1766
|
-
|
|
1294
|
+
projectId,
|
|
1767
1295
|
projectPath,
|
|
1768
1296
|
templateId,
|
|
1769
1297
|
templateName: template.name,
|