mcoda 0.1.2 → 0.1.4

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 (461) hide show
  1. package/CHANGELOG.md +2 -2
  2. package/README.md +9 -300
  3. package/dist/bin/McodaEntrypoint.d.ts +5 -0
  4. package/dist/bin/McodaEntrypoint.d.ts.map +1 -0
  5. package/dist/bin/McodaEntrypoint.js +175 -0
  6. package/dist/commands/agents/AgentsCommands.d.ts +4 -0
  7. package/dist/commands/agents/AgentsCommands.d.ts.map +1 -0
  8. package/dist/commands/agents/AgentsCommands.js +376 -0
  9. package/dist/commands/agents/GatewayAgentCommand.d.ts +4 -0
  10. package/dist/commands/agents/GatewayAgentCommand.d.ts.map +1 -0
  11. package/dist/commands/agents/GatewayAgentCommand.js +583 -0
  12. package/dist/commands/agents/TestAgentCommand.d.ts +4 -0
  13. package/dist/commands/agents/TestAgentCommand.d.ts.map +1 -0
  14. package/dist/commands/agents/TestAgentCommand.js +57 -0
  15. package/dist/commands/backlog/BacklogCommands.d.ts +17 -0
  16. package/dist/commands/backlog/BacklogCommands.d.ts.map +1 -0
  17. package/dist/commands/backlog/BacklogCommands.js +260 -0
  18. package/dist/commands/backlog/OrderTasksCommand.d.ts +16 -0
  19. package/dist/commands/backlog/OrderTasksCommand.d.ts.map +1 -0
  20. package/dist/commands/backlog/OrderTasksCommand.js +211 -0
  21. package/dist/commands/backlog/TaskShowCommands.d.ts +16 -0
  22. package/dist/commands/backlog/TaskShowCommands.d.ts.map +1 -0
  23. package/dist/commands/backlog/TaskShowCommands.js +275 -0
  24. package/dist/commands/docs/DocsCommands.d.ts +37 -0
  25. package/dist/commands/docs/DocsCommands.d.ts.map +1 -0
  26. package/dist/commands/docs/DocsCommands.js +381 -0
  27. package/dist/commands/estimate/EstimateCommands.d.ts +24 -0
  28. package/dist/commands/estimate/EstimateCommands.d.ts.map +1 -0
  29. package/dist/commands/estimate/EstimateCommands.js +259 -0
  30. package/dist/commands/jobs/JobsCommands.d.ts +24 -0
  31. package/dist/commands/jobs/JobsCommands.d.ts.map +1 -0
  32. package/dist/commands/jobs/JobsCommands.js +535 -0
  33. package/dist/commands/openapi/OpenapiCommands.d.ts +14 -0
  34. package/dist/commands/openapi/OpenapiCommands.d.ts.map +1 -0
  35. package/dist/commands/openapi/OpenapiCommands.js +157 -0
  36. package/dist/commands/planning/CreateTasksCommand.d.ts +17 -0
  37. package/dist/commands/planning/CreateTasksCommand.d.ts.map +1 -0
  38. package/dist/commands/planning/CreateTasksCommand.js +134 -0
  39. package/dist/commands/planning/MigrateTasksCommand.d.ts +15 -0
  40. package/dist/commands/planning/MigrateTasksCommand.d.ts.map +1 -0
  41. package/dist/commands/planning/MigrateTasksCommand.js +95 -0
  42. package/dist/commands/planning/PlanningCommands.d.ts +3 -0
  43. package/dist/commands/planning/PlanningCommands.d.ts.map +1 -0
  44. package/dist/commands/planning/PlanningCommands.js +2 -0
  45. package/dist/commands/planning/QaTasksCommand.d.ts +30 -0
  46. package/dist/commands/planning/QaTasksCommand.d.ts.map +1 -0
  47. package/dist/commands/planning/QaTasksCommand.js +293 -0
  48. package/dist/commands/planning/RefineTasksCommand.d.ts +30 -0
  49. package/dist/commands/planning/RefineTasksCommand.d.ts.map +1 -0
  50. package/dist/commands/planning/RefineTasksCommand.js +365 -0
  51. package/dist/commands/review/CodeReviewCommand.d.ts +21 -0
  52. package/dist/commands/review/CodeReviewCommand.d.ts.map +1 -0
  53. package/dist/commands/review/CodeReviewCommand.js +236 -0
  54. package/dist/commands/routing/RoutingCommands.d.ts +7 -0
  55. package/dist/commands/routing/RoutingCommands.d.ts.map +1 -0
  56. package/dist/commands/routing/RoutingCommands.js +484 -0
  57. package/dist/commands/telemetry/TelemetryCommands.d.ts +26 -0
  58. package/dist/commands/telemetry/TelemetryCommands.d.ts.map +1 -0
  59. package/dist/commands/telemetry/TelemetryCommands.js +313 -0
  60. package/dist/commands/update/UpdateCommands.d.ts +4 -0
  61. package/dist/commands/update/UpdateCommands.d.ts.map +1 -0
  62. package/dist/commands/update/UpdateCommands.js +280 -0
  63. package/dist/commands/work/WorkOnTasksCommand.d.ts +21 -0
  64. package/dist/commands/work/WorkOnTasksCommand.d.ts.map +1 -0
  65. package/dist/commands/work/WorkOnTasksCommand.js +238 -0
  66. package/dist/commands/workspace/SetWorkspaceCommand.d.ts +9 -0
  67. package/dist/commands/workspace/SetWorkspaceCommand.d.ts.map +1 -0
  68. package/dist/commands/workspace/SetWorkspaceCommand.js +128 -0
  69. package/dist/index.d.ts +19 -0
  70. package/dist/index.d.ts.map +1 -0
  71. package/package.json +31 -16
  72. package/.editorconfig +0 -9
  73. package/.eslintrc.cjs +0 -12
  74. package/.github/ISSUE_TEMPLATE/bug_report.md +0 -29
  75. package/.github/ISSUE_TEMPLATE/config.yml +0 -5
  76. package/.github/ISSUE_TEMPLATE/feature_request.md +0 -19
  77. package/.github/workflows/ci.yml +0 -37
  78. package/.github/workflows/nightly.yml +0 -38
  79. package/.github/workflows/release-dry-run.yml +0 -40
  80. package/.github/workflows/release-please.yml +0 -22
  81. package/.github/workflows/release.yml +0 -139
  82. package/.prettierrc +0 -5
  83. package/.release-please-manifest.json +0 -8
  84. package/CLA.md +0 -42
  85. package/CONTRIBUTING.md +0 -38
  86. package/docs/oss_publishing_plan.md +0 -41
  87. package/docs/pdr/.gitkeep +0 -0
  88. package/docs/quality_gates.md +0 -32
  89. package/docs/rfp/.gitkeep +0 -0
  90. package/docs/sds/sds.md +0 -11963
  91. package/docs/usage.md +0 -72
  92. package/openapi/gen-openapi.ts +0 -1
  93. package/openapi/generated/clients/.gitkeep +0 -0
  94. package/openapi/generated/types/.gitkeep +0 -0
  95. package/openapi/generated/types/index.ts +0 -118
  96. package/openapi/mcoda.yaml +0 -2063
  97. package/pack-mcoda.sh +0 -88
  98. package/packages/agents/CHANGELOG.md +0 -7
  99. package/packages/agents/LICENSE +0 -21
  100. package/packages/agents/README.md +0 -9
  101. package/packages/agents/package.json +0 -41
  102. package/packages/agents/src/AgentService/.gitkeep +0 -0
  103. package/packages/agents/src/AgentService/AgentService.d.ts +0 -21
  104. package/packages/agents/src/AgentService/AgentService.d.ts.map +0 -1
  105. package/packages/agents/src/AgentService/AgentService.js +0 -141
  106. package/packages/agents/src/AgentService/AgentService.ts +0 -308
  107. package/packages/agents/src/__tests__/AgentService.test.ts +0 -284
  108. package/packages/agents/src/adapters/AdapterTypes.d.ts +0 -29
  109. package/packages/agents/src/adapters/AdapterTypes.d.ts.map +0 -1
  110. package/packages/agents/src/adapters/AdapterTypes.js +0 -1
  111. package/packages/agents/src/adapters/AdapterTypes.ts +0 -32
  112. package/packages/agents/src/adapters/codex/.gitkeep +0 -0
  113. package/packages/agents/src/adapters/codex/CodexAdapter.d.ts +0 -11
  114. package/packages/agents/src/adapters/codex/CodexAdapter.d.ts.map +0 -1
  115. package/packages/agents/src/adapters/codex/CodexAdapter.js +0 -43
  116. package/packages/agents/src/adapters/codex/CodexAdapter.ts +0 -63
  117. package/packages/agents/src/adapters/codex/CodexCliRunner.ts +0 -154
  118. package/packages/agents/src/adapters/gemini/.gitkeep +0 -0
  119. package/packages/agents/src/adapters/gemini/GeminiAdapter.d.ts +0 -11
  120. package/packages/agents/src/adapters/gemini/GeminiAdapter.d.ts.map +0 -1
  121. package/packages/agents/src/adapters/gemini/GeminiAdapter.js +0 -42
  122. package/packages/agents/src/adapters/gemini/GeminiAdapter.ts +0 -58
  123. package/packages/agents/src/adapters/gemini/GeminiCliRunner.ts +0 -75
  124. package/packages/agents/src/adapters/local/.gitkeep +0 -0
  125. package/packages/agents/src/adapters/local/LocalAdapter.d.ts +0 -11
  126. package/packages/agents/src/adapters/local/LocalAdapter.d.ts.map +0 -1
  127. package/packages/agents/src/adapters/local/LocalAdapter.js +0 -38
  128. package/packages/agents/src/adapters/local/LocalAdapter.ts +0 -43
  129. package/packages/agents/src/adapters/ollama/OllamaCliAdapter.ts +0 -58
  130. package/packages/agents/src/adapters/ollama/OllamaCliRunner.ts +0 -70
  131. package/packages/agents/src/adapters/ollama/OllamaRemoteAdapter.ts +0 -205
  132. package/packages/agents/src/adapters/openai/.gitkeep +0 -0
  133. package/packages/agents/src/adapters/openai/OpenAiAdapter.d.ts +0 -11
  134. package/packages/agents/src/adapters/openai/OpenAiAdapter.d.ts.map +0 -1
  135. package/packages/agents/src/adapters/openai/OpenAiAdapter.js +0 -51
  136. package/packages/agents/src/adapters/openai/OpenAiAdapter.ts +0 -56
  137. package/packages/agents/src/adapters/openai/OpenAiCliAdapter.ts +0 -62
  138. package/packages/agents/src/adapters/qa/.gitkeep +0 -0
  139. package/packages/agents/src/adapters/qa/QaAdapter.d.ts +0 -11
  140. package/packages/agents/src/adapters/qa/QaAdapter.d.ts.map +0 -1
  141. package/packages/agents/src/adapters/qa/QaAdapter.js +0 -37
  142. package/packages/agents/src/adapters/qa/QaAdapter.ts +0 -42
  143. package/packages/agents/src/adapters/zhipu/ZhipuApiAdapter.ts +0 -273
  144. package/packages/agents/src/index.d.ts +0 -8
  145. package/packages/agents/src/index.d.ts.map +0 -1
  146. package/packages/agents/src/index.js +0 -7
  147. package/packages/agents/src/index.ts +0 -11
  148. package/packages/agents/tsconfig.json +0 -14
  149. package/packages/cli/CHANGELOG.md +0 -7
  150. package/packages/cli/LICENSE +0 -21
  151. package/packages/cli/README.md +0 -23
  152. package/packages/cli/package.json +0 -61
  153. package/packages/cli/src/__tests__/AgentsCommands.test.ts +0 -137
  154. package/packages/cli/src/__tests__/BacklogCommands.test.ts +0 -40
  155. package/packages/cli/src/__tests__/CodeReviewCommand.test.ts +0 -594
  156. package/packages/cli/src/__tests__/CreateTasksCommand.test.ts +0 -40
  157. package/packages/cli/src/__tests__/DocsCommands.test.ts +0 -41
  158. package/packages/cli/src/__tests__/EstimateCommands.test.ts +0 -54
  159. package/packages/cli/src/__tests__/JobsCommands.behavior.test.ts +0 -311
  160. package/packages/cli/src/__tests__/JobsCommands.test.ts +0 -49
  161. package/packages/cli/src/__tests__/MigrateTasksCommand.test.ts +0 -36
  162. package/packages/cli/src/__tests__/OpenapiCommands.test.ts +0 -34
  163. package/packages/cli/src/__tests__/OrderTasksCommand.test.ts +0 -150
  164. package/packages/cli/src/__tests__/PlanningCommands.test.ts +0 -9
  165. package/packages/cli/src/__tests__/QaTasksCommand.test.ts +0 -58
  166. package/packages/cli/src/__tests__/RefineTasksCommand.test.ts +0 -63
  167. package/packages/cli/src/__tests__/RoutingCommands.test.ts +0 -302
  168. package/packages/cli/src/__tests__/SetWorkspaceCommand.test.ts +0 -18
  169. package/packages/cli/src/__tests__/TaskShowCommands.test.ts +0 -130
  170. package/packages/cli/src/__tests__/TelemetryCommands.test.ts +0 -35
  171. package/packages/cli/src/__tests__/TestAgentCommand.test.ts +0 -41
  172. package/packages/cli/src/__tests__/UpdateCommands.test.ts +0 -292
  173. package/packages/cli/src/__tests__/WorkOnTasksCommand.test.ts +0 -42
  174. package/packages/cli/src/bin/.gitkeep +0 -0
  175. package/packages/cli/src/bin/McodaEntrypoint.ts +0 -180
  176. package/packages/cli/src/commands/agents/.gitkeep +0 -0
  177. package/packages/cli/src/commands/agents/AgentsCommands.ts +0 -374
  178. package/packages/cli/src/commands/agents/GatewayAgentCommand.ts +0 -621
  179. package/packages/cli/src/commands/agents/TestAgentCommand.ts +0 -63
  180. package/packages/cli/src/commands/backlog/.gitkeep +0 -0
  181. package/packages/cli/src/commands/backlog/BacklogCommands.ts +0 -286
  182. package/packages/cli/src/commands/backlog/OrderTasksCommand.ts +0 -237
  183. package/packages/cli/src/commands/backlog/TaskShowCommands.ts +0 -289
  184. package/packages/cli/src/commands/docs/.gitkeep +0 -0
  185. package/packages/cli/src/commands/docs/DocsCommands.ts +0 -413
  186. package/packages/cli/src/commands/estimate/EstimateCommands.ts +0 -290
  187. package/packages/cli/src/commands/jobs/.gitkeep +0 -0
  188. package/packages/cli/src/commands/jobs/JobsCommands.ts +0 -595
  189. package/packages/cli/src/commands/openapi/OpenapiCommands.ts +0 -167
  190. package/packages/cli/src/commands/planning/.gitkeep +0 -0
  191. package/packages/cli/src/commands/planning/CreateTasksCommand.ts +0 -149
  192. package/packages/cli/src/commands/planning/MigrateTasksCommand.ts +0 -105
  193. package/packages/cli/src/commands/planning/PlanningCommands.ts +0 -1
  194. package/packages/cli/src/commands/planning/QaTasksCommand.ts +0 -320
  195. package/packages/cli/src/commands/planning/RefineTasksCommand.ts +0 -408
  196. package/packages/cli/src/commands/review/CodeReviewCommand.ts +0 -262
  197. package/packages/cli/src/commands/routing/.gitkeep +0 -0
  198. package/packages/cli/src/commands/routing/RoutingCommands.ts +0 -554
  199. package/packages/cli/src/commands/telemetry/.gitkeep +0 -0
  200. package/packages/cli/src/commands/telemetry/TelemetryCommands.ts +0 -348
  201. package/packages/cli/src/commands/update/.gitkeep +0 -0
  202. package/packages/cli/src/commands/update/UpdateCommands.ts +0 -301
  203. package/packages/cli/src/commands/work/WorkOnTasksCommand.ts +0 -264
  204. package/packages/cli/src/commands/workspace/SetWorkspaceCommand.ts +0 -132
  205. package/packages/cli/test/packaging_guardrails.test.js +0 -75
  206. package/packages/cli/tsconfig.json +0 -20
  207. package/packages/core/CHANGELOG.md +0 -7
  208. package/packages/core/LICENSE +0 -21
  209. package/packages/core/README.md +0 -9
  210. package/packages/core/package.json +0 -45
  211. package/packages/core/src/__tests__/SmokeClasses.test.ts +0 -32
  212. package/packages/core/src/api/AgentsApi.ts +0 -219
  213. package/packages/core/src/api/QaTasksApi.ts +0 -38
  214. package/packages/core/src/api/TasksApi.ts +0 -35
  215. package/packages/core/src/api/__tests__/AgentsApi.test.ts +0 -203
  216. package/packages/core/src/api/__tests__/QaTasksApi.test.ts +0 -51
  217. package/packages/core/src/api/__tests__/TasksApi.test.ts +0 -56
  218. package/packages/core/src/config/.gitkeep +0 -0
  219. package/packages/core/src/config/ConfigService.ts +0 -1
  220. package/packages/core/src/domain/dependencies/.gitkeep +0 -0
  221. package/packages/core/src/domain/dependencies/Dependency.ts +0 -1
  222. package/packages/core/src/domain/epics/.gitkeep +0 -0
  223. package/packages/core/src/domain/epics/Epic.ts +0 -1
  224. package/packages/core/src/domain/projects/.gitkeep +0 -0
  225. package/packages/core/src/domain/projects/Project.ts +0 -1
  226. package/packages/core/src/domain/tasks/.gitkeep +0 -0
  227. package/packages/core/src/domain/tasks/Task.ts +0 -1
  228. package/packages/core/src/domain/userStories/.gitkeep +0 -0
  229. package/packages/core/src/domain/userStories/UserStory.ts +0 -1
  230. package/packages/core/src/index.ts +0 -27
  231. package/packages/core/src/prompts/.gitkeep +0 -0
  232. package/packages/core/src/prompts/PdrPrompts.ts +0 -23
  233. package/packages/core/src/prompts/PromptLoader.ts +0 -1
  234. package/packages/core/src/prompts/SdsPrompts.ts +0 -47
  235. package/packages/core/src/services/agents/.gitkeep +0 -0
  236. package/packages/core/src/services/agents/AgentManagementService.ts +0 -1
  237. package/packages/core/src/services/agents/GatewayAgentService.ts +0 -956
  238. package/packages/core/src/services/agents/RoutingService.ts +0 -461
  239. package/packages/core/src/services/agents/__tests__/GatewayAgentService.test.ts +0 -72
  240. package/packages/core/src/services/agents/__tests__/RoutingService.test.ts +0 -267
  241. package/packages/core/src/services/agents/generated/RoutingApiClient.ts +0 -89
  242. package/packages/core/src/services/backlog/.gitkeep +0 -0
  243. package/packages/core/src/services/backlog/BacklogService.ts +0 -580
  244. package/packages/core/src/services/backlog/TaskOrderingService.ts +0 -868
  245. package/packages/core/src/services/backlog/__tests__/BacklogService.test.ts +0 -219
  246. package/packages/core/src/services/backlog/__tests__/TaskOrderingService.test.ts +0 -268
  247. package/packages/core/src/services/docs/.gitkeep +0 -0
  248. package/packages/core/src/services/docs/DocsService.ts +0 -1913
  249. package/packages/core/src/services/docs/__tests__/DocsService.test.ts +0 -350
  250. package/packages/core/src/services/estimate/EstimateService.ts +0 -111
  251. package/packages/core/src/services/estimate/VelocityService.ts +0 -272
  252. package/packages/core/src/services/estimate/__tests__/VelocityAndEstimate.test.ts +0 -209
  253. package/packages/core/src/services/estimate/types.ts +0 -41
  254. package/packages/core/src/services/execution/.gitkeep +0 -0
  255. package/packages/core/src/services/execution/ExecutionService.ts +0 -1
  256. package/packages/core/src/services/execution/QaFollowupService.ts +0 -289
  257. package/packages/core/src/services/execution/QaProfileService.ts +0 -160
  258. package/packages/core/src/services/execution/QaTasksService.ts +0 -1303
  259. package/packages/core/src/services/execution/TaskSelectionService.ts +0 -362
  260. package/packages/core/src/services/execution/TaskStateService.ts +0 -64
  261. package/packages/core/src/services/execution/WorkOnTasksService.ts +0 -2023
  262. package/packages/core/src/services/execution/__tests__/QaFollowupService.test.ts +0 -58
  263. package/packages/core/src/services/execution/__tests__/QaProfileService.test.ts +0 -49
  264. package/packages/core/src/services/execution/__tests__/QaTasksService.test.ts +0 -157
  265. package/packages/core/src/services/execution/__tests__/TaskSelectionService.test.ts +0 -179
  266. package/packages/core/src/services/execution/__tests__/TaskStateService.test.ts +0 -51
  267. package/packages/core/src/services/execution/__tests__/WorkOnTasksService.test.ts +0 -285
  268. package/packages/core/src/services/jobs/.gitkeep +0 -0
  269. package/packages/core/src/services/jobs/JobInsightsService.ts +0 -355
  270. package/packages/core/src/services/jobs/JobResumeService.ts +0 -119
  271. package/packages/core/src/services/jobs/JobService.ts +0 -648
  272. package/packages/core/src/services/jobs/JobsApiClient.ts +0 -113
  273. package/packages/core/src/services/jobs/__tests__/JobInsightsService.test.ts +0 -17
  274. package/packages/core/src/services/jobs/__tests__/JobResumeService.test.ts +0 -45
  275. package/packages/core/src/services/jobs/__tests__/JobService.test.ts +0 -44
  276. package/packages/core/src/services/openapi/OpenApiService.ts +0 -558
  277. package/packages/core/src/services/openapi/__tests__/OpenApiService.test.ts +0 -57
  278. package/packages/core/src/services/planning/.gitkeep +0 -0
  279. package/packages/core/src/services/planning/CreateTasksService.ts +0 -1280
  280. package/packages/core/src/services/planning/KeyHelpers.ts +0 -80
  281. package/packages/core/src/services/planning/PlanningService.ts +0 -1
  282. package/packages/core/src/services/planning/RefineTasksService.ts +0 -1552
  283. package/packages/core/src/services/planning/__tests__/CreateTasksService.test.ts +0 -288
  284. package/packages/core/src/services/planning/__tests__/KeyHelpers.test.ts +0 -16
  285. package/packages/core/src/services/planning/__tests__/RefineTasksService.test.ts +0 -172
  286. package/packages/core/src/services/review/CodeReviewService.ts +0 -1386
  287. package/packages/core/src/services/review/__tests__/CodeReviewService.test.ts +0 -89
  288. package/packages/core/src/services/system/SystemUpdateService.ts +0 -177
  289. package/packages/core/src/services/system/__tests__/SystemUpdateService.test.ts +0 -40
  290. package/packages/core/src/services/tasks/TaskApiResolver.ts +0 -37
  291. package/packages/core/src/services/tasks/TaskDetailService.ts +0 -494
  292. package/packages/core/src/services/tasks/__tests__/TaskApiResolver.test.ts +0 -41
  293. package/packages/core/src/services/tasks/__tests__/TaskDetailService.test.ts +0 -178
  294. package/packages/core/src/services/telemetry/.gitkeep +0 -0
  295. package/packages/core/src/services/telemetry/TelemetryService.ts +0 -515
  296. package/packages/core/src/services/telemetry/__tests__/TelemetryService.test.ts +0 -160
  297. package/packages/core/src/workspace/.gitkeep +0 -0
  298. package/packages/core/src/workspace/WorkspaceManager.ts +0 -234
  299. package/packages/core/tsconfig.json +0 -20
  300. package/packages/db/CHANGELOG.md +0 -7
  301. package/packages/db/LICENSE +0 -21
  302. package/packages/db/README.md +0 -9
  303. package/packages/db/package.json +0 -42
  304. package/packages/db/src/__tests__/GlobalRepository.test.ts +0 -109
  305. package/packages/db/src/__tests__/SchemaAlignment.test.ts +0 -80
  306. package/packages/db/src/__tests__/WorkspaceRepository.test.ts +0 -19
  307. package/packages/db/src/index.d.ts +0 -6
  308. package/packages/db/src/index.d.ts.map +0 -1
  309. package/packages/db/src/index.js +0 -5
  310. package/packages/db/src/index.ts +0 -6
  311. package/packages/db/src/migrations/global/.gitkeep +0 -0
  312. package/packages/db/src/migrations/global/GlobalMigrations.d.ts +0 -9
  313. package/packages/db/src/migrations/global/GlobalMigrations.d.ts.map +0 -1
  314. package/packages/db/src/migrations/global/GlobalMigrations.js +0 -68
  315. package/packages/db/src/migrations/global/GlobalMigrations.ts +0 -336
  316. package/packages/db/src/migrations/workspace/.gitkeep +0 -0
  317. package/packages/db/src/migrations/workspace/WorkspaceMigrations.d.ts +0 -9
  318. package/packages/db/src/migrations/workspace/WorkspaceMigrations.d.ts.map +0 -1
  319. package/packages/db/src/migrations/workspace/WorkspaceMigrations.js +0 -251
  320. package/packages/db/src/migrations/workspace/WorkspaceMigrations.ts +0 -248
  321. package/packages/db/src/repositories/global/.gitkeep +0 -0
  322. package/packages/db/src/repositories/global/GlobalRepository.d.ts +0 -30
  323. package/packages/db/src/repositories/global/GlobalRepository.d.ts.map +0 -1
  324. package/packages/db/src/repositories/global/GlobalRepository.js +0 -209
  325. package/packages/db/src/repositories/global/GlobalRepository.ts +0 -492
  326. package/packages/db/src/repositories/workspace/.gitkeep +0 -0
  327. package/packages/db/src/repositories/workspace/WorkspaceRepository.d.ts +0 -282
  328. package/packages/db/src/repositories/workspace/WorkspaceRepository.d.ts.map +0 -1
  329. package/packages/db/src/repositories/workspace/WorkspaceRepository.js +0 -773
  330. package/packages/db/src/repositories/workspace/WorkspaceRepository.ts +0 -1511
  331. package/packages/db/src/sqlite/connection.d.ts +0 -11
  332. package/packages/db/src/sqlite/connection.d.ts.map +0 -1
  333. package/packages/db/src/sqlite/connection.js +0 -31
  334. package/packages/db/src/sqlite/connection.ts +0 -35
  335. package/packages/db/src/sqlite/pragmas.d.ts +0 -5
  336. package/packages/db/src/sqlite/pragmas.d.ts.map +0 -1
  337. package/packages/db/src/sqlite/pragmas.js +0 -6
  338. package/packages/db/src/sqlite/pragmas.ts +0 -10
  339. package/packages/db/tsconfig.json +0 -13
  340. package/packages/generators/package.json +0 -21
  341. package/packages/generators/src/__tests__/Generators.test.ts +0 -19
  342. package/packages/generators/src/index.ts +0 -1
  343. package/packages/generators/src/openapi/generateTypes.ts +0 -1
  344. package/packages/generators/src/openapi/validateSchema.ts +0 -1
  345. package/packages/generators/src/scaffolding/docs/.gitkeep +0 -0
  346. package/packages/generators/src/scaffolding/docs/DocsScaffolder.ts +0 -1
  347. package/packages/generators/src/scaffolding/global/.gitkeep +0 -0
  348. package/packages/generators/src/scaffolding/global/GlobalScaffolder.ts +0 -1
  349. package/packages/generators/src/scaffolding/workspace/.gitkeep +0 -0
  350. package/packages/generators/src/scaffolding/workspace/WorkspaceScaffolder.ts +0 -1
  351. package/packages/generators/tsconfig.json +0 -10
  352. package/packages/integrations/CHANGELOG.md +0 -7
  353. package/packages/integrations/LICENSE +0 -21
  354. package/packages/integrations/README.md +0 -9
  355. package/packages/integrations/package.json +0 -47
  356. package/packages/integrations/src/docdex/.gitkeep +0 -0
  357. package/packages/integrations/src/docdex/DocdexClient.d.ts +0 -50
  358. package/packages/integrations/src/docdex/DocdexClient.d.ts.map +0 -1
  359. package/packages/integrations/src/docdex/DocdexClient.js +0 -216
  360. package/packages/integrations/src/docdex/DocdexClient.ts +0 -261
  361. package/packages/integrations/src/docdex/__tests__/DocdexClient.test.ts +0 -29
  362. package/packages/integrations/src/index.d.ts +0 -2
  363. package/packages/integrations/src/index.d.ts.map +0 -1
  364. package/packages/integrations/src/index.js +0 -4
  365. package/packages/integrations/src/index.ts +0 -5
  366. package/packages/integrations/src/issues/.gitkeep +0 -0
  367. package/packages/integrations/src/issues/IssuesClient.ts +0 -1
  368. package/packages/integrations/src/issues/__tests__/IssuesClient.test.ts +0 -10
  369. package/packages/integrations/src/qa/.gitkeep +0 -0
  370. package/packages/integrations/src/qa/ChromiumQaAdapter.ts +0 -89
  371. package/packages/integrations/src/qa/CliQaAdapter.ts +0 -95
  372. package/packages/integrations/src/qa/MaestroQaAdapter.ts +0 -91
  373. package/packages/integrations/src/qa/QaAdapter.ts +0 -7
  374. package/packages/integrations/src/qa/QaClient.ts +0 -1
  375. package/packages/integrations/src/qa/QaTypes.ts +0 -26
  376. package/packages/integrations/src/qa/__tests__/ChromiumQaAdapter.test.ts +0 -30
  377. package/packages/integrations/src/qa/__tests__/CliQaAdapter.test.ts +0 -33
  378. package/packages/integrations/src/qa/__tests__/MaestroQaAdapter.test.ts +0 -30
  379. package/packages/integrations/src/qa/index.ts +0 -5
  380. package/packages/integrations/src/system/SystemClient.ts +0 -50
  381. package/packages/integrations/src/system/__tests__/SystemClient.test.ts +0 -40
  382. package/packages/integrations/src/telemetry/TelemetryClient.ts +0 -139
  383. package/packages/integrations/src/telemetry/__tests__/TelemetryClient.test.ts +0 -41
  384. package/packages/integrations/src/vcs/.gitkeep +0 -0
  385. package/packages/integrations/src/vcs/VcsClient.ts +0 -211
  386. package/packages/integrations/src/vcs/__tests__/VcsClient.test.ts +0 -26
  387. package/packages/integrations/tsconfig.json +0 -14
  388. package/packages/shared/CHANGELOG.md +0 -7
  389. package/packages/shared/LICENSE +0 -21
  390. package/packages/shared/README.md +0 -9
  391. package/packages/shared/package.json +0 -40
  392. package/packages/shared/src/__tests__/CommandMetadata.test.ts +0 -15
  393. package/packages/shared/src/__tests__/ServiceShells.test.ts +0 -16
  394. package/packages/shared/src/crypto/.gitkeep +0 -0
  395. package/packages/shared/src/crypto/CryptoHelper.d.ts +0 -15
  396. package/packages/shared/src/crypto/CryptoHelper.d.ts.map +0 -1
  397. package/packages/shared/src/crypto/CryptoHelper.js +0 -54
  398. package/packages/shared/src/crypto/CryptoHelper.ts +0 -57
  399. package/packages/shared/src/errors/.gitkeep +0 -0
  400. package/packages/shared/src/errors/ErrorFactory.ts +0 -1
  401. package/packages/shared/src/index.d.ts +0 -6
  402. package/packages/shared/src/index.d.ts.map +0 -1
  403. package/packages/shared/src/index.js +0 -4
  404. package/packages/shared/src/index.ts +0 -35
  405. package/packages/shared/src/logging/.gitkeep +0 -0
  406. package/packages/shared/src/logging/Logger.ts +0 -1
  407. package/packages/shared/src/metadata/CommandMetadata.ts +0 -165
  408. package/packages/shared/src/openapi/.gitkeep +0 -0
  409. package/packages/shared/src/openapi/OpenApiTypes.d.ts +0 -216
  410. package/packages/shared/src/openapi/OpenApiTypes.d.ts.map +0 -1
  411. package/packages/shared/src/openapi/OpenApiTypes.js +0 -1
  412. package/packages/shared/src/openapi/OpenApiTypes.ts +0 -312
  413. package/packages/shared/src/paths/.gitkeep +0 -0
  414. package/packages/shared/src/paths/PathHelper.d.ts +0 -12
  415. package/packages/shared/src/paths/PathHelper.d.ts.map +0 -1
  416. package/packages/shared/src/paths/PathHelper.js +0 -24
  417. package/packages/shared/src/paths/PathHelper.ts +0 -29
  418. package/packages/shared/src/qa/QaProfile.ts +0 -14
  419. package/packages/shared/src/utils/.gitkeep +0 -0
  420. package/packages/shared/src/utils/UtilityService.ts +0 -1
  421. package/packages/shared/tsconfig.json +0 -10
  422. package/packages/testing/package.json +0 -26
  423. package/packages/testing/src/__tests__/TestingFakes.test.ts +0 -15
  424. package/packages/testing/src/cli/e2e/.gitkeep +0 -0
  425. package/packages/testing/src/cli/e2e/E2eSuite.ts +0 -1
  426. package/packages/testing/src/fakes/agents/.gitkeep +0 -0
  427. package/packages/testing/src/fakes/agents/FakeAgents.ts +0 -1
  428. package/packages/testing/src/fakes/docdex/.gitkeep +0 -0
  429. package/packages/testing/src/fakes/docdex/FakeDocdexClient.ts +0 -1
  430. package/packages/testing/src/fakes/qa/.gitkeep +0 -0
  431. package/packages/testing/src/fakes/qa/FakeQaClient.ts +0 -1
  432. package/packages/testing/src/fakes/vcs/.gitkeep +0 -0
  433. package/packages/testing/src/fakes/vcs/FakeVcsClient.ts +0 -1
  434. package/packages/testing/src/fixtures/db/.gitkeep +0 -0
  435. package/packages/testing/src/fixtures/db/DbFixtures.ts +0 -1
  436. package/packages/testing/src/fixtures/workspaces/.gitkeep +0 -0
  437. package/packages/testing/src/fixtures/workspaces/WorkspaceFixtures.ts +0 -1
  438. package/packages/testing/src/index.ts +0 -1
  439. package/packages/testing/tsconfig.json +0 -10
  440. package/pnpm-workspace.yaml +0 -2
  441. package/prompts/README.md +0 -5
  442. package/prompts/code-reviewer.md +0 -23
  443. package/prompts/code-writer.md +0 -35
  444. package/prompts/gateway-agent.md +0 -27
  445. package/prompts/qa-agent.md +0 -21
  446. package/release-please-config.json +0 -39
  447. package/scripts/build-all.ts +0 -1
  448. package/scripts/dev.ts +0 -1
  449. package/scripts/install-local-cli.sh +0 -28
  450. package/scripts/pack-npm-tarballs.js +0 -63
  451. package/scripts/release.ts +0 -1
  452. package/scripts/run-node-tests.js +0 -37
  453. package/tests/all.js +0 -127
  454. package/tests/api/openapi_spec.test.js +0 -21
  455. package/tests/artifacts.md +0 -31
  456. package/tests/component/cli_version.test.js +0 -38
  457. package/tests/integration/workspace_resolver.test.js +0 -44
  458. package/tests/unit/crypto_helper.test.js +0 -36
  459. package/tests/unit/path_helper.test.js +0 -20
  460. package/tsconfig.base.json +0 -32
  461. /package/{packages/cli/src/index.ts → dist/index.js} +0 -0
@@ -1,956 +0,0 @@
1
- import path from "node:path";
2
- import fs from "node:fs";
3
- import { AgentService } from "@mcoda/agents";
4
- import { DocdexClient, DocdexDocument } from "@mcoda/integrations";
5
- import { GlobalRepository, WorkspaceRepository } from "@mcoda/db";
6
- import { Agent, canonicalizeCommandName, getCommandRequiredCapabilities } from "@mcoda/shared";
7
- import { WorkspaceResolution } from "../../workspace/WorkspaceManager.js";
8
- import { JobService } from "../jobs/JobService.js";
9
- import { TaskSelectionService, TaskSelectionFilters, SelectedTask } from "../execution/TaskSelectionService.js";
10
- import { RoutingService } from "./RoutingService.js";
11
-
12
- const DEFAULT_GATEWAY_PROMPT = [
13
- "You are the gateway agent. Read the task context and docdex snippets, digest the task, decide what is done vs. remaining, and plan the work.",
14
- "You must identify concrete file paths to modify or create before offloading.",
15
- "Do not use placeholders like (unknown), TBD, or glob patterns in file paths.",
16
- "If docdex returns no results, say so in docdexNotes.",
17
- "Do not leave currentState, todo, or understanding blank.",
18
- "Put reasoningSummary near the top of the JSON object so it appears early in the stream.",
19
- "Do not claim to have read files or performed a repo scan unless explicit file content was provided.",
20
- "Do not include fields outside the schema.",
21
- "Return JSON only with the following schema:",
22
- "{",
23
- ' "summary": "1-3 sentence summary of the task and intent",',
24
- ' "reasoningSummary": "1-2 sentence high-level rationale (no chain-of-thought)",',
25
- ' "currentState": "short statement of what is already implemented or known to exist",',
26
- ' "todo": "short statement of what still needs to be done",',
27
- ' "understanding": "short statement of what success looks like",',
28
- ' "plan": ["step 1", "step 2", "step 3"],',
29
- ' "complexity": 1-10,',
30
- ' "discipline": "backend|frontend|uiux|docs|architecture|qa|planning|ops|other",',
31
- ' "filesLikelyTouched": ["path/to/file.ext"],',
32
- ' "filesToCreate": ["path/to/new_file.ext"],',
33
- ' "assumptions": ["assumption 1"],',
34
- ' "risks": ["risk 1"],',
35
- ' "docdexNotes": ["notes about docdex coverage/gaps"]',
36
- "}",
37
- "If information is missing, keep arrays empty and mention the gap in assumptions or docdexNotes.",
38
- ].join("\n");
39
-
40
- const REQUIRED_PROMPT_MARKERS = [
41
- '"summary"',
42
- '"reasoningSummary"',
43
- '"currentState"',
44
- '"todo"',
45
- '"understanding"',
46
- '"filesLikelyTouched"',
47
- '"filesToCreate"',
48
- ];
49
-
50
- const hasRequiredPromptMarkers = (content: string): boolean =>
51
- REQUIRED_PROMPT_MARKERS.every((marker) => content.includes(marker));
52
-
53
- const DEFAULT_JOB_PROMPT =
54
- "You are an mcoda agent that follows workspace runbooks and responds with actionable, concise output.";
55
- const DEFAULT_CHARACTER_PROMPT =
56
- "Write clearly, avoid hallucinations, cite assumptions, and prioritize risk mitigation for the user.";
57
-
58
- const extractJson = (raw: string): any | undefined => {
59
- const fenced = raw.match(/```json([\s\S]*?)```/);
60
- const candidate = fenced ? fenced[1] : raw;
61
- const start = candidate.indexOf("{");
62
- const end = candidate.lastIndexOf("}");
63
- if (start === -1 || end === -1 || end <= start) return undefined;
64
- const body = candidate.slice(start, end + 1);
65
- try {
66
- return JSON.parse(body);
67
- } catch {
68
- return undefined;
69
- }
70
- };
71
-
72
- const estimateTokens = (text: string): number => Math.max(1, Math.ceil((text ?? "").length / 4));
73
-
74
- const clamp = (value: number, min: number, max: number): number => Math.min(max, Math.max(min, value));
75
-
76
- const normalizeList = (value: unknown): string[] => {
77
- if (Array.isArray(value)) return value.map((item) => String(item)).filter(Boolean);
78
- if (typeof value === "string" && value.trim()) return [value.trim()];
79
- return [];
80
- };
81
-
82
- const normalizeTextField = (value: unknown): string | undefined => {
83
- if (typeof value === "string") {
84
- const trimmed = value.trim();
85
- return trimmed ? trimmed : undefined;
86
- }
87
- if (Array.isArray(value)) {
88
- const parts = value.map((item) => String(item).trim()).filter(Boolean);
89
- return parts.length ? parts.join("; ") : undefined;
90
- }
91
- return undefined;
92
- };
93
-
94
- const isPlaceholderPath = (value: string): boolean => {
95
- const lower = value.trim().toLowerCase();
96
- if (!lower) return true;
97
- const hasWord = (word: string) => new RegExp(`\\b${word}\\b`, "i").test(lower);
98
- if (lower.includes("(unknown)") || hasWord("unknown") || hasWord("tbd") || hasWord("todo")) return true;
99
- if (lower.includes("...") || lower.includes("*") || lower.includes("<") || lower.includes(">")) return true;
100
- return false;
101
- };
102
-
103
- const normalizeFileList = (value: unknown): string[] =>
104
- normalizeList(value).map((item) => item.trim()).filter((item) => item.length > 0 && !isPlaceholderPath(item));
105
-
106
- const listMissingFields = (raw: any): string[] => {
107
- const missing: string[] = [];
108
- const summary = normalizeTextField(raw?.summary);
109
- const reasoningSummary = normalizeTextField(raw?.reasoningSummary);
110
- const currentState = normalizeTextField(raw?.currentState);
111
- const todo = normalizeTextField(raw?.todo);
112
- const understanding = normalizeTextField(raw?.understanding);
113
- const plan = normalizeList(raw?.plan);
114
- const filesLikelyTouched = normalizeFileList(raw?.filesLikelyTouched);
115
- const filesToCreate = normalizeFileList(raw?.filesToCreate);
116
- if (!summary) missing.push("summary");
117
- if (!reasoningSummary) missing.push("reasoningSummary");
118
- if (!currentState) missing.push("currentState");
119
- if (!todo) missing.push("todo");
120
- if (!understanding) missing.push("understanding");
121
- if (plan.length === 0) missing.push("plan");
122
- if (filesLikelyTouched.length === 0 && filesToCreate.length === 0) missing.push("files");
123
- return missing;
124
- };
125
-
126
- const normalizeDiscipline = (value: string | undefined): string | undefined => {
127
- if (!value) return undefined;
128
- const normalized = value.trim().toLowerCase();
129
- if (!normalized) return undefined;
130
- const allowed = new Set(["backend", "frontend", "uiux", "docs", "architecture", "qa", "planning", "ops", "other"]);
131
- return allowed.has(normalized) ? normalized : "other";
132
- };
133
-
134
- const inferDiscipline = (job: string, taskTitles: string[], input?: string): string => {
135
- const text = [job, ...taskTitles, input ?? ""].join(" ").toLowerCase();
136
- if (text.includes("sds") || text.includes("pdr") || text.includes("documentation")) return "docs";
137
- if (text.includes("openapi") || text.includes("spec")) return "docs";
138
- if (text.includes("qa") || text.includes("test")) return "qa";
139
- if (text.includes("architecture") || text.includes("design")) return "architecture";
140
- if (text.includes("refine") || text.includes("create-tasks") || text.includes("planning")) return "planning";
141
- if (text.includes("frontend") || text.includes("ui") || text.includes("ux")) return "frontend";
142
- if (text.includes("backend") || text.includes("api") || text.includes("database")) return "backend";
143
- return "other";
144
- };
145
-
146
- const usageKeywords: Record<string, string[]> = {
147
- backend: ["backend", "api", "server", "db", "database"],
148
- frontend: ["frontend", "ui", "ux", "web", "react", "mobile"],
149
- uiux: ["ui", "ux", "design", "prototype"],
150
- docs: ["doc", "documentation", "sds", "pdr", "spec"],
151
- architecture: ["arch", "architecture", "system", "design"],
152
- qa: ["qa", "test", "testing", "quality"],
153
- planning: ["plan", "planning", "product", "pm"],
154
- ops: ["ops", "devops", "infra", "deployment"],
155
- };
156
-
157
- const scoreUsage = (discipline: string, bestUsage?: string, capabilities?: string[]): number => {
158
- if (!discipline) return 0;
159
- const normalized = (bestUsage ?? "").toLowerCase();
160
- const keywords = usageKeywords[discipline] ?? [];
161
- const hasKeyword = keywords.some((k) => normalized.includes(k));
162
- let score = hasKeyword ? 1 : 0;
163
- const caps = new Set((capabilities ?? []).map((c) => c.toLowerCase()));
164
- if (discipline === "docs" && caps.has("docdex_query")) score += 0.5;
165
- if (discipline === "qa" && caps.has("qa_interpretation")) score += 0.5;
166
- if (discipline === "planning" && caps.has("plan")) score += 0.5;
167
- if ((discipline === "backend" || discipline === "frontend") && caps.has("code_write")) score += 0.5;
168
- return score;
169
- };
170
-
171
- const DEFAULT_STATUS_FILTER = [
172
- "not_started",
173
- "in_progress",
174
- "blocked",
175
- "ready_to_review",
176
- "ready_to_qa",
177
- "completed",
178
- "cancelled",
179
- "failed",
180
- "skipped",
181
- ];
182
-
183
- const summarizeDoc = (doc: DocdexDocument, index: number): GatewayDocSummary => {
184
- const title = doc.title ?? doc.path ?? doc.id ?? `doc-${index + 1}`;
185
- const excerptSource = doc.segments?.[0]?.content ?? doc.content ?? "";
186
- const excerpt = excerptSource ? (excerptSource.length > 480 ? `${excerptSource.slice(0, 480)}...` : excerptSource) : undefined;
187
- return {
188
- id: doc.id ?? `doc-${index + 1}`,
189
- docType: doc.docType,
190
- title,
191
- path: doc.path,
192
- excerpt,
193
- };
194
- };
195
-
196
- const buildDocContext = (docs: GatewayDocSummary[]): string => {
197
- if (docs.length === 0) return "Docdex: (no matching documents found)";
198
- return [
199
- "Docdex context:",
200
- ...docs.map((doc) => {
201
- const head = `[${doc.docType}] ${doc.title}`;
202
- const tail = doc.path ? ` (${doc.path})` : "";
203
- const excerpt = doc.excerpt ? `\n Excerpt: ${doc.excerpt}` : "";
204
- return `- ${head}${tail}${excerpt}`;
205
- }),
206
- ].join("\n");
207
- };
208
-
209
- const buildTaskContext = (tasks: GatewayTaskSummary[]): string => {
210
- if (tasks.length === 0) return "Task context: (no task records found)";
211
- const lines: string[] = ["Task context:"];
212
- for (const task of tasks) {
213
- lines.push(
214
- [
215
- `- ${task.key}: ${task.title}`,
216
- task.description ? ` Description: ${task.description}` : undefined,
217
- task.status ? ` Status: ${task.status}` : undefined,
218
- task.storyKey ? ` Story: ${task.storyKey} ${task.storyTitle ?? ""}`.trim() : undefined,
219
- task.epicKey ? ` Epic: ${task.epicKey} ${task.epicTitle ?? ""}`.trim() : undefined,
220
- task.storyPoints !== undefined ? ` Story points: ${task.storyPoints}` : undefined,
221
- task.acceptanceCriteria?.length ? ` Acceptance: ${task.acceptanceCriteria.join(" | ")}` : undefined,
222
- task.dependencies?.length ? ` Dependencies: ${task.dependencies.join(", ")}` : undefined,
223
- ]
224
- .filter(Boolean)
225
- .join("\n"),
226
- );
227
- }
228
- return lines.join("\n");
229
- };
230
-
231
- export interface GatewayDocSummary {
232
- id: string;
233
- docType: string;
234
- title: string;
235
- path?: string;
236
- excerpt?: string;
237
- }
238
-
239
- export interface GatewayTaskSummary {
240
- key: string;
241
- title: string;
242
- description?: string;
243
- status?: string;
244
- storyPoints?: number;
245
- storyKey?: string;
246
- storyTitle?: string;
247
- epicKey?: string;
248
- epicTitle?: string;
249
- acceptanceCriteria?: string[];
250
- dependencies?: string[];
251
- }
252
-
253
- export interface GatewayAnalysis {
254
- summary: string;
255
- reasoningSummary?: string;
256
- currentState: string;
257
- todo: string;
258
- understanding: string;
259
- plan: string[];
260
- complexity: number;
261
- discipline: string;
262
- filesLikelyTouched: string[];
263
- filesToCreate: string[];
264
- assumptions: string[];
265
- risks: string[];
266
- docdexNotes: string[];
267
- }
268
-
269
- export interface GatewayAgentDecision {
270
- agentId: string;
271
- agentSlug: string;
272
- rating?: number;
273
- reasoningRating?: number;
274
- bestUsage?: string;
275
- costPerMillion?: number;
276
- rationale: string;
277
- }
278
-
279
- export interface GatewayAgentResult {
280
- commandRunId: string;
281
- job: string;
282
- gatewayAgent: { id: string; slug: string };
283
- tasks: GatewayTaskSummary[];
284
- docdex: GatewayDocSummary[];
285
- analysis: GatewayAnalysis;
286
- chosenAgent: GatewayAgentDecision;
287
- warnings: string[];
288
- }
289
-
290
- export interface GatewayAgentRequest extends TaskSelectionFilters {
291
- workspace: WorkspaceResolution;
292
- job: string;
293
- inputText?: string;
294
- gatewayAgentName?: string;
295
- maxDocs?: number;
296
- agentStream?: boolean;
297
- onStreamChunk?: (chunk: string) => void;
298
- }
299
-
300
- type Candidate = {
301
- agent: Agent;
302
- capabilities: string[];
303
- health?: { status?: string };
304
- quality: number;
305
- reasoning: number;
306
- usageScore: number;
307
- cost: number;
308
- };
309
-
310
- export class GatewayAgentService {
311
- private taskSelectionService: TaskSelectionService;
312
-
313
- private constructor(
314
- private workspace: WorkspaceResolution,
315
- private deps: {
316
- agentService: AgentService;
317
- docdex: DocdexClient;
318
- globalRepo: GlobalRepository;
319
- jobService: JobService;
320
- workspaceRepo: WorkspaceRepository;
321
- routingService: RoutingService;
322
- },
323
- ) {
324
- this.taskSelectionService = new TaskSelectionService(workspace, deps.workspaceRepo);
325
- }
326
-
327
- static async create(workspace: WorkspaceResolution): Promise<GatewayAgentService> {
328
- const globalRepo = await GlobalRepository.create();
329
- const agentService = new AgentService(globalRepo);
330
- const routingService = await RoutingService.create();
331
- const docdex = new DocdexClient({
332
- workspaceRoot: workspace.workspaceRoot,
333
- baseUrl: workspace.config?.docdexUrl ?? process.env.MCODA_DOCDEX_URL,
334
- });
335
- const workspaceRepo = await WorkspaceRepository.create(workspace.workspaceRoot);
336
- const jobService = new JobService(workspace, workspaceRepo);
337
- return new GatewayAgentService(workspace, {
338
- agentService,
339
- docdex,
340
- globalRepo,
341
- jobService,
342
- workspaceRepo,
343
- routingService,
344
- });
345
- }
346
-
347
- private async readPromptFiles(paths: string[]): Promise<string[]> {
348
- const contents: string[] = [];
349
- const seen = new Set<string>();
350
- for (const promptPath of paths) {
351
- try {
352
- const content = await fs.promises.readFile(promptPath, "utf8");
353
- const trimmed = content.trim();
354
- if (trimmed && !seen.has(trimmed)) {
355
- contents.push(trimmed);
356
- seen.add(trimmed);
357
- }
358
- } catch {
359
- /* optional prompt */
360
- }
361
- }
362
- return contents;
363
- }
364
-
365
- async close(): Promise<void> {
366
- const maybeClose = async (target: unknown) => {
367
- try {
368
- if ((target as any)?.close) await (target as any).close();
369
- } catch {
370
- /* ignore */
371
- }
372
- };
373
- await maybeClose(this.taskSelectionService);
374
- await maybeClose(this.deps.agentService);
375
- await maybeClose(this.deps.docdex);
376
- await maybeClose(this.deps.globalRepo);
377
- await maybeClose(this.deps.jobService);
378
- await maybeClose(this.deps.workspaceRepo);
379
- await maybeClose(this.deps.routingService);
380
- }
381
-
382
- private async loadGatewayPrompts(agentId: string): Promise<{ jobPrompt: string; characterPrompt: string; commandPrompt: string }> {
383
- const agentPrompts =
384
- "getPrompts" in this.deps.agentService ? await (this.deps.agentService as any).getPrompts(agentId) : undefined;
385
- const mcodaPromptPath = path.join(this.workspace.workspaceRoot, ".mcoda", "prompts", "gateway-agent.md");
386
- const workspacePromptPath = path.join(this.workspace.workspaceRoot, "prompts", "gateway-agent.md");
387
- try {
388
- await fs.promises.mkdir(path.dirname(mcodaPromptPath), { recursive: true });
389
- await fs.promises.access(mcodaPromptPath);
390
- } catch {
391
- try {
392
- await fs.promises.access(workspacePromptPath);
393
- await fs.promises.copyFile(workspacePromptPath, mcodaPromptPath);
394
- } catch {
395
- await fs.promises.writeFile(mcodaPromptPath, DEFAULT_GATEWAY_PROMPT, "utf8");
396
- }
397
- }
398
- try {
399
- const existing = await fs.promises.readFile(mcodaPromptPath, "utf8");
400
- if (!hasRequiredPromptMarkers(existing)) {
401
- let nextPrompt = DEFAULT_GATEWAY_PROMPT;
402
- try {
403
- const workspacePrompt = await fs.promises.readFile(workspacePromptPath, "utf8");
404
- if (hasRequiredPromptMarkers(workspacePrompt)) {
405
- nextPrompt = workspacePrompt.trim();
406
- }
407
- } catch {
408
- /* ignore */
409
- }
410
- await fs.promises.writeFile(mcodaPromptPath, nextPrompt, "utf8");
411
- }
412
- } catch {
413
- /* ignore */
414
- }
415
- const commandPromptFiles = (await this.readPromptFiles([mcodaPromptPath, workspacePromptPath])).filter(
416
- hasRequiredPromptMarkers,
417
- );
418
- const mergedCommandPrompt = (() => {
419
- const parts = [...commandPromptFiles];
420
- const agentCommandPrompt = agentPrompts?.commandPrompts?.["gateway-agent"];
421
- if (agentCommandPrompt && hasRequiredPromptMarkers(agentCommandPrompt)) {
422
- parts.push(agentCommandPrompt);
423
- }
424
- if (!parts.length) parts.push(DEFAULT_GATEWAY_PROMPT);
425
- return parts.filter(Boolean).join("\n\n");
426
- })();
427
- return {
428
- jobPrompt: agentPrompts?.jobPrompt ?? DEFAULT_JOB_PROMPT,
429
- characterPrompt: agentPrompts?.characterPrompt ?? DEFAULT_CHARACTER_PROMPT,
430
- commandPrompt: mergedCommandPrompt,
431
- };
432
- }
433
-
434
- private async resolveGatewayAgent(override?: string, warnings: string[] = []): Promise<Agent> {
435
- try {
436
- const resolved = await this.deps.routingService.resolveAgentForCommand({
437
- workspace: this.workspace,
438
- commandName: "gateway-agent",
439
- overrideAgentSlug: override,
440
- });
441
- return resolved.agent;
442
- } catch (error) {
443
- warnings.push(`Routing defaults unavailable for gateway-agent; using best available agent (${(error as Error).message})`);
444
- const requiredCaps = getCommandRequiredCapabilities("gateway-agent");
445
- if (override) {
446
- try {
447
- const overrideAgent = await this.deps.agentService.resolveAgent(override);
448
- const caps = await this.deps.globalRepo.getAgentCapabilities(overrideAgent.id);
449
- const missing = requiredCaps.filter((cap) => !caps.includes(cap));
450
- const health = await this.deps.globalRepo.getAgentHealth(overrideAgent.id);
451
- if (missing.length === 0 && health?.status !== "unreachable") {
452
- return overrideAgent;
453
- }
454
- if (missing.length) {
455
- warnings.push(
456
- `Override agent ${overrideAgent.slug} is missing gateway capabilities (${missing.join(", ")}); ignoring override.`,
457
- );
458
- } else if (health?.status === "unreachable") {
459
- warnings.push(`Override agent ${overrideAgent.slug} is unreachable; ignoring override.`);
460
- }
461
- } catch (overrideError) {
462
- warnings.push(`Override agent ${override} could not be resolved (${(overrideError as Error).message}); ignoring override.`);
463
- }
464
- }
465
- const candidates = await this.listCandidates(requiredCaps, "planning");
466
- if (!candidates.length) {
467
- throw new Error("No eligible gateway agents available; add a plan/docdex_query-capable agent");
468
- }
469
- const sorted = candidates
470
- .slice()
471
- .sort((a, b) => {
472
- const qa = b.reasoning || b.quality;
473
- const qb = a.reasoning || a.quality;
474
- if (qa !== qb) return qa - qb;
475
- if (b.quality !== a.quality) return b.quality - a.quality;
476
- return a.cost - b.cost;
477
- });
478
- return sorted[0].agent;
479
- }
480
- }
481
-
482
- private async invokeGatewayAgent(
483
- agent: Agent,
484
- prompt: string,
485
- job: string,
486
- options?: { stream?: boolean; onChunk?: (chunk: string) => void },
487
- ): Promise<{ output: string; durationSeconds: number }> {
488
- const startedAt = Date.now();
489
- const stream = options?.stream !== false;
490
- const onChunk = options?.onChunk;
491
- try {
492
- if (stream) {
493
- const generator = await this.deps.agentService.invokeStream(agent.id, {
494
- input: prompt,
495
- metadata: { command: "gateway-agent", job },
496
- });
497
- let output = "";
498
- for await (const chunk of generator) {
499
- const text = chunk.output ?? "";
500
- output += text;
501
- if (text && onChunk) onChunk(text);
502
- }
503
- return { output, durationSeconds: (Date.now() - startedAt) / 1000 };
504
- }
505
- } catch (error) {
506
- const message = (error as Error).message ?? "";
507
- if (!/does not support streaming/i.test(message)) {
508
- throw error;
509
- }
510
- }
511
- const response = await this.deps.agentService.invoke(agent.id, {
512
- input: prompt,
513
- metadata: { command: "gateway-agent", job },
514
- });
515
- const output = response.output ?? "";
516
- if (output && onChunk) onChunk(output);
517
- return { output, durationSeconds: (Date.now() - startedAt) / 1000 };
518
- }
519
-
520
- private async buildTasksSummary(request: GatewayAgentRequest, warnings: string[]): Promise<GatewayTaskSummary[]> {
521
- const hasFilters =
522
- Boolean(request.projectKey) ||
523
- Boolean(request.epicKey) ||
524
- Boolean(request.storyKey) ||
525
- Boolean(request.taskKeys?.length);
526
- if (!hasFilters) return [];
527
- const limit = request.taskKeys?.length ? request.taskKeys.length : request.limit ?? 8;
528
- try {
529
- const filters: TaskSelectionFilters = {
530
- projectKey: request.projectKey,
531
- epicKey: request.epicKey,
532
- storyKey: request.storyKey,
533
- taskKeys: request.taskKeys,
534
- statusFilter: request.statusFilter?.length ? request.statusFilter : DEFAULT_STATUS_FILTER,
535
- limit,
536
- };
537
- const selection = await this.taskSelectionService.selectTasks(filters);
538
- if (selection.warnings.length) warnings.push(...selection.warnings);
539
- const combined: SelectedTask[] = [...selection.ordered, ...selection.blocked];
540
- return combined.slice(0, limit).map((entry) => ({
541
- key: entry.task.key,
542
- title: entry.task.title,
543
- description: entry.task.description ?? undefined,
544
- status: entry.task.status,
545
- storyPoints: entry.task.storyPoints ?? undefined,
546
- storyKey: entry.task.storyKey,
547
- storyTitle: entry.task.storyTitle,
548
- epicKey: entry.task.epicKey,
549
- epicTitle: entry.task.epicTitle,
550
- acceptanceCriteria: entry.task.acceptanceCriteria,
551
- dependencies: entry.dependencies.keys,
552
- }));
553
- } catch (error) {
554
- warnings.push(`Task lookup failed: ${(error as Error).message}`);
555
- return [];
556
- }
557
- }
558
-
559
- private pickDocTypes(job: string, input?: string): string[] {
560
- const types = new Set<string>();
561
- const lower = `${job} ${input ?? ""}`.toLowerCase();
562
- if (lower.includes("sds")) types.add("SDS");
563
- if (lower.includes("pdr")) types.add("PDR");
564
- if (lower.includes("rfp")) types.add("RFP");
565
- if (lower.includes("openapi")) types.add("OPENAPI");
566
- if (lower.includes("doc")) {
567
- types.add("SDS");
568
- types.add("PDR");
569
- }
570
- if (types.size === 0) {
571
- types.add("SDS");
572
- types.add("PDR");
573
- types.add("OPENAPI");
574
- }
575
- return Array.from(types);
576
- }
577
-
578
- private buildQuerySeed(tasks: GatewayTaskSummary[], input?: string): string {
579
- const seeds: string[] = [];
580
- tasks.forEach((task) => {
581
- seeds.push(task.key, task.title);
582
- if (task.storyTitle) seeds.push(task.storyTitle);
583
- if (task.epicTitle) seeds.push(task.epicTitle);
584
- });
585
- if (input) {
586
- seeds.push(...input.split(/\s+/).slice(0, 12));
587
- }
588
- return Array.from(new Set(seeds.map((s) => s.trim()).filter(Boolean))).slice(0, 10).join(" ");
589
- }
590
-
591
- private async buildDocSummaries(
592
- request: GatewayAgentRequest,
593
- tasks: GatewayTaskSummary[],
594
- warnings: string[],
595
- ): Promise<GatewayDocSummary[]> {
596
- const maxDocs = request.maxDocs ?? 4;
597
- if (maxDocs <= 0) return [];
598
- const docTypes = this.pickDocTypes(request.job, request.inputText);
599
- const query = this.buildQuerySeed(tasks, request.inputText);
600
- const summaries: GatewayDocSummary[] = [];
601
- for (const docType of docTypes) {
602
- if (summaries.length >= maxDocs) break;
603
- try {
604
- const docs = await this.deps.docdex.search({
605
- projectKey: request.projectKey,
606
- docType,
607
- query,
608
- });
609
- for (const doc of docs) {
610
- if (summaries.length >= maxDocs) break;
611
- summaries.push(summarizeDoc(doc, summaries.length));
612
- }
613
- } catch (error) {
614
- warnings.push(`Docdex search failed (${docType}): ${(error as Error).message}`);
615
- }
616
- }
617
- return summaries;
618
- }
619
-
620
- private buildGatewayPrompt(
621
- job: string,
622
- tasks: GatewayTaskSummary[],
623
- docs: GatewayDocSummary[],
624
- inputText?: string,
625
- ): string {
626
- const taskContext = buildTaskContext(tasks);
627
- const docContext = buildDocContext(docs);
628
- const inputBlock = inputText ? `Additional input:\n${inputText}` : "Additional input: (none)";
629
- return [`Job: ${job}`, taskContext, inputBlock, docContext].join("\n\n");
630
- }
631
-
632
- private normalizeAnalysis(raw: any, job: string, tasks: GatewayTaskSummary[], inputText?: string): GatewayAnalysis {
633
- const summary = normalizeTextField(raw?.summary);
634
- const currentState = normalizeTextField(raw?.currentState);
635
- const todo = normalizeTextField(raw?.todo);
636
- const reasoningSummary = normalizeTextField(raw?.reasoningSummary) ?? "";
637
- const understanding = normalizeTextField(raw?.understanding) ?? "";
638
- const plan = normalizeList(raw?.plan);
639
- const filesLikelyTouched = normalizeFileList(raw?.filesLikelyTouched);
640
- const filesToCreate = normalizeFileList(raw?.filesToCreate);
641
- const complexityRaw = Number(raw?.complexity);
642
- const complexity = Number.isFinite(complexityRaw) ? clamp(Math.round(complexityRaw), 1, 10) : 5;
643
- const discipline =
644
- normalizeDiscipline(typeof raw?.discipline === "string" ? raw.discipline : undefined) ??
645
- inferDiscipline(job, tasks.map((t) => t.title), inputText);
646
- const fallbackSummary =
647
- summary ??
648
- (tasks.length
649
- ? `Handle ${tasks.length} task${tasks.length > 1 ? "s" : ""}: ${tasks.map((t) => t.key).join(", ")}.`
650
- : inputText?.slice(0, 200) ?? "Summarize the requested job.");
651
- const fallbackState = currentState
652
- ? currentState
653
- : tasks.length
654
- ? tasks.map((t) => `${t.key} is ${t.status ?? "unknown"} (${t.title})`).join("; ")
655
- : "Current state unknown; requires investigation.";
656
- const fallbackTodo = todo
657
- ? todo
658
- : tasks.length
659
- ? tasks.map((t) => t.title).join("; ")
660
- : "Determine remaining work based on provided input and docs.";
661
- return {
662
- summary: fallbackSummary,
663
- reasoningSummary,
664
- currentState: fallbackState,
665
- todo: fallbackTodo,
666
- understanding,
667
- plan: plan.length ? plan : ["Review requirements and docs", "Execute the job", "Verify outcomes"],
668
- complexity,
669
- discipline,
670
- filesLikelyTouched,
671
- filesToCreate,
672
- assumptions: normalizeList(raw?.assumptions),
673
- risks: normalizeList(raw?.risks),
674
- docdexNotes: normalizeList(raw?.docdexNotes),
675
- };
676
- }
677
-
678
- private async validateFilePlan(analysis: GatewayAnalysis, warnings: string[]): Promise<GatewayAnalysis> {
679
- const root = this.workspace.workspaceRoot;
680
- const normalize = (file: string): { relative: string; resolved: string } => {
681
- const resolved = path.resolve(root, file);
682
- const relative = path.relative(root, resolved);
683
- return { relative, resolved };
684
- };
685
- const isInside = (relative: string): boolean => !relative.startsWith("..") && !path.isAbsolute(relative);
686
- const touched: string[] = [];
687
- const created: string[] = [];
688
- for (const file of analysis.filesLikelyTouched) {
689
- const { relative, resolved } = normalize(file);
690
- if (!isInside(relative)) {
691
- warnings.push(`Gateway file path outside workspace ignored: ${file}`);
692
- continue;
693
- }
694
- try {
695
- const stat = await fs.promises.stat(resolved);
696
- if (stat.isFile()) {
697
- touched.push(relative.replace(/\\/g, "/"));
698
- } else {
699
- warnings.push(`Gateway file path is not a file: ${file}`);
700
- }
701
- } catch {
702
- warnings.push(`Gateway file path does not exist: ${file}`);
703
- }
704
- }
705
- for (const file of analysis.filesToCreate) {
706
- const { relative, resolved } = normalize(file);
707
- if (!isInside(relative)) {
708
- warnings.push(`Gateway create path outside workspace ignored: ${file}`);
709
- continue;
710
- }
711
- const parent = path.dirname(resolved);
712
- try {
713
- const stat = await fs.promises.stat(parent);
714
- if (!stat.isDirectory()) {
715
- warnings.push(`Gateway create path parent is not a directory: ${file}`);
716
- continue;
717
- }
718
- } catch {
719
- warnings.push(`Gateway create path parent does not exist: ${file}`);
720
- continue;
721
- }
722
- try {
723
- const stat = await fs.promises.stat(resolved);
724
- if (stat.isFile()) {
725
- warnings.push(`Gateway create path already exists; treating as touch: ${file}`);
726
- touched.push(relative.replace(/\\/g, "/"));
727
- continue;
728
- }
729
- } catch {
730
- /* file does not exist; ok */
731
- }
732
- created.push(relative.replace(/\\/g, "/"));
733
- }
734
- return {
735
- ...analysis,
736
- filesLikelyTouched: touched,
737
- filesToCreate: created,
738
- };
739
- }
740
-
741
- private async listCandidates(requiredCaps: string[], discipline: string): Promise<Candidate[]> {
742
- const agents = await this.deps.globalRepo.listAgents();
743
- if (agents.length === 0) {
744
- throw new Error("No agents available; register one with mcoda agent add");
745
- }
746
- const health = await this.deps.globalRepo.listAgentHealthSummary();
747
- const healthById = new Map(health.map((row) => [row.agentId, row]));
748
- const candidates: Candidate[] = [];
749
- for (const agent of agents) {
750
- const capabilities = await this.deps.globalRepo.getAgentCapabilities(agent.id);
751
- const missing = requiredCaps.filter((cap) => !capabilities.includes(cap));
752
- if (missing.length) continue;
753
- const healthEntry = healthById.get(agent.id);
754
- if (healthEntry?.status === "unreachable") continue;
755
- const rating = agent.rating ?? 0;
756
- const reasoning = agent.reasoningRating ?? rating;
757
- const quality =
758
- discipline === "architecture" || discipline === "planning"
759
- ? reasoning || rating || 5
760
- : rating || reasoning || 5;
761
- const usageScore = scoreUsage(discipline, agent.bestUsage, capabilities);
762
- const cost = agent.costPerMillion ?? Number.POSITIVE_INFINITY;
763
- const adjustedQuality = healthEntry?.status === "degraded" ? quality - 0.5 : quality;
764
- candidates.push({
765
- agent,
766
- capabilities,
767
- health: healthEntry,
768
- quality: adjustedQuality,
769
- reasoning,
770
- usageScore,
771
- cost,
772
- });
773
- }
774
- return candidates;
775
- }
776
-
777
- private chooseCandidate(candidates: Candidate[], complexity: number, discipline: string): { pick: Candidate; rationale: string } {
778
- if (candidates.length === 0) {
779
- throw new Error("No eligible agents available for this job");
780
- }
781
- const sortedQuality = candidates.map((c) => c.quality);
782
- const maxQuality = Math.max(...sortedQuality);
783
- if (complexity >= 9) {
784
- const pick = candidates
785
- .slice()
786
- .sort((a, b) => {
787
- if (b.quality !== a.quality) return b.quality - a.quality;
788
- if (b.usageScore !== a.usageScore) return b.usageScore - a.usageScore;
789
- if (b.reasoning !== a.reasoning) return b.reasoning - a.reasoning;
790
- return a.cost - b.cost;
791
- })[0];
792
- return {
793
- pick,
794
- rationale: `Complexity ${complexity}/10 requires the highest capability; selected top-rated agent with best fit for ${discipline}.`,
795
- };
796
- }
797
- if (complexity >= 8) {
798
- const pool = candidates.filter((c) => c.quality >= maxQuality - 1);
799
- const pick = (pool.length ? pool : candidates)
800
- .slice()
801
- .sort((a, b) => {
802
- if (b.usageScore !== a.usageScore) return b.usageScore - a.usageScore;
803
- if (a.cost !== b.cost) return a.cost - b.cost;
804
- return b.quality - a.quality;
805
- })[0];
806
- return {
807
- pick,
808
- rationale: `Complexity ${complexity}/10 favors strong agents with good cost/fit balance; selected best-fit candidate.`,
809
- };
810
- }
811
- const target = complexity;
812
- const pool = candidates.filter((c) => c.quality >= target);
813
- const base = pool.length ? pool : candidates;
814
- const pick = base
815
- .slice()
816
- .sort((a, b) => {
817
- const diffA = Math.abs(a.quality - target);
818
- const diffB = Math.abs(b.quality - target);
819
- if (diffA !== diffB) return diffA - diffB;
820
- if (b.usageScore !== a.usageScore) return b.usageScore - a.usageScore;
821
- if (a.cost !== b.cost) return a.cost - b.cost;
822
- return a.quality - b.quality;
823
- })[0];
824
- return {
825
- pick,
826
- rationale: `Complexity ${complexity}/10 targets a comparable tier agent; selected closest match with discipline fit and cost awareness.`,
827
- };
828
- }
829
-
830
- private async selectAgentForJob(job: string, analysis: GatewayAnalysis): Promise<GatewayAgentDecision> {
831
- const normalizedJob = canonicalizeCommandName(job);
832
- const requiredCaps = getCommandRequiredCapabilities(normalizedJob);
833
- const candidates = await this.listCandidates(requiredCaps, analysis.discipline);
834
- const { pick, rationale } = this.chooseCandidate(candidates, analysis.complexity, analysis.discipline);
835
- return {
836
- agentId: pick.agent.id,
837
- agentSlug: pick.agent.slug ?? pick.agent.id,
838
- rating: pick.agent.rating ?? undefined,
839
- reasoningRating: pick.agent.reasoningRating ?? undefined,
840
- bestUsage: pick.agent.bestUsage ?? undefined,
841
- costPerMillion: Number.isFinite(pick.cost) ? pick.cost : undefined,
842
- rationale,
843
- };
844
- }
845
-
846
- async run(request: GatewayAgentRequest): Promise<GatewayAgentResult> {
847
- const warnings: string[] = [];
848
- const normalizedJob = canonicalizeCommandName(request.job);
849
- const commandRun = await this.deps.jobService.startCommandRun("gateway-agent", request.projectKey);
850
- try {
851
- const tasks = await this.buildTasksSummary(request, warnings);
852
- const docs = await this.buildDocSummaries(request, tasks, warnings);
853
- const gatewayAgent = await this.resolveGatewayAgent(request.gatewayAgentName, warnings);
854
- const prompts = await this.loadGatewayPrompts(gatewayAgent.id);
855
- const prompt = [
856
- prompts.jobPrompt,
857
- prompts.characterPrompt,
858
- prompts.commandPrompt,
859
- this.buildGatewayPrompt(normalizedJob, tasks, docs, request.inputText),
860
- ]
861
- .filter(Boolean)
862
- .join("\n\n");
863
- const recordUsage = async (promptText: string, outputText: string, durationSeconds: number, action: string) => {
864
- const promptTokens = estimateTokens(promptText);
865
- const completionTokens = estimateTokens(outputText ?? "");
866
- await this.deps.jobService.recordTokenUsage({
867
- timestamp: new Date().toISOString(),
868
- workspaceId: this.workspace.workspaceId,
869
- commandName: "gateway-agent",
870
- commandRunId: commandRun.id,
871
- agentId: gatewayAgent.id,
872
- modelName: gatewayAgent.defaultModel,
873
- promptTokens,
874
- completionTokens,
875
- tokensPrompt: promptTokens,
876
- tokensCompletion: completionTokens,
877
- tokensTotal: promptTokens + completionTokens,
878
- durationSeconds,
879
- metadata: { action, job: normalizedJob },
880
- });
881
- };
882
-
883
- const response = await this.invokeGatewayAgent(gatewayAgent, prompt, normalizedJob, {
884
- stream: request.agentStream !== false,
885
- onChunk: request.onStreamChunk,
886
- });
887
- await recordUsage(prompt, response.output ?? "", response.durationSeconds, "gateway_summary");
888
-
889
- let parsed = extractJson(response.output);
890
- let missingFields = parsed
891
- ? listMissingFields(parsed)
892
- : ["summary", "reasoningSummary", "currentState", "todo", "understanding", "plan", "files"];
893
- if (!parsed) {
894
- warnings.push("Gateway analysis response was not valid JSON; falling back to defaults.");
895
- }
896
-
897
- if (missingFields.length) {
898
- const repairPrompt = [
899
- prompt,
900
- "",
901
- "Your previous response was incomplete or invalid. Return JSON only with the exact schema.",
902
- `Missing fields: ${missingFields.join(", ")}.`,
903
- "Ensure reasoningSummary, currentState, todo, understanding, plan, and filesLikelyTouched/filesToCreate are populated.",
904
- "Use real file paths only (no placeholders like (unknown), TBD, or glob patterns).",
905
- "If docdex returned no results, say so in docdexNotes.",
906
- ].join("\n");
907
- if (request.onStreamChunk) {
908
- request.onStreamChunk("\n[gateway-agent] Retrying for missing fields...\n");
909
- }
910
- const repairResponse = await this.invokeGatewayAgent(gatewayAgent, repairPrompt, normalizedJob, {
911
- stream: request.agentStream !== false,
912
- onChunk: request.onStreamChunk,
913
- });
914
- await recordUsage(repairPrompt, repairResponse.output ?? "", repairResponse.durationSeconds, "gateway_summary_repair");
915
- const repaired = extractJson(repairResponse.output);
916
- if (repaired) {
917
- parsed = repaired;
918
- missingFields = listMissingFields(parsed);
919
- } else {
920
- warnings.push("Gateway repair response was not valid JSON; using fallback analysis.");
921
- }
922
- }
923
-
924
- if (missingFields.length) {
925
- warnings.push(`Gateway analysis missing fields: ${missingFields.join(", ")}.`);
926
- }
927
-
928
- let analysis = this.normalizeAnalysis(parsed ?? {}, normalizedJob, tasks, request.inputText);
929
- if (analysis.docdexNotes.length === 0) {
930
- if (docs.length === 0) {
931
- analysis.docdexNotes.push("Docdex: no matching documents found.");
932
- } else {
933
- warnings.push("Gateway analysis missing docdexNotes for retrieved docdex context.");
934
- }
935
- const docdexWarnings = warnings.filter((w) => w.toLowerCase().includes("docdex"));
936
- analysis.docdexNotes.push(...docdexWarnings);
937
- }
938
- analysis = await this.validateFilePlan(analysis, warnings);
939
- const chosenAgent = await this.selectAgentForJob(normalizedJob, analysis);
940
- await this.deps.jobService.finishCommandRun(commandRun.id, "succeeded");
941
- return {
942
- commandRunId: commandRun.id,
943
- job: normalizedJob,
944
- gatewayAgent: { id: gatewayAgent.id, slug: gatewayAgent.slug ?? gatewayAgent.id },
945
- tasks,
946
- docdex: docs,
947
- analysis,
948
- chosenAgent,
949
- warnings,
950
- };
951
- } catch (error) {
952
- await this.deps.jobService.finishCommandRun(commandRun.id, "failed", (error as Error).message);
953
- throw error;
954
- }
955
- }
956
- }