sofia-cli 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (435) hide show
  1. package/.github/agents/copilot-instructions.md +39 -0
  2. package/.github/agents/speckit.analyze.agent.md +184 -0
  3. package/.github/agents/speckit.checklist.agent.md +294 -0
  4. package/.github/agents/speckit.clarify.agent.md +181 -0
  5. package/.github/agents/speckit.constitution.agent.md +84 -0
  6. package/.github/agents/speckit.implement.agent.md +135 -0
  7. package/.github/agents/speckit.plan.agent.md +90 -0
  8. package/.github/agents/speckit.specify.agent.md +258 -0
  9. package/.github/agents/speckit.tasks.agent.md +137 -0
  10. package/.github/agents/speckit.taskstoissues.agent.md +30 -0
  11. package/.github/copilot-instructions.md +257 -0
  12. package/.github/prompts/speckit.analyze.prompt.md +3 -0
  13. package/.github/prompts/speckit.checklist.prompt.md +3 -0
  14. package/.github/prompts/speckit.clarify.prompt.md +3 -0
  15. package/.github/prompts/speckit.constitution.prompt.md +3 -0
  16. package/.github/prompts/speckit.implement.prompt.md +3 -0
  17. package/.github/prompts/speckit.plan.prompt.md +3 -0
  18. package/.github/prompts/speckit.specify.prompt.md +3 -0
  19. package/.github/prompts/speckit.tasks.prompt.md +3 -0
  20. package/.github/prompts/speckit.taskstoissues.prompt.md +3 -0
  21. package/.github/workflows/ci.yml +38 -0
  22. package/.prettierrc +6 -0
  23. package/.specify/memory/constitution.md +181 -0
  24. package/.specify/scripts/bash/check-prerequisites.sh +166 -0
  25. package/.specify/scripts/bash/common.sh +156 -0
  26. package/.specify/scripts/bash/create-new-feature.sh +297 -0
  27. package/.specify/scripts/bash/setup-plan.sh +61 -0
  28. package/.specify/scripts/bash/update-agent-context.sh +810 -0
  29. package/.specify/templates/agent-file-template.md +28 -0
  30. package/.specify/templates/checklist-template.md +40 -0
  31. package/.specify/templates/constitution-template.md +50 -0
  32. package/.specify/templates/plan-template.md +113 -0
  33. package/.specify/templates/spec-template.md +115 -0
  34. package/.specify/templates/tasks-template.md +251 -0
  35. package/.vscode/mcp.json +42 -0
  36. package/.vscode/settings.json +19 -0
  37. package/CODE_OF_CONDUCT.md +128 -0
  38. package/LICENSE +21 -0
  39. package/README.md +213 -0
  40. package/dist/src/cli/developCommand.js +240 -0
  41. package/dist/src/cli/directCommands.js +143 -0
  42. package/dist/src/cli/envLoader.js +16 -0
  43. package/dist/src/cli/exportCommand.js +53 -0
  44. package/dist/src/cli/index.js +203 -0
  45. package/dist/src/cli/ioContext.js +109 -0
  46. package/dist/src/cli/preflight.js +57 -0
  47. package/dist/src/cli/statusCommand.js +110 -0
  48. package/dist/src/cli/workshopCommand.js +400 -0
  49. package/dist/src/develop/checkpointState.js +86 -0
  50. package/dist/src/develop/codeGenerator.js +319 -0
  51. package/dist/src/develop/dynamicScaffolder.js +226 -0
  52. package/dist/src/develop/githubMcpAdapter.js +122 -0
  53. package/dist/src/develop/index.js +15 -0
  54. package/dist/src/develop/mcpContextEnricher.js +195 -0
  55. package/dist/src/develop/pocScaffolder.js +542 -0
  56. package/dist/src/develop/ralphLoop.js +659 -0
  57. package/dist/src/develop/templateRegistry.js +364 -0
  58. package/dist/src/develop/testRunner.js +202 -0
  59. package/dist/src/logging/logger.js +58 -0
  60. package/dist/src/loop/conversationLoop.js +227 -0
  61. package/dist/src/loop/phaseSummarizer.js +87 -0
  62. package/dist/src/mcp/mcpManager.js +267 -0
  63. package/dist/src/mcp/mcpTransport.js +391 -0
  64. package/dist/src/mcp/retryPolicy.js +47 -0
  65. package/dist/src/mcp/webSearch.js +254 -0
  66. package/dist/src/phases/contextSummarizer.js +101 -0
  67. package/dist/src/phases/discoveryEnricher.js +156 -0
  68. package/dist/src/phases/phaseExtractors.js +222 -0
  69. package/dist/src/phases/phaseHandlers.js +328 -0
  70. package/dist/src/prompts/design.md +51 -0
  71. package/dist/src/prompts/develop-boundary.md +51 -0
  72. package/dist/src/prompts/develop.md +111 -0
  73. package/dist/src/prompts/discover.md +58 -0
  74. package/dist/src/prompts/ideate.md +56 -0
  75. package/dist/src/prompts/plan.md +51 -0
  76. package/dist/src/prompts/promptLoader.js +167 -0
  77. package/dist/src/prompts/promptLoader.ts +198 -0
  78. package/dist/src/prompts/select.md +47 -0
  79. package/dist/src/prompts/summarize/README.md +8 -0
  80. package/dist/src/prompts/summarize/design-summary.md +37 -0
  81. package/dist/src/prompts/summarize/develop-summary.md +25 -0
  82. package/dist/src/prompts/summarize/ideate-summary.md +27 -0
  83. package/dist/src/prompts/summarize/plan-summary.md +27 -0
  84. package/dist/src/prompts/summarize/select-summary.md +21 -0
  85. package/dist/src/prompts/system.md +28 -0
  86. package/dist/src/sessions/exportPaths.js +22 -0
  87. package/dist/src/sessions/exportWriter.js +406 -0
  88. package/dist/src/sessions/sessionManager.js +81 -0
  89. package/dist/src/sessions/sessionStore.js +65 -0
  90. package/dist/src/shared/activitySpinner.js +91 -0
  91. package/dist/src/shared/copilotClient.js +129 -0
  92. package/dist/src/shared/data/cards.json +1249 -0
  93. package/dist/src/shared/data/cardsLoader.js +51 -0
  94. package/dist/src/shared/errorClassifier.js +120 -0
  95. package/dist/src/shared/events.js +28 -0
  96. package/dist/src/shared/markdownRenderer.js +34 -0
  97. package/dist/src/shared/schemas/session.js +265 -0
  98. package/dist/src/shared/tableRenderer.js +20 -0
  99. package/dist/src/vendor/chalk.js +2 -0
  100. package/dist/src/vendor/cli-table3.js +3 -0
  101. package/dist/src/vendor/commander.js +2 -0
  102. package/dist/src/vendor/marked-terminal.js +3 -0
  103. package/dist/src/vendor/marked.js +2 -0
  104. package/dist/src/vendor/ora.js +2 -0
  105. package/dist/src/vendor/pino.js +2 -0
  106. package/dist/src/vendor/zod.js +2 -0
  107. package/dist/tests/e2e/developE2e.spec.js +126 -0
  108. package/dist/tests/e2e/developFailureE2e.spec.js +247 -0
  109. package/dist/tests/e2e/developPty.spec.js +75 -0
  110. package/dist/tests/e2e/discoveryWebSearchRelevance.spec.js +84 -0
  111. package/dist/tests/e2e/harness.spec.js +83 -0
  112. package/dist/tests/e2e/mcpLive.spec.js +120 -0
  113. package/dist/tests/e2e/newSession.e2e.spec.js +177 -0
  114. package/dist/tests/e2e/ralphLoopEnrichmentComparison.spec.js +62 -0
  115. package/dist/tests/e2e/workiqEnrichment.spec.js +56 -0
  116. package/dist/tests/e2e/zavaSimulation.spec.js +452 -0
  117. package/dist/tests/fixtures/test-fixture-project/src/add.js +3 -0
  118. package/dist/tests/fixtures/test-fixture-project/tests/failing.test.js +6 -0
  119. package/dist/tests/fixtures/test-fixture-project/tests/hanging.test.js +8 -0
  120. package/dist/tests/fixtures/test-fixture-project/tests/passing.test.js +10 -0
  121. package/dist/tests/fixtures/test-fixture-project/vitest.config.js +6 -0
  122. package/dist/tests/integration/autoStartConversation.spec.js +138 -0
  123. package/dist/tests/integration/defaultCommand.spec.js +147 -0
  124. package/dist/tests/integration/directCommandNonTty.spec.js +224 -0
  125. package/dist/tests/integration/directCommandTty.spec.js +151 -0
  126. package/dist/tests/integration/discoveryEnrichmentFlow.spec.js +175 -0
  127. package/dist/tests/integration/exportArtifacts.spec.js +202 -0
  128. package/dist/tests/integration/exportFallbackFlow.spec.js +99 -0
  129. package/dist/tests/integration/mcpDegradationFlow.spec.js +190 -0
  130. package/dist/tests/integration/mcpTransportFlow.spec.js +139 -0
  131. package/dist/tests/integration/newSessionFlow.spec.js +343 -0
  132. package/dist/tests/integration/pocGithubMcp.spec.js +186 -0
  133. package/dist/tests/integration/pocLocalFallback.spec.js +171 -0
  134. package/dist/tests/integration/pocScaffold.spec.js +163 -0
  135. package/dist/tests/integration/ralphLoopFlow.spec.js +359 -0
  136. package/dist/tests/integration/ralphLoopPartial.spec.js +368 -0
  137. package/dist/tests/integration/resumeAndBacktrack.spec.js +247 -0
  138. package/dist/tests/integration/spinnerLifecycle.spec.js +220 -0
  139. package/dist/tests/integration/summarizationFlow.spec.js +115 -0
  140. package/dist/tests/integration/testRunnerReal.spec.js +52 -0
  141. package/dist/tests/integration/webSearchAgent.spec.js +128 -0
  142. package/dist/tests/live/copilotSdkLive.spec.js +107 -0
  143. package/dist/tests/live/zavaFullWorkshop.spec.js +392 -0
  144. package/dist/tests/setup/loadEnv.js +3 -0
  145. package/dist/tests/unit/cli/developCommand.spec.js +567 -0
  146. package/dist/tests/unit/cli/directCommands.spec.js +279 -0
  147. package/dist/tests/unit/cli/envLoader.spec.js +58 -0
  148. package/dist/tests/unit/cli/ioContext.spec.js +119 -0
  149. package/dist/tests/unit/cli/preflight.spec.js +108 -0
  150. package/dist/tests/unit/cli/statusCommand.spec.js +111 -0
  151. package/dist/tests/unit/cli/workshopClientFallback.spec.js +80 -0
  152. package/dist/tests/unit/cli/workshopCommand.spec.js +329 -0
  153. package/dist/tests/unit/config/vitestEnvSetup.spec.js +13 -0
  154. package/dist/tests/unit/develop/checkpointState.spec.js +315 -0
  155. package/dist/tests/unit/develop/codeGenerator.spec.js +355 -0
  156. package/dist/tests/unit/develop/githubMcpAdapter.spec.js +231 -0
  157. package/dist/tests/unit/develop/mcpContextEnricher.spec.js +433 -0
  158. package/dist/tests/unit/develop/outputValidator.spec.js +119 -0
  159. package/dist/tests/unit/develop/pocScaffolder.spec.js +353 -0
  160. package/dist/tests/unit/develop/ralphLoop.spec.js +1248 -0
  161. package/dist/tests/unit/develop/templateRegistry.spec.js +85 -0
  162. package/dist/tests/unit/develop/testRunner.spec.js +249 -0
  163. package/dist/tests/unit/infraBicep.spec.js +92 -0
  164. package/dist/tests/unit/infraDeploy.spec.js +82 -0
  165. package/dist/tests/unit/infraTeardown.spec.js +63 -0
  166. package/dist/tests/unit/logging/logger.spec.js +43 -0
  167. package/dist/tests/unit/loop/conversationLoop.spec.js +592 -0
  168. package/dist/tests/unit/loop/phaseSummarizer.spec.js +141 -0
  169. package/dist/tests/unit/loop/streamingMarkdown.spec.js +147 -0
  170. package/dist/tests/unit/mcp/mcpManager.spec.js +279 -0
  171. package/dist/tests/unit/mcp/mcpTransport.spec.js +529 -0
  172. package/dist/tests/unit/mcp/retryPolicy.spec.js +218 -0
  173. package/dist/tests/unit/mcp/timeoutValidation.spec.js +46 -0
  174. package/dist/tests/unit/mcp/webSearch.spec.js +567 -0
  175. package/dist/tests/unit/phases/contextSummarizer.spec.js +140 -0
  176. package/dist/tests/unit/phases/discoveryEnricher.repeatCalls.spec.js +93 -0
  177. package/dist/tests/unit/phases/discoveryEnricher.spec.js +411 -0
  178. package/dist/tests/unit/phases/phaseExtractors.spec.js +352 -0
  179. package/dist/tests/unit/phases/phaseHandlers.spec.js +425 -0
  180. package/dist/tests/unit/prompts/promptLoader.spec.js +118 -0
  181. package/dist/tests/unit/schemas/pocSchemas.spec.js +412 -0
  182. package/dist/tests/unit/schemas/session.spec.js +257 -0
  183. package/dist/tests/unit/sessions/exportPaths.spec.js +31 -0
  184. package/dist/tests/unit/sessions/exportWriter.spec.js +655 -0
  185. package/dist/tests/unit/sessions/sessionManager.spec.js +151 -0
  186. package/dist/tests/unit/sessions/sessionStore.spec.js +116 -0
  187. package/dist/tests/unit/shared/activitySpinner.spec.js +175 -0
  188. package/dist/tests/unit/shared/cardsLoader.spec.js +76 -0
  189. package/dist/tests/unit/shared/copilotClient.spec.js +155 -0
  190. package/dist/tests/unit/shared/errorClassifier.spec.js +131 -0
  191. package/dist/tests/unit/shared/events.spec.js +55 -0
  192. package/dist/tests/unit/shared/markdownRenderer.spec.js +35 -0
  193. package/dist/tests/unit/shared/markdownRendererChunks.spec.js +70 -0
  194. package/dist/tests/unit/shared/tableRenderer.spec.js +34 -0
  195. package/dist/vitest.config.js +14 -0
  196. package/dist/vitest.live.config.js +18 -0
  197. package/docs/README.md +35 -0
  198. package/docs/architecture.md +169 -0
  199. package/docs/cli-usage.md +207 -0
  200. package/docs/environment.md +66 -0
  201. package/docs/export-format.md +146 -0
  202. package/docs/session-model.md +113 -0
  203. package/eslint.config.js +35 -0
  204. package/infra/deploy.sh +193 -0
  205. package/infra/gather-env.sh +211 -0
  206. package/infra/main.bicep +90 -0
  207. package/infra/main.bicepparam +18 -0
  208. package/infra/resources.bicep +134 -0
  209. package/infra/teardown.sh +114 -0
  210. package/package.json +63 -0
  211. package/specs/001-cli-workshop-rebuild/checklists/requirements.md +35 -0
  212. package/specs/001-cli-workshop-rebuild/contracts/cli.md +59 -0
  213. package/specs/001-cli-workshop-rebuild/contracts/export-summary-json.md +23 -0
  214. package/specs/001-cli-workshop-rebuild/contracts/session-json.md +30 -0
  215. package/specs/001-cli-workshop-rebuild/data-model.md +210 -0
  216. package/specs/001-cli-workshop-rebuild/plan.md +361 -0
  217. package/specs/001-cli-workshop-rebuild/quickstart.md +83 -0
  218. package/specs/001-cli-workshop-rebuild/research.md +116 -0
  219. package/specs/001-cli-workshop-rebuild/spec.md +240 -0
  220. package/specs/001-cli-workshop-rebuild/tasks.md +476 -0
  221. package/specs/002-poc-generation/contracts/poc-output.md +172 -0
  222. package/specs/002-poc-generation/contracts/ralph-loop.md +113 -0
  223. package/specs/002-poc-generation/data-model.md +172 -0
  224. package/specs/002-poc-generation/plan.md +109 -0
  225. package/specs/002-poc-generation/quickstart.md +97 -0
  226. package/specs/002-poc-generation/research.md +786 -0
  227. package/specs/002-poc-generation/spec.md +81 -0
  228. package/specs/002-poc-generation/tasks-fix.md +198 -0
  229. package/specs/002-poc-generation/tasks.md +252 -0
  230. package/specs/003-mcp-transport-integration/checklists/requirements.md +37 -0
  231. package/specs/003-mcp-transport-integration/contracts/context-enricher.md +220 -0
  232. package/specs/003-mcp-transport-integration/contracts/discovery-enricher.md +267 -0
  233. package/specs/003-mcp-transport-integration/contracts/github-adapter.md +149 -0
  234. package/specs/003-mcp-transport-integration/contracts/mcp-transport.md +288 -0
  235. package/specs/003-mcp-transport-integration/data-model.md +326 -0
  236. package/specs/003-mcp-transport-integration/plan.md +114 -0
  237. package/specs/003-mcp-transport-integration/quickstart.md +311 -0
  238. package/specs/003-mcp-transport-integration/research.md +395 -0
  239. package/specs/003-mcp-transport-integration/spec.md +234 -0
  240. package/specs/003-mcp-transport-integration/tasks.md +324 -0
  241. package/specs/003-next-spec-gaps.md +150 -0
  242. package/specs/004-dev-resume-hardening/checklists/requirements.md +37 -0
  243. package/specs/004-dev-resume-hardening/contracts/cli.md +160 -0
  244. package/specs/004-dev-resume-hardening/data-model.md +321 -0
  245. package/specs/004-dev-resume-hardening/plan.md +107 -0
  246. package/specs/004-dev-resume-hardening/quickstart.md +115 -0
  247. package/specs/004-dev-resume-hardening/research.md +142 -0
  248. package/specs/004-dev-resume-hardening/spec.md +221 -0
  249. package/specs/004-dev-resume-hardening/tasks.md +333 -0
  250. package/specs/005-ai-search-deploy/checklists/requirements.md +39 -0
  251. package/specs/005-ai-search-deploy/contracts/web-search-tool.md +241 -0
  252. package/specs/005-ai-search-deploy/data-model.md +130 -0
  253. package/specs/005-ai-search-deploy/plan.md +93 -0
  254. package/specs/005-ai-search-deploy/quickstart.md +96 -0
  255. package/specs/005-ai-search-deploy/research.md +187 -0
  256. package/specs/005-ai-search-deploy/spec.md +143 -0
  257. package/specs/005-ai-search-deploy/tasks.md +284 -0
  258. package/specs/006-workshop-extraction-fixes/checklists/requirements.md +61 -0
  259. package/specs/006-workshop-extraction-fixes/contracts/summarization-and-export.md +131 -0
  260. package/specs/006-workshop-extraction-fixes/data-model.md +149 -0
  261. package/specs/006-workshop-extraction-fixes/plan.md +123 -0
  262. package/specs/006-workshop-extraction-fixes/quickstart.md +101 -0
  263. package/specs/006-workshop-extraction-fixes/research.md +143 -0
  264. package/specs/006-workshop-extraction-fixes/spec.md +210 -0
  265. package/specs/006-workshop-extraction-fixes/tasks.md +316 -0
  266. package/src/cli/developCommand.ts +308 -0
  267. package/src/cli/directCommands.ts +195 -0
  268. package/src/cli/envLoader.ts +17 -0
  269. package/src/cli/exportCommand.ts +65 -0
  270. package/src/cli/index.ts +249 -0
  271. package/src/cli/ioContext.ts +139 -0
  272. package/src/cli/preflight.ts +86 -0
  273. package/src/cli/statusCommand.ts +118 -0
  274. package/src/cli/workshopCommand.ts +496 -0
  275. package/src/develop/checkpointState.ts +121 -0
  276. package/src/develop/codeGenerator.ts +402 -0
  277. package/src/develop/dynamicScaffolder.ts +284 -0
  278. package/src/develop/githubMcpAdapter.ts +199 -0
  279. package/src/develop/index.ts +34 -0
  280. package/src/develop/mcpContextEnricher.ts +279 -0
  281. package/src/develop/pocScaffolder.ts +646 -0
  282. package/src/develop/ralphLoop.ts +1044 -0
  283. package/src/develop/templateRegistry.ts +427 -0
  284. package/src/develop/testRunner.ts +276 -0
  285. package/src/logging/logger.ts +73 -0
  286. package/src/loop/conversationLoop.ts +355 -0
  287. package/src/loop/phaseSummarizer.ts +114 -0
  288. package/src/mcp/mcpManager.ts +365 -0
  289. package/src/mcp/mcpTransport.ts +562 -0
  290. package/src/mcp/retryPolicy.ts +87 -0
  291. package/src/mcp/webSearch.ts +388 -0
  292. package/src/originalPrompts/design_thinking.md +178 -0
  293. package/src/originalPrompts/design_thinking_persona.md +76 -0
  294. package/src/originalPrompts/document_generator_example.md +77 -0
  295. package/src/originalPrompts/document_generator_persona.md +47 -0
  296. package/src/originalPrompts/facilitator_persona.md +125 -0
  297. package/src/originalPrompts/guardrails.md +47 -0
  298. package/src/phases/contextSummarizer.ts +154 -0
  299. package/src/phases/discoveryEnricher.ts +223 -0
  300. package/src/phases/phaseExtractors.ts +247 -0
  301. package/src/phases/phaseHandlers.ts +450 -0
  302. package/src/prompts/design.md +51 -0
  303. package/src/prompts/develop-boundary.md +51 -0
  304. package/src/prompts/develop.md +111 -0
  305. package/src/prompts/discover.md +58 -0
  306. package/src/prompts/ideate.md +56 -0
  307. package/src/prompts/plan.md +51 -0
  308. package/src/prompts/promptLoader.ts +198 -0
  309. package/src/prompts/select.md +47 -0
  310. package/src/prompts/summarize/README.md +8 -0
  311. package/src/prompts/summarize/design-summary.md +37 -0
  312. package/src/prompts/summarize/develop-summary.md +25 -0
  313. package/src/prompts/summarize/ideate-summary.md +27 -0
  314. package/src/prompts/summarize/plan-summary.md +27 -0
  315. package/src/prompts/summarize/select-summary.md +21 -0
  316. package/src/prompts/system.md +28 -0
  317. package/src/sessions/exportPaths.ts +28 -0
  318. package/src/sessions/exportWriter.ts +490 -0
  319. package/src/sessions/sessionManager.ts +119 -0
  320. package/src/sessions/sessionStore.ts +69 -0
  321. package/src/shared/activitySpinner.ts +108 -0
  322. package/src/shared/copilotClient.ts +291 -0
  323. package/src/shared/data/cards.json +1249 -0
  324. package/src/shared/data/cardsLoader.ts +70 -0
  325. package/src/shared/errorClassifier.ts +160 -0
  326. package/src/shared/events.ts +103 -0
  327. package/src/shared/markdownRenderer.ts +44 -0
  328. package/src/shared/schemas/session.ts +346 -0
  329. package/src/shared/tableRenderer.ts +28 -0
  330. package/src/types/marked-terminal.d.ts +5 -0
  331. package/src/vendor/chalk.ts +2 -0
  332. package/src/vendor/cli-table3.ts +3 -0
  333. package/src/vendor/commander.ts +2 -0
  334. package/src/vendor/marked-terminal.ts +3 -0
  335. package/src/vendor/marked.ts +2 -0
  336. package/src/vendor/ora.ts +2 -0
  337. package/src/vendor/pino.ts +3 -0
  338. package/src/vendor/zod.ts +3 -0
  339. package/tests/e2e/developE2e.spec.ts +152 -0
  340. package/tests/e2e/developFailureE2e.spec.ts +289 -0
  341. package/tests/e2e/developPty.spec.ts +86 -0
  342. package/tests/e2e/discoveryWebSearchRelevance.spec.ts +103 -0
  343. package/tests/e2e/harness.spec.ts +104 -0
  344. package/tests/e2e/mcpLive.spec.ts +149 -0
  345. package/tests/e2e/newSession.e2e.spec.ts +245 -0
  346. package/tests/e2e/ralphLoopEnrichmentComparison.spec.ts +70 -0
  347. package/tests/e2e/workiqEnrichment.spec.ts +72 -0
  348. package/tests/e2e/zava-assessment/agent-interaction-script.md +258 -0
  349. package/tests/e2e/zava-assessment/company-profile.md +98 -0
  350. package/tests/e2e/zava-assessment/expected-results-checklist.md +454 -0
  351. package/tests/e2e/zavaSimulation.spec.ts +511 -0
  352. package/tests/fixtures/completedSession.json +141 -0
  353. package/tests/fixtures/test-fixture-project/package-lock.json +1585 -0
  354. package/tests/fixtures/test-fixture-project/package.json +12 -0
  355. package/tests/fixtures/test-fixture-project/src/add.ts +3 -0
  356. package/tests/fixtures/test-fixture-project/tests/failing.test.ts +7 -0
  357. package/tests/fixtures/test-fixture-project/tests/hanging.test.ts +9 -0
  358. package/tests/fixtures/test-fixture-project/tests/passing.test.ts +13 -0
  359. package/tests/fixtures/test-fixture-project/vitest.config.ts +7 -0
  360. package/tests/integration/autoStartConversation.spec.ts +168 -0
  361. package/tests/integration/defaultCommand.spec.ts +179 -0
  362. package/tests/integration/directCommandNonTty.spec.ts +260 -0
  363. package/tests/integration/directCommandTty.spec.ts +185 -0
  364. package/tests/integration/discoveryEnrichmentFlow.spec.ts +209 -0
  365. package/tests/integration/exportArtifacts.spec.ts +232 -0
  366. package/tests/integration/exportFallbackFlow.spec.ts +115 -0
  367. package/tests/integration/mcpDegradationFlow.spec.ts +231 -0
  368. package/tests/integration/mcpTransportFlow.spec.ts +178 -0
  369. package/tests/integration/newSessionFlow.spec.ts +406 -0
  370. package/tests/integration/pocGithubMcp.spec.ts +224 -0
  371. package/tests/integration/pocLocalFallback.spec.ts +205 -0
  372. package/tests/integration/pocScaffold.spec.ts +220 -0
  373. package/tests/integration/ralphLoopFlow.spec.ts +430 -0
  374. package/tests/integration/ralphLoopPartial.spec.ts +416 -0
  375. package/tests/integration/resumeAndBacktrack.spec.ts +278 -0
  376. package/tests/integration/spinnerLifecycle.spec.ts +270 -0
  377. package/tests/integration/summarizationFlow.spec.ts +135 -0
  378. package/tests/integration/testRunnerReal.spec.ts +63 -0
  379. package/tests/integration/webSearchAgent.spec.ts +155 -0
  380. package/tests/live/copilotSdkLive.spec.ts +149 -0
  381. package/tests/live/zavaFullWorkshop.spec.ts +515 -0
  382. package/tests/setup/loadEnv.ts +5 -0
  383. package/tests/unit/cli/developCommand.spec.ts +679 -0
  384. package/tests/unit/cli/directCommands.spec.ts +325 -0
  385. package/tests/unit/cli/envLoader.spec.ts +73 -0
  386. package/tests/unit/cli/ioContext.spec.ts +148 -0
  387. package/tests/unit/cli/preflight.spec.ts +125 -0
  388. package/tests/unit/cli/statusCommand.spec.ts +134 -0
  389. package/tests/unit/cli/workshopClientFallback.spec.ts +100 -0
  390. package/tests/unit/cli/workshopCommand.spec.ts +378 -0
  391. package/tests/unit/config/vitestEnvSetup.spec.ts +24 -0
  392. package/tests/unit/develop/checkpointState.spec.ts +378 -0
  393. package/tests/unit/develop/codeGenerator.spec.ts +447 -0
  394. package/tests/unit/develop/githubMcpAdapter.spec.ts +283 -0
  395. package/tests/unit/develop/mcpContextEnricher.spec.ts +564 -0
  396. package/tests/unit/develop/outputValidator.spec.ts +134 -0
  397. package/tests/unit/develop/pocScaffolder.spec.ts +451 -0
  398. package/tests/unit/develop/ralphLoop.spec.ts +1439 -0
  399. package/tests/unit/develop/templateRegistry.spec.ts +106 -0
  400. package/tests/unit/develop/testRunner.spec.ts +294 -0
  401. package/tests/unit/infraBicep.spec.ts +116 -0
  402. package/tests/unit/infraDeploy.spec.ts +102 -0
  403. package/tests/unit/infraTeardown.spec.ts +77 -0
  404. package/tests/unit/logging/logger.spec.ts +50 -0
  405. package/tests/unit/loop/conversationLoop.spec.ts +719 -0
  406. package/tests/unit/loop/phaseSummarizer.spec.ts +169 -0
  407. package/tests/unit/loop/streamingMarkdown.spec.ts +180 -0
  408. package/tests/unit/mcp/mcpManager.spec.ts +336 -0
  409. package/tests/unit/mcp/mcpTransport.spec.ts +689 -0
  410. package/tests/unit/mcp/retryPolicy.spec.ts +278 -0
  411. package/tests/unit/mcp/timeoutValidation.spec.ts +55 -0
  412. package/tests/unit/mcp/webSearch.spec.ts +718 -0
  413. package/tests/unit/phases/contextSummarizer.spec.ts +158 -0
  414. package/tests/unit/phases/discoveryEnricher.repeatCalls.spec.ts +125 -0
  415. package/tests/unit/phases/discoveryEnricher.spec.ts +512 -0
  416. package/tests/unit/phases/phaseExtractors.spec.ts +406 -0
  417. package/tests/unit/phases/phaseHandlers.spec.ts +483 -0
  418. package/tests/unit/prompts/promptLoader.spec.ts +144 -0
  419. package/tests/unit/schemas/pocSchemas.spec.ts +457 -0
  420. package/tests/unit/schemas/session.spec.ts +328 -0
  421. package/tests/unit/sessions/exportPaths.spec.ts +38 -0
  422. package/tests/unit/sessions/exportWriter.spec.ts +737 -0
  423. package/tests/unit/sessions/sessionManager.spec.ts +174 -0
  424. package/tests/unit/sessions/sessionStore.spec.ts +136 -0
  425. package/tests/unit/shared/activitySpinner.spec.ts +211 -0
  426. package/tests/unit/shared/cardsLoader.spec.ts +89 -0
  427. package/tests/unit/shared/copilotClient.spec.ts +185 -0
  428. package/tests/unit/shared/errorClassifier.spec.ts +152 -0
  429. package/tests/unit/shared/events.spec.ts +71 -0
  430. package/tests/unit/shared/markdownRenderer.spec.ts +42 -0
  431. package/tests/unit/shared/markdownRendererChunks.spec.ts +83 -0
  432. package/tests/unit/shared/tableRenderer.spec.ts +38 -0
  433. package/tsconfig.json +20 -0
  434. package/vitest.config.ts +15 -0
  435. package/vitest.live.config.ts +19 -0
@@ -0,0 +1,288 @@
1
+ # Contract: MCP Transport Layer
2
+
3
+ **Feature**: 003-mcp-transport-integration
4
+ **Module**: `src/mcp/mcpTransport.ts`, `src/mcp/mcpManager.ts`, `src/mcp/retryPolicy.ts`
5
+ **Status**: Authoritative design document
6
+
7
+ ---
8
+
9
+ ## Overview
10
+
11
+ This contract defines the interface and behavior of `McpManager.callTool()` and the underlying transport layer (`McpTransport`). All MCP adapters and enrichers call `mcpManager.callTool()` — this is the single point of entry for **programmatic** MCP tool invocations (i.e., deterministic application-layer calls that bypass the LLM).
12
+
13
+ ### Scope: Programmatic Adapter Calls Only
14
+
15
+ The custom transport layer described in this contract handles **only** direct tool calls made by adapters (GitHub adapter, Context7 enricher, Azure enricher) that need deterministic, application-controlled MCP invocations. These calls bypass the LLM conversation loop.
16
+
17
+ **LLM-initiated tool calls** (e.g., web search during conversation, MCP tools invoked by the LLM during `sendAndWait()`) are handled by the **Copilot SDK's native MCP support**. The SDK manages server lifecycle (spawn, connect, JSON-RPC) for these calls via `SessionConfig.mcpServers` passed to `CopilotClient.createSession()`. See `research.md` Topic 1 for details.
18
+
19
+ **⚠️ Dual-lifecycle note**: If the same MCP server is used in both paths (e.g., `context7` queried by the LLM and by `McpContextEnricher`), two separate subprocess instances will be spawned — one by the SDK and one by the custom transport. This is acceptable for Feature 003 scope.
20
+
21
+ ---
22
+
23
+ ## McpTransport Interface
24
+
25
+ ```typescript
26
+ // src/mcp/mcpTransport.ts
27
+
28
+ export interface McpTransport {
29
+ callTool(
30
+ toolName: string,
31
+ args: Record<string, unknown>,
32
+ timeoutMs: number,
33
+ ): Promise<ToolCallResponse>;
34
+ isConnected(): boolean;
35
+ disconnect(): Promise<void>;
36
+ }
37
+
38
+ export interface ToolCallResponse {
39
+ content: Record<string, unknown> | string;
40
+ raw?: unknown;
41
+ wasRetried?: boolean;
42
+ }
43
+
44
+ export class McpTransportError extends Error {
45
+ constructor(
46
+ message: string,
47
+ public readonly serverName: string,
48
+ public readonly toolName: string,
49
+ public readonly cause?: unknown,
50
+ ) {
51
+ super(message);
52
+ this.name = 'McpTransportError';
53
+ }
54
+ }
55
+ ```
56
+
57
+ ---
58
+
59
+ ## StdioMcpTransport Contract
60
+
61
+ **Constructor**: `new StdioMcpTransport(config: StdioServerConfig, logger: pino.Logger)`
62
+
63
+ ### `connect(): Promise<void>`
64
+
65
+ | Step | Behavior |
66
+ | ---- | --------------------------------------------------------------------------------------------------------------------- |
67
+ | 1 | Spawn subprocess: `spawn(config.command, config.args, { stdio: ['pipe','pipe','pipe'], env: process.env })` |
68
+ | 2 | Send JSON-RPC `initialize` request with `{ protocolVersion: '1.0', clientInfo: { name: 'sofIA', version: '0.1.0' } }` |
69
+ | 3 | Wait for any JSON-RPC response with matching id within **5 seconds** |
70
+ | 4 | On success: set `connected = true`; log info `'MCP stdio server connected: {name}'` |
71
+ | 5 | On timeout: kill subprocess, throw `McpTransportError` classified as `timeout` |
72
+ | 6 | On subprocess exit before init: throw `McpTransportError` classified as `connection-refused` |
73
+
74
+ ### `callTool(toolName, args, timeoutMs): Promise<ToolCallResponse>`
75
+
76
+ **Preconditions**: `connect()` must have been called and succeeded.
77
+
78
+ | Step | Behavior |
79
+ | ---- | -------------------------------------------------------------------------------------------------------------------------------------------- |
80
+ | 1 | Generate `id = this.nextId++` |
81
+ | 2 | Register pending request: `pendingRequests.set(id, { resolve, reject, timer })` |
82
+ | 3 | Start timeout: after `timeoutMs` ms, reject pending request with timeout error |
83
+ | 4 | Write to `process.stdin`: `JSON.stringify({ jsonrpc: '2.0', id, method: 'tools/call', params: { name: toolName, arguments: args } }) + '\n'` |
84
+ | 5 | On `process.stdout` line: parse JSON; if `line.id === id`, resolve/reject pending request |
85
+ | 6 | On JSON-RPC error response: throw `McpTransportError(error.message)` |
86
+ | 7 | On malformed line (JSON parse fails): skip, log debug `'Skipping non-JSON stdout line'` |
87
+ | 8 | Map `result.content[0].text` → `ToolCallResponse.content` (or `result` directly if no content array) |
88
+
89
+ ### `disconnect(): Promise<void>`
90
+
91
+ | Step | Behavior |
92
+ | ---- | ------------------------------------------------------------------------------ |
93
+ | 1 | Reject all pending requests with `McpTransportError('transport disconnected')` |
94
+ | 2 | Kill subprocess: `process.kill('SIGTERM')` |
95
+ | 3 | Set `connected = false` |
96
+
97
+ ---
98
+
99
+ ## HttpMcpTransport Contract
100
+
101
+ **Constructor**: `new HttpMcpTransport(config: HttpServerConfig, logger: pino.Logger)`
102
+
103
+ ### `callTool(toolName, args, timeoutMs): Promise<ToolCallResponse>`
104
+
105
+ | Step | Behavior |
106
+ | ---- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
107
+ | 1 | Build request body: `{ jsonrpc: '2.0', id: nextId++, method: 'tools/call', params: { name: toolName, arguments: args } }` |
108
+ | 2 | Build headers: `{ 'Content-Type': 'application/json', ...(token ? { 'Authorization': 'Bearer <token>' } : {}) }` where token = `process.env.GITHUB_TOKEN` |
109
+ | 3 | Create `AbortController`, schedule `abort()` after `timeoutMs` ms |
110
+ | 4 | `fetch(config.url, { method: 'POST', headers, body: JSON.stringify(body), signal: controller.signal })` |
111
+ | 5 | On abort: throw `McpTransportError` classified as `timeout` |
112
+ | 6 | On HTTP 401/403: throw `McpTransportError` classified as `auth-failure` |
113
+ | 7 | On HTTP 5xx: throw `McpTransportError` classified as `unknown` |
114
+ | 8 | Parse response body as JSON; extract `result.content` → `ToolCallResponse` |
115
+ | 9 | On JSON-RPC error: throw `McpTransportError(error.message)` |
116
+
117
+ ### `isConnected(): boolean`
118
+
119
+ Returns `true` always (HTTP is stateless).
120
+
121
+ ### `disconnect(): Promise<void>`
122
+
123
+ No-op (no persistent connection to close).
124
+
125
+ ---
126
+
127
+ ## McpManager.callTool() Contract
128
+
129
+ ```typescript
130
+ // src/mcp/mcpManager.ts
131
+
132
+ async callTool(
133
+ serverName: string,
134
+ toolName: string,
135
+ args: Record<string, unknown>,
136
+ options?: { timeoutMs?: number; retryOnTransient?: boolean }
137
+ ): Promise<Record<string, unknown>>
138
+ ```
139
+
140
+ ### Behavior
141
+
142
+ | Step | Behavior |
143
+ | ---- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
144
+ | 1 | Validate `serverName` is in `this.config.servers`; throw `Error('Unknown MCP server: {serverName}')` if not |
145
+ | 2 | Get or create transport: `this.getOrCreateTransport(serverName)` |
146
+ | 3 | For stdio transports: if not connected, call `transport.connect()` and `markConnected(serverName)` |
147
+ | 4 | Determine timeout: `options.timeoutMs ?? this.defaultTimeouts[serverName] ?? 30_000` |
148
+ | 5 | Apply retry policy (if `retryOnTransient !== false`): `withRetry(() => transport.callTool(toolName, args, timeoutMs), { serverName, toolName })` |
149
+ | 6 | Normalize response: cast `ToolCallResponse.content` to `Record<string, unknown>` (if string, wrap as `{ text: content }`) |
150
+ | 7 | On transport error: call `markDisconnected(serverName)`; re-throw `McpTransportError` to caller |
151
+
152
+ ### Default Timeouts
153
+
154
+ | Server | Default Timeout |
155
+ | ------------------- | --------------------------------------- |
156
+ | `github` | 60,000 ms (repo operations can be slow) |
157
+ | `context7` | 30,000 ms |
158
+ | `azure` | 30,000 ms |
159
+ | `workiq` | 30,000 ms |
160
+ | `microsoftdocs/mcp` | 30,000 ms |
161
+ | any other | 30,000 ms |
162
+
163
+ ### Error Propagation
164
+
165
+ `McpManager.callTool()` does **not** swallow errors. Callers (adapters, enrichers) are responsible for catching `McpTransportError` and degrading gracefully. This keeps the transport layer simple and the caller's error handling explicit.
166
+
167
+ ---
168
+
169
+ ## RetryPolicy Contract
170
+
171
+ ```typescript
172
+ // src/mcp/retryPolicy.ts
173
+
174
+ export interface RetryOptions {
175
+ serverName: string;
176
+ toolName: string;
177
+ /** Initial delay in ms before first retry. Default: 1000 */
178
+ initialDelayMs?: number;
179
+ /** Jitter fraction (0–1). Default: 0.2 (±20%) */
180
+ jitter?: number;
181
+ logger?: pino.Logger;
182
+ }
183
+
184
+ /**
185
+ * Wrap an async function with a single-retry policy for transient MCP errors.
186
+ *
187
+ * Retryable errors: connection-refused, timeout, dns-failure
188
+ * Non-retryable: auth-failure, unknown, validation errors
189
+ *
190
+ * On retry: waits initialDelayMs ± jitter, then calls fn() again once.
191
+ * If the retry also fails, the second error is thrown (not the first).
192
+ */
193
+ export async function withRetry<T>(fn: () => Promise<T>, options: RetryOptions): Promise<T>;
194
+ ```
195
+
196
+ ### Retry Decision Table
197
+
198
+ | `classifyMcpError()` result | Retried? |
199
+ | --------------------------- | ------------------------- |
200
+ | `connection-refused` | ✅ Yes, once |
201
+ | `timeout` | ✅ Yes, once |
202
+ | `dns-failure` | ✅ Yes, once |
203
+ | `auth-failure` | ❌ No — throw immediately |
204
+ | `unknown` | ❌ No — throw immediately |
205
+ | Not a `McpTransportError` | ❌ No — throw immediately |
206
+
207
+ ### Logging on Retry
208
+
209
+ When a retry is triggered, log at `warn` level:
210
+
211
+ ```
212
+ { server: serverName, tool: toolName, attempt: 1, delayMs: N, errorClass: '...' }
213
+ MCP transient error — retrying after {N}ms
214
+ ```
215
+
216
+ ---
217
+
218
+ ## Transport Factory
219
+
220
+ ```typescript
221
+ // src/mcp/mcpTransport.ts
222
+
223
+ /**
224
+ * Create the correct transport implementation for a server config.
225
+ */
226
+ export function createTransport(config: McpServerConfig, logger: pino.Logger): McpTransport {
227
+ if (config.type === 'stdio') return new StdioMcpTransport(config, logger);
228
+ if (config.type === 'http') return new HttpMcpTransport(config, logger);
229
+ throw new Error(`Unsupported MCP transport type: ${(config as McpServerConfig).type}`);
230
+ }
231
+ ```
232
+
233
+ ---
234
+
235
+ ## Test Doubles
236
+
237
+ ### FakeMcpTransport (for unit tests)
238
+
239
+ ```typescript
240
+ // tests/helpers/fakeMcpTransport.ts
241
+
242
+ export class FakeMcpTransport implements McpTransport {
243
+ private readonly responses: Map<string, Record<string, unknown>>;
244
+ public callCount = 0;
245
+ public connected = true;
246
+ public callLog: Array<{ toolName: string; args: Record<string, unknown> }> = [];
247
+
248
+ constructor(responses: Map<string, Record<string, unknown>>) {
249
+ this.responses = responses;
250
+ }
251
+
252
+ async callTool(toolName: string, args: Record<string, unknown>): Promise<ToolCallResponse> {
253
+ this.callCount++;
254
+ this.callLog.push({ toolName, args });
255
+ const response = this.responses.get(toolName);
256
+ if (!response)
257
+ throw new McpTransportError(`No fake response for tool: ${toolName}`, 'fake', toolName);
258
+ return { content: response };
259
+ }
260
+
261
+ isConnected(): boolean {
262
+ return this.connected;
263
+ }
264
+ async disconnect(): Promise<void> {
265
+ this.connected = false;
266
+ }
267
+ }
268
+ ```
269
+
270
+ ---
271
+
272
+ ## Acceptance Tests (Unit + Integration)
273
+
274
+ | Test | Type | Description |
275
+ | ------------------------------------------------------------------ | ----------- | ----------------------------------------------------- |
276
+ | `callTool routes to StdioTransport for stdio servers` | unit | Verify transport factory creates correct type |
277
+ | `callTool routes to HttpTransport for HTTP servers` | unit | Verify transport factory creates correct type |
278
+ | `StdioMcpTransport sends JSON-RPC and parses response` | unit | Mock subprocess stdout returns valid response |
279
+ | `StdioMcpTransport times out after timeoutMs` | unit | Mock subprocess that never responds |
280
+ | `HttpMcpTransport POSTs correct JSON-RPC and parses response` | unit | Mock `fetch` returns valid response |
281
+ | `HttpMcpTransport sets Authorization header when GITHUB_TOKEN set` | unit | Verify header presence |
282
+ | `HttpMcpTransport throws auth-failure on 401` | unit | Mock `fetch` returns 401 |
283
+ | `withRetry retries once on connection-refused` | unit | First call throws connection-refused, second succeeds |
284
+ | `withRetry does NOT retry on auth-failure` | unit | Throws immediately |
285
+ | `McpManager.callTool unknown server throws` | unit | Verify guard |
286
+ | `McpManager.callTool creates and caches transport` | unit | Second call reuses same transport |
287
+ | `McpManager.disconnectAll terminates all transports` | unit | Both transports disconnected |
288
+ | `End-to-end transport with mock MCP server` | integration | Node.js echo server over stdin/stdout |
@@ -0,0 +1,326 @@
1
+ # Data Model: MCP Transport Integration
2
+
3
+ **Feature ID**: 003-mcp-transport-integration
4
+ **Date**: 2026-03-01
5
+ **Status**: Complete
6
+
7
+ ---
8
+
9
+ ## Overview
10
+
11
+ This feature introduces three new logical entities and extends two existing ones:
12
+
13
+ | Entity | Status | Module |
14
+ |--------|--------|--------|
15
+ | `McpTransport` | **NEW** | `src/mcp/mcpTransport.ts` |
16
+ | `ToolCallRequest` | **NEW** | `src/mcp/mcpTransport.ts` |
17
+ | `ToolCallResponse` | **NEW** | `src/mcp/mcpTransport.ts` |
18
+ | `DiscoveryEnrichment` | **NEW** | `src/shared/schemas/session.ts` |
19
+ | `McpManager` | **EXTENDED** | `src/mcp/mcpManager.ts` |
20
+ | `DiscoveryState` | **EXTENDED** | `src/shared/schemas/session.ts` |
21
+
22
+ ---
23
+
24
+ ## Entity 1: McpTransport (Interface + Implementations)
25
+
26
+ **Purpose**: Abstracts the communication channel to a single MCP server. Handles connection lifecycle and JSON-RPC framing.
27
+
28
+ ### Interface
29
+
30
+ ```typescript
31
+ /**
32
+ * Common interface for all MCP transport implementations.
33
+ * A transport represents a live connection to one MCP server.
34
+ */
35
+ export interface McpTransport {
36
+ /**
37
+ * Invoke a named tool on this MCP server.
38
+ * Throws McpTransportError on failure (callers use classifyMcpError).
39
+ */
40
+ callTool(
41
+ toolName: string,
42
+ args: Record<string, unknown>,
43
+ timeoutMs: number
44
+ ): Promise<ToolCallResponse>;
45
+
46
+ /** Whether the transport is currently connected and able to accept calls. */
47
+ isConnected(): boolean;
48
+
49
+ /** Gracefully disconnect (terminate subprocess or close HTTP keepalive). */
50
+ disconnect(): Promise<void>;
51
+ }
52
+ ```
53
+
54
+ ### StdioMcpTransport
55
+
56
+ **Module**: `src/mcp/mcpTransport.ts`
57
+ **Description**: Manages a long-lived child process for stdio-based MCP servers (Context7, Azure MCP, WorkIQ, Playwright).
58
+
59
+ **Fields**:
60
+ | Field | Type | Description |
61
+ |-------|------|-------------|
62
+ | `config` | `StdioServerConfig` | Server name, command, args from `.vscode/mcp.json` |
63
+ | `process` | `ChildProcess \| null` | The spawned subprocess |
64
+ | `pendingRequests` | `Map<number, PendingRequest>` | In-flight JSON-RPC requests keyed by id |
65
+ | `nextId` | `number` | Auto-incrementing JSON-RPC request id counter |
66
+ | `connected` | `boolean` | Whether the initialization handshake completed |
67
+
68
+ **Lifecycle**:
69
+ 1. `connect()`: `spawn()` subprocess, send `initialize` JSON-RPC request, wait for `initialized` response. Sets `connected = true`.
70
+ 2. `callTool()`: Generate next id, create `PendingRequest` with resolve/reject + timeout, write JSON-RPC request to `process.stdin`, wait for matching response id on `process.stdout`.
71
+ 3. `disconnect()`: Send `shutdown` request (optional), then `process.kill()`, clear pending requests with `McpTransportError`.
72
+
73
+ **Validation rules**:
74
+ - Subprocess must respond to `initialize` within 5 seconds or `connect()` throws.
75
+ - Malformed stdout (non-JSON lines) are silently skipped (debug-logged).
76
+ - If subprocess exits unexpectedly, all pending requests are rejected with `connection-refused` class error.
77
+
78
+ ### HttpMcpTransport
79
+
80
+ **Module**: `src/mcp/mcpTransport.ts`
81
+ **Description**: Stateless HTTPS tool calls for HTTP-based MCP servers (GitHub MCP, Microsoft Docs MCP).
82
+
83
+ **Fields**:
84
+ | Field | Type | Description |
85
+ |-------|------|-------------|
86
+ | `config` | `HttpServerConfig` | Server name and URL from `.vscode/mcp.json` |
87
+ | `nextId` | `number` | Auto-incrementing request id |
88
+
89
+ **Behavior**:
90
+ - Each `callTool()` makes one `fetch()` POST to `config.url`.
91
+ - `AbortController` enforces `timeoutMs`.
92
+ - `Authorization: Bearer <GITHUB_TOKEN>` added when `process.env.GITHUB_TOKEN` is set.
93
+ - No persistent connection (`isConnected()` always returns `true` if the URL is reachable).
94
+
95
+ **Validation rules**:
96
+ - HTTP 4xx responses with status 401/403 → `auth-failure` error class.
97
+ - HTTP 5xx responses → `unknown` error class (not retried).
98
+ - Non-JSON response body → `unknown` error class.
99
+ - Missing `GITHUB_TOKEN` for authenticated endpoints → `auth-failure` (immediate, no retry).
100
+
101
+ ---
102
+
103
+ ## Entity 2: ToolCallRequest
104
+
105
+ **Purpose**: Structured input for a tool call — server, tool, args, and policy configuration.
106
+
107
+ ```typescript
108
+ export interface ToolCallRequest {
109
+ /** MCP server name as defined in .vscode/mcp.json (e.g., 'github', 'context7') */
110
+ serverName: string;
111
+ /** Tool name to invoke on the server (e.g., 'create_repository', 'resolve-library-id') */
112
+ toolName: string;
113
+ /** Tool arguments — must match the tool's declared JSON Schema */
114
+ args: Record<string, unknown>;
115
+ /**
116
+ * Timeout in milliseconds.
117
+ * Default: 30_000 for query tools, 60_000 for repo operations.
118
+ */
119
+ timeoutMs?: number;
120
+ /**
121
+ * Whether to apply retry policy for transient errors.
122
+ * Default: true
123
+ */
124
+ retryOnTransient?: boolean;
125
+ }
126
+ ```
127
+
128
+ **Validation rules**:
129
+ - `serverName` must be a key in the loaded `McpConfig.servers` — throws `Error` if unknown.
130
+ - `toolName` must be a non-empty string.
131
+ - `args` must be a plain object (no prototype chain, no Functions).
132
+ - `timeoutMs` must be between 1_000 and 120_000 ms when provided.
133
+
134
+ ---
135
+
136
+ ## Entity 3: ToolCallResponse
137
+
138
+ **Purpose**: Parsed and normalized output from an MCP tool call.
139
+
140
+ ```typescript
141
+ export interface ToolCallResponse {
142
+ /**
143
+ * The tool's result content. For MCP protocol, this is the parsed
144
+ * `result.content[0].text` value (or the full `result` object if no content array).
145
+ */
146
+ content: Record<string, unknown> | string;
147
+ /** Raw MCP response for debugging (not logged in production) */
148
+ raw?: unknown;
149
+ /** Whether this response came from a retry attempt */
150
+ wasRetried?: boolean;
151
+ }
152
+ ```
153
+
154
+ **Validation rules**:
155
+ - If the MCP JSON-RPC response contains `error`, throw `McpTransportError` with the error message.
156
+ - If `result.content` is an array, use `content[0].text` as the content (standard MCP protocol format).
157
+ - If `result.content` is an object (some servers return directly), use it as-is.
158
+ - `content` must never be undefined in a successful response — throw if result is empty.
159
+
160
+ ---
161
+
162
+ ## Entity 4: DiscoveryEnrichment
163
+
164
+ **Purpose**: Optional context gathered during the discovery phase, stored in the session for downstream phases (ideation, planning).
165
+
166
+ **Module**: `src/shared/schemas/session.ts`
167
+
168
+ ### Zod Schema
169
+
170
+ ```typescript
171
+ export const DiscoveryEnrichmentSchema = z.object({
172
+ /** Raw web search summary text (combined from all queries) */
173
+ webSearchResults: z.string().optional(),
174
+ /** Recent news headlines/snippets about the company */
175
+ companyNews: z.array(z.string()).optional(),
176
+ /** Competitor activity summaries */
177
+ competitorInfo: z.array(z.string()).optional(),
178
+ /** Industry trend descriptions */
179
+ industryTrends: z.array(z.string()).optional(),
180
+ /** WorkIQ-derived team insights (only present if user consented) */
181
+ workiqInsights: z.object({
182
+ /** Identified team skill areas */
183
+ teamExpertise: z.array(z.string()).optional(),
184
+ /** Meeting/communication patterns identified */
185
+ collaborationPatterns: z.array(z.string()).optional(),
186
+ /** Areas lacking internal documentation */
187
+ documentationGaps: z.array(z.string()).optional(),
188
+ }).optional(),
189
+ /** ISO 8601 timestamp when enrichment was collected */
190
+ enrichedAt: z.string().optional(),
191
+ /** Which sources were queried ('websearch', 'workiq') */
192
+ sourcesUsed: z.array(z.string()).optional(),
193
+ });
194
+
195
+ export type DiscoveryEnrichment = z.infer<typeof DiscoveryEnrichmentSchema>;
196
+ ```
197
+
198
+ ### Relationships
199
+
200
+ - **Belongs to `DiscoveryState`**: Added as `enrichment?: DiscoveryEnrichment` on the existing `DiscoveryState` schema.
201
+ - **Referenced by ideation/planning phases**: The enrichment fields are injected into LLM prompts as additional context when non-empty.
202
+
203
+ ### State Transitions
204
+
205
+ ```
206
+ DiscoveryEnrichment states:
207
+ absent → populated (after user provides Step 1 input and enrichment completes)
208
+ populated → updated (if user re-runs Step 1; enrichment is replaced, not merged)
209
+ ```
210
+
211
+ **Validation rules**:
212
+ - All fields are optional; a completely empty `DiscoveryEnrichment` is valid (means enrichment was attempted but returned no results or was declined).
213
+ - `enrichedAt` must be a valid ISO 8601 string when present.
214
+ - `sourcesUsed` entries must be lowercase strings (e.g., `'websearch'`, `'workiq'`).
215
+ - Maximum 10 items per array field to avoid unbounded session growth.
216
+
217
+ ---
218
+
219
+ ## Entity 5: McpManager (Extended)
220
+
221
+ **Purpose**: Existing class extended with `callTool()` implementation and transport registry.
222
+
223
+ ### New Fields
224
+
225
+ | Field | Type | Description |
226
+ |-------|------|-------------|
227
+ | `transports` | `Map<string, McpTransport>` | One transport per connected server name |
228
+ | `defaultTimeouts` | `Record<string, number>` | Default timeout per server (30s or 60s) |
229
+
230
+ ### New Methods
231
+
232
+ ```typescript
233
+ /**
234
+ * Call a tool on a named MCP server.
235
+ * Creates and caches a transport for the server on first call.
236
+ * Applies retry policy for transient errors.
237
+ *
238
+ * @throws Error if serverName not in config
239
+ * @throws McpTransportError if tool call fails after retries
240
+ */
241
+ async callTool(
242
+ serverName: string,
243
+ toolName: string,
244
+ args: Record<string, unknown>,
245
+ options?: { timeoutMs?: number; retryOnTransient?: boolean }
246
+ ): Promise<Record<string, unknown>>;
247
+
248
+ /**
249
+ * Disconnect all active transports. Call on process exit.
250
+ */
251
+ async disconnectAll(): Promise<void>;
252
+ ```
253
+
254
+ ### Transport Registry Rules
255
+
256
+ - Transports are lazily created on first `callTool()` for a server.
257
+ - `StdioMcpTransport` servers: subprocess is started and kept alive for the session.
258
+ - `HttpMcpTransport` servers: stateless; no persistent connection to manage.
259
+ - `markConnected()` is called after a successful `initialize` handshake for stdio, or after a successful HTTP call for HTTP servers.
260
+ - `markDisconnected()` is called when a transport errors or disconnects.
261
+
262
+ ---
263
+
264
+ ## Entity 6: DiscoveryState (Extended)
265
+
266
+ **Existing entity** in `src/shared/schemas/session.ts`.
267
+
268
+ ### Change
269
+
270
+ Add `enrichment?: DiscoveryEnrichment` field to the existing `DiscoveryState` Zod schema.
271
+
272
+ ```typescript
273
+ // Before:
274
+ export const DiscoveryStateSchema = z.object({
275
+ steps: z.record(z.string(), z.unknown()),
276
+ currentStep: z.number(),
277
+ // ...
278
+ });
279
+
280
+ // After: (add one field)
281
+ export const DiscoveryStateSchema = z.object({
282
+ steps: z.record(z.string(), z.unknown()),
283
+ currentStep: z.number(),
284
+ // ...
285
+ enrichment: DiscoveryEnrichmentSchema.optional(),
286
+ });
287
+ ```
288
+
289
+ **Backward compatibility**: The field is optional; existing sessions without enrichment remain valid and parse without errors.
290
+
291
+ ---
292
+
293
+ ## Entity Relationships Diagram
294
+
295
+ ```
296
+ McpConfig (loaded from .vscode/mcp.json)
297
+ └── servers: Record<string, McpServerConfig>
298
+ ├── StdioServerConfig → StdioMcpTransport (spawns subprocess)
299
+ └── HttpServerConfig → HttpMcpTransport (stateless fetch)
300
+
301
+ McpManager
302
+ ├── config: McpConfig
303
+ ├── transports: Map<serverName, McpTransport>
304
+ └── callTool(serverName, toolName, args)
305
+ ├── withRetry (retryPolicy.ts)
306
+ └── transport.callTool(toolName, args, timeoutMs)
307
+ └── returns: ToolCallResponse
308
+
309
+ GitHubMcpAdapter
310
+ └── mcpManager.callTool('github', ...) → ToolCallResponse
311
+
312
+ McpContextEnricher
313
+ ├── mcpManager.callTool('context7', 'resolve-library-id', ...) → ToolCallResponse
314
+ ├── mcpManager.callTool('context7', 'query-docs', ...) → ToolCallResponse
315
+ ├── mcpManager.callTool('azure', 'documentation', ...) → ToolCallResponse
316
+ └── mcpManager.callTool('websearch', 'search', ...) → ToolCallResponse
317
+
318
+ DiscoveryEnricher
319
+ ├── webSearch.searchWeb(...) → WebSearchResult
320
+ └── mcpManager.callTool('workiq', ...) → ToolCallResponse
321
+ → DiscoveryEnrichment stored in WorkshopSession.discovery.enrichment
322
+
323
+ WorkshopSession
324
+ └── discovery: DiscoveryState
325
+ └── enrichment?: DiscoveryEnrichment ← NEW FIELD
326
+ ```