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,220 @@
1
+ # Contract: MCP Context Enricher (Real Integration)
2
+
3
+ **Feature**: 003-mcp-transport-integration
4
+ **Module**: `src/develop/mcpContextEnricher.ts`
5
+ **Status**: Authoritative design document (replaces stub behavior from Feature 002)
6
+
7
+ ---
8
+
9
+ ## Overview
10
+
11
+ `McpContextEnricher` conditionally queries three MCP servers to enrich LLM iteration prompts:
12
+
13
+ 1. **Context7** — library documentation for PoC dependencies
14
+ 2. **Azure MCP** — architecture guidance when plan references Azure services
15
+ 3. **Web Search** — solutions to failing tests when stuck (2+ consecutive iterations)
16
+
17
+ All three methods use real MCP `callTool()` invocations (replacing hardcoded strings). All degrade gracefully when their respective servers are unavailable.
18
+
19
+ ---
20
+
21
+ ## queryContext7() Contract
22
+
23
+ ### When Invoked
24
+
25
+ Only when:
26
+ - `mcpManager.isAvailable('context7')` is `true`
27
+ - `dependencies.length > 0`
28
+
29
+ ### Tool Call Sequence (per dependency)
30
+
31
+ **Step 1: Resolve library ID**
32
+
33
+ ```typescript
34
+ mcpManager.callTool('context7', 'resolve-library-id', {
35
+ libraryName: dep, // e.g., 'express', 'zod'
36
+ }, { timeoutMs: 30_000 })
37
+ ```
38
+
39
+ Response field extraction for `libraryId`:
40
+ - `response.libraryId` (primary)
41
+ - `response.id` (fallback)
42
+ - If neither present: skip to fallback link (do not throw)
43
+
44
+ **Step 2: Query docs (only if libraryId resolved)**
45
+
46
+ ```typescript
47
+ mcpManager.callTool('context7', 'query-docs', {
48
+ libraryId, // e.g., '/expressjs/express'
49
+ topic: dep, // hint to focus the query
50
+ }, { timeoutMs: 30_000 })
51
+ ```
52
+
53
+ Response field extraction for documentation text:
54
+ - `response.content` (string, primary)
55
+ - `response.text` (string, fallback)
56
+ - If neither present: use fallback link
57
+
58
+ ### Dependency Filter Rules
59
+
60
+ | Dependency | Skip? |
61
+ |------------|-------|
62
+ | Starts with `@types/` | ✅ Skip (type-only package) |
63
+ | `typescript` | ✅ Skip (well-known, no runtime docs needed) |
64
+ | `vitest` | ✅ Skip (test-only) |
65
+ | `node` | ✅ Skip |
66
+ | First 5 non-skipped deps only | Process (others skipped to limit tokens) |
67
+
68
+ ### Fallback
69
+
70
+ When Context7 is unavailable OR a dependency resolution fails:
71
+ ```
72
+ - **{dep}**: See https://www.npmjs.com/package/{dep} for API documentation
73
+ ```
74
+
75
+ ### Output Format
76
+
77
+ ```
78
+ - **express**:
79
+ {documentation text from Context7}
80
+
81
+ - **zod**:
82
+ {documentation text from Context7}
83
+ ```
84
+
85
+ ---
86
+
87
+ ## queryAzureMcp() Contract
88
+
89
+ ### When Invoked
90
+
91
+ Only when:
92
+ - `mcpManager.isAvailable('azure')` is `true`
93
+ - `architectureNotes` contains at least one Azure keyword (existing detection logic)
94
+
95
+ ### Tool Call
96
+
97
+ ```typescript
98
+ mcpManager.callTool('azure', 'documentation', {
99
+ query: `Best practices for ${detectedKeywords.join(', ')} in Azure`,
100
+ }, { timeoutMs: 30_000 })
101
+ ```
102
+
103
+ Response field extraction:
104
+ - `response.content` (string, primary)
105
+ - `response.text` (string, fallback)
106
+ - If neither: fall through to static guidance
107
+
108
+ ### Fallback (when Azure MCP unavailable or call fails)
109
+
110
+ Return static guidance string (existing behavior):
111
+ ```
112
+ Detected Azure services: {detected.join(', ')}
113
+ Use the @azure/identity DefaultAzureCredential for authentication.
114
+ Prefer connection strings from environment variables (never hardcode).
115
+ ```
116
+
117
+ ---
118
+
119
+ ## queryWebSearch() Contract
120
+
121
+ ### When Invoked
122
+
123
+ Only when:
124
+ - `isWebSearchConfigured()` returns `true` (env var `AZURE_AI_FOUNDRY_ENDPOINT` set)
125
+ - `stuckIterations >= 2`
126
+ - `failingTests.length > 0`
127
+
128
+ ### Invocation Priority
129
+
130
+ 1. **Prefer MCP-based search** (if `mcpManager.isAvailable('websearch')`):
131
+ ```typescript
132
+ mcpManager.callTool('websearch', 'search', {
133
+ query: `how to fix: ${failingTests.slice(0, 3).join('; ')}`,
134
+ }, { timeoutMs: 30_000 })
135
+ ```
136
+ Response: `response.content` or `response.text`
137
+
138
+ 2. **Fall back to Azure AI Foundry bridge** (existing `webSearch.ts` implementation):
139
+ ```typescript
140
+ // Already implemented in src/mcp/webSearch.ts
141
+ webSearchClient.search(query)
142
+ ```
143
+
144
+ ### Output Format
145
+
146
+ When results are returned:
147
+ ```
148
+ Search results for: "{query}"
149
+
150
+ {formatted search results}
151
+ ```
152
+
153
+ When no results available:
154
+ ```
155
+ Web search for: "{query}" — no results available in this environment.
156
+ ```
157
+
158
+ ---
159
+
160
+ ## enrich() Orchestration Contract
161
+
162
+ ```typescript
163
+ async enrich(options: EnricherOptions): Promise<EnrichedContext>
164
+ ```
165
+
166
+ ### Execution Order
167
+
168
+ 1. Context7 query (parallel-safe, independent)
169
+ 2. Azure MCP query (parallel-safe, independent)
170
+ 3. Web search (only if stuck — gated by `stuckIterations >= 2`)
171
+
172
+ **Parallelism**: Queries 1 and 2 MAY be run concurrently with `Promise.allSettled()` to reduce latency. Web search runs sequentially after both to avoid unnecessary API calls when Context7 already unblocks the LLM.
173
+
174
+ ### EnrichedContext Assembly
175
+
176
+ ```typescript
177
+ {
178
+ libraryDocs, // from Context7 (undefined if unavailable)
179
+ azureGuidance, // from Azure MCP (undefined if unavailable)
180
+ webSearchResults, // from web search (undefined if not stuck or unavailable)
181
+ combined: parts.join('\n\n'), // non-empty parts assembled as markdown sections
182
+ }
183
+ ```
184
+
185
+ ---
186
+
187
+ ## Graceful Degradation Matrix
188
+
189
+ | Server | Unavailable Behavior |
190
+ |--------|---------------------|
191
+ | `context7` | Returns npm links instead of real docs. `combined` omits Context7 section. |
192
+ | `azure` | Returns static guidance string. `combined` uses static string. |
193
+ | `websearch` | Falls back to Azure AI Foundry bridge. If also unavailable, returns placeholder string. |
194
+ | All unavailable | `combined` is empty string. Ralph Loop continues with LLM's baseline knowledge. |
195
+
196
+ ---
197
+
198
+ ## Acceptance Tests
199
+
200
+ | Test | Type | Description |
201
+ |------|------|-------------|
202
+ | `queryContext7 calls resolve-library-id for each dependency` | unit | Verify tool calls dispatched |
203
+ | `queryContext7 uses libraryId from response.libraryId` | unit | Primary field extraction |
204
+ | `queryContext7 uses libraryId from response.id as fallback` | unit | Fallback field extraction |
205
+ | `queryContext7 skips @types/* dependencies` | unit | Filter rule |
206
+ | `queryContext7 skips typescript and vitest dependencies` | unit | Filter rule |
207
+ | `queryContext7 processes max 5 non-skipped deps` | unit | Limit rule |
208
+ | `queryContext7 returns npm link when resolve-library-id fails` | unit | Graceful degradation |
209
+ | `queryContext7 returns npm link when libraryId missing` | unit | No libraryId in response |
210
+ | `queryContext7 returns undefined when context7 unavailable` | unit | `isAvailable('context7')` false |
211
+ | `queryAzureMcp calls documentation tool with detected keywords` | unit | Tool dispatched with correct query |
212
+ | `queryAzureMcp extracts content from response.content` | unit | Primary field |
213
+ | `queryAzureMcp falls back to static guidance on callTool error` | unit | Graceful degradation |
214
+ | `queryAzureMcp returns undefined when azure unavailable` | unit | `isAvailable('azure')` false |
215
+ | `queryWebSearch calls websearch.search when server available` | unit | MCP tool dispatch |
216
+ | `queryWebSearch uses Azure AI Foundry bridge as fallback` | unit | Bridge used when MCP unavailable |
217
+ | `queryWebSearch returns undefined when not configured` | unit | `isWebSearchConfigured()` false |
218
+ | `enrich returns combined string with all available contexts` | unit | All three sections present |
219
+ | `enrich skips web search when stuckIterations < 2` | unit | Gate enforced |
220
+ | `enrich handles all servers unavailable gracefully` | unit | Empty combined, no throws |
@@ -0,0 +1,267 @@
1
+ # Contract: Discovery Phase Enrichment
2
+
3
+ **Feature**: 003-mcp-transport-integration
4
+ **Modules**: `src/phases/discoveryEnricher.ts`, `src/shared/schemas/session.ts`
5
+ **Status**: Authoritative design document
6
+
7
+ ---
8
+
9
+ ## Overview
10
+
11
+ After the user provides company and team information in Step 1 of the discovery workshop, the system optionally enriches the session with:
12
+ 1. **Web search results** — recent company news, competitor activity, industry trends
13
+ 2. **WorkIQ insights** — internal team collaboration patterns and expertise (requires explicit user consent and WorkIQ availability)
14
+
15
+ Enrichment is stored in `WorkshopSession.discovery.enrichment` and is referenced by subsequent phases (ideation, planning) to improve PoC relevance.
16
+
17
+ ---
18
+
19
+ ## DiscoveryEnricher Interface
20
+
21
+ ```typescript
22
+ // src/phases/discoveryEnricher.ts
23
+
24
+ export interface DiscoveryEnricherOptions {
25
+ /** Company and team summary from Step 1 (used to build search queries) */
26
+ companySummary: string;
27
+ /** MCP manager for WorkIQ tool calls */
28
+ mcpManager: McpManager;
29
+ /** IO for permission prompts and progress messages */
30
+ io: LoopIO;
31
+ /** Activity spinner for visual feedback */
32
+ spinner?: ActivitySpinner;
33
+ /** Web search client (defaults to production webSearch module) */
34
+ webSearchClient?: WebSearchClient;
35
+ }
36
+
37
+ export class DiscoveryEnricher {
38
+ /**
39
+ * Run the full enrichment flow: web search + optional WorkIQ.
40
+ * Returns a populated DiscoveryEnrichment object (may have empty fields
41
+ * if all enrichment sources are unavailable).
42
+ */
43
+ async enrich(options: DiscoveryEnricherOptions): Promise<DiscoveryEnrichment>;
44
+
45
+ /**
46
+ * Run only the web search enrichment step.
47
+ * Does not prompt the user.
48
+ */
49
+ async enrichFromWebSearch(
50
+ companySummary: string,
51
+ webSearchClient: WebSearchClient,
52
+ ): Promise<Partial<DiscoveryEnrichment>>;
53
+
54
+ /**
55
+ * Run only the WorkIQ enrichment step.
56
+ * Prompts the user for consent before making any WorkIQ calls.
57
+ * Returns empty partial if user declines or WorkIQ unavailable.
58
+ */
59
+ async enrichFromWorkIQ(
60
+ companySummary: string,
61
+ mcpManager: McpManager,
62
+ io: LoopIO,
63
+ ): Promise<Partial<DiscoveryEnrichment>>;
64
+ }
65
+ ```
66
+
67
+ ---
68
+
69
+ ## enrich() Orchestration Flow
70
+
71
+ ```
72
+ Step 1 input collected
73
+
74
+
75
+ [Web Search Available?] ──no──► skip, continue
76
+ │ yes
77
+
78
+ io.writeActivity('Searching for recent company and industry context...')
79
+ spinner.start('Enriching discovery context')
80
+
81
+
82
+ enrichFromWebSearch(companySummary)
83
+
84
+
85
+ [WorkIQ MCP Available?] ──no──► skip to session save
86
+ │ yes
87
+
88
+ io.writeActivity('WorkIQ is available — it can analyze your team's internal context.')
89
+ io.prompt('May sofIA query WorkIQ for team insights? [y/N]')
90
+
91
+ ├── no/timeout ──► skip WorkIQ
92
+
93
+ ▼ yes
94
+ enrichFromWorkIQ(companySummary)
95
+
96
+
97
+ Merge partial enrichments → DiscoveryEnrichment
98
+ Set enrichment.enrichedAt = new Date().toISOString()
99
+ Set enrichment.sourcesUsed = ['websearch'?, 'workiq'?]
100
+ session.discovery.enrichment = enrichment
101
+ onSessionUpdate(session)
102
+ spinner.stop()
103
+ io.writeActivity('Discovery context enriched ✓')
104
+ ```
105
+
106
+ ---
107
+
108
+ ## enrichFromWebSearch() Contract
109
+
110
+ ### Web Search Query Strategy
111
+
112
+ Three sequential queries (or as many as return results before timeout):
113
+
114
+ | Query | Purpose |
115
+ |-------|---------|
116
+ | `"${company name} recent news 2024 2025"` | Company news |
117
+ | `"${company name} competitors market 2024"` | Competitor activity |
118
+ | `"${industry or domain} AI trends 2025"` | Industry trends |
119
+
120
+ The company name and industry are extracted from `companySummary` via simple keyword heuristic (first quoted proper noun, or first capitalized multi-word sequence).
121
+
122
+ ### Response Mapping
123
+
124
+ ```typescript
125
+ // From WebSearchResult:
126
+ {
127
+ companyNews: results[0]?.results.map(r => `${r.title}: ${r.snippet}`),
128
+ competitorInfo: results[1]?.results.map(r => `${r.title}: ${r.snippet}`),
129
+ industryTrends: results[2]?.results.map(r => `${r.title}: ${r.snippet}`),
130
+ webSearchResults: [results].flatMap(r => r.results).map(r => r.snippet).join('\n'),
131
+ }
132
+ ```
133
+
134
+ Array fields are capped at 10 items each.
135
+
136
+ ### Graceful Degradation
137
+
138
+ | Condition | Behavior |
139
+ |-----------|---------|
140
+ | Web search not configured (`isWebSearchConfigured()` false) | Return `{}` immediately, no prompt shown |
141
+ | `WebSearchResult.degraded` is `true` | Return `{}` with no error surfaced to user |
142
+ | Individual query throws | Log debug, continue with remaining queries |
143
+
144
+ ---
145
+
146
+ ## enrichFromWorkIQ() Contract
147
+
148
+ ### Permission Gate
149
+
150
+ **REQUIRED**: Show a consent prompt before any WorkIQ call:
151
+
152
+ ```
153
+ sofIA can query WorkIQ to analyze your team's internal context
154
+ (meeting patterns, expertise areas, documentation gaps).
155
+ This requires access to your Microsoft 365 tenant.
156
+
157
+ May sofIA access WorkIQ for team insights? (y/N)
158
+ ```
159
+
160
+ If the user responds `n` or `N` (or presses Enter for the default):
161
+ - Return `{}` immediately
162
+ - Do NOT call any WorkIQ tool
163
+ - Log at `info` level: `'User declined WorkIQ enrichment'`
164
+
165
+ ### WorkIQ Tool Call
166
+
167
+ ```typescript
168
+ mcpManager.callTool('workiq', 'analyze_team', {
169
+ summary: companySummary,
170
+ focus: ['expertise', 'collaboration', 'documentation'],
171
+ }, { timeoutMs: 30_000 })
172
+ ```
173
+
174
+ Response field extraction:
175
+ - `response.teamExpertise` → `workiqInsights.teamExpertise`
176
+ - `response.collaborationPatterns` → `workiqInsights.collaborationPatterns`
177
+ - `response.documentationGaps` → `workiqInsights.documentationGaps`
178
+ - `response.insights` (fallback, split by newline) → all three fields
179
+
180
+ ### Graceful Degradation
181
+
182
+ | Condition | Behavior |
183
+ |-----------|---------|
184
+ | `mcpManager.isAvailable('workiq')` false | Return `{}`, no prompt shown, log info `'WorkIQ not available'` |
185
+ | `callTool` throws `auth-failure` | Return `{}`, show message: `'WorkIQ authentication required — skipping team insights'` |
186
+ | `callTool` throws timeout/connection error | Return `{}`, log warn, show message: `'WorkIQ temporarily unavailable — skipping team insights'` |
187
+ | User declines consent | Return `{}`, no WorkIQ calls |
188
+
189
+ ---
190
+
191
+ ## Session Schema Extension
192
+
193
+ ```typescript
194
+ // src/shared/schemas/session.ts
195
+
196
+ // DiscoveryEnrichmentSchema (new)
197
+ export const DiscoveryEnrichmentSchema = z.object({
198
+ webSearchResults: z.string().optional(),
199
+ companyNews: z.array(z.string()).max(10).optional(),
200
+ competitorInfo: z.array(z.string()).max(10).optional(),
201
+ industryTrends: z.array(z.string()).max(10).optional(),
202
+ workiqInsights: z.object({
203
+ teamExpertise: z.array(z.string()).max(10).optional(),
204
+ collaborationPatterns: z.array(z.string()).max(10).optional(),
205
+ documentationGaps: z.array(z.string()).max(10).optional(),
206
+ }).optional(),
207
+ enrichedAt: z.string().datetime().optional(),
208
+ sourcesUsed: z.array(z.string()).optional(),
209
+ });
210
+
211
+ // DiscoveryStateSchema (modified — add enrichment field)
212
+ export const DiscoveryStateSchema = z.object({
213
+ // ... existing fields ...
214
+ enrichment: DiscoveryEnrichmentSchema.optional(),
215
+ });
216
+ ```
217
+
218
+ **Backward compatibility**: `enrichment` is optional. Sessions from Feature 001/002 parse without errors.
219
+
220
+ ---
221
+
222
+ ## Downstream Phase Usage
223
+
224
+ When `session.discovery.enrichment` is non-empty, the enrichment is injected into the ideation and planning phase prompts:
225
+
226
+ ```markdown
227
+ ## Discovery Context (from market research)
228
+
229
+ **Recent Company News**:
230
+ - {companyNews[0]}
231
+ - {companyNews[1]}
232
+
233
+ **Competitive Landscape**:
234
+ - {competitorInfo[0]}
235
+
236
+ **Industry Trends**:
237
+ - {industryTrends[0]}
238
+
239
+ **Internal Team Context** (from WorkIQ):
240
+ - Expertise: {workiqInsights.teamExpertise.join(', ')}
241
+ - Collaboration: {workiqInsights.collaborationPatterns.join(', ')}
242
+ ```
243
+
244
+ This injection is the responsibility of the ideation/planning phase prompt builder, not `DiscoveryEnricher`.
245
+
246
+ ---
247
+
248
+ ## Acceptance Tests
249
+
250
+ | Test | Type | Description |
251
+ |------|------|-------------|
252
+ | `enrich runs web search when configured` | unit | webSearchClient called with company queries |
253
+ | `enrich skips web search when not configured` | unit | Returns without querying |
254
+ | `enrich shows WorkIQ prompt when available` | unit | io.prompt called before WorkIQ |
255
+ | `enrich calls WorkIQ when user consents` | unit | callTool('workiq', 'analyze_team', ...) dispatched |
256
+ | `enrich skips WorkIQ when user declines` | unit | No callTool for workiq |
257
+ | `enrich skips WorkIQ when not available` | unit | No prompt shown, no callTool |
258
+ | `enrich stores enrichedAt timestamp` | unit | ISO string set |
259
+ | `enrich stores sourcesUsed correctly` | unit | Reflects which sources ran |
260
+ | `enrichFromWebSearch builds three queries from companySummary` | unit | Query construction |
261
+ | `enrichFromWebSearch caps array fields at 10 items` | unit | Boundary check |
262
+ | `enrichFromWebSearch returns empty on degraded search` | unit | Graceful degradation |
263
+ | `enrichFromWorkIQ returns empty on auth-failure` | unit | Auth error handling |
264
+ | `enrichFromWorkIQ returns empty on timeout` | unit | Timeout handling |
265
+ | `enrichFromWorkIQ returns empty on user decline` | unit | No-consent path |
266
+ | `discoveryEnricher saves enrichment to session via onSessionUpdate` | integration | Session persistence |
267
+ | `phaseHandler injects enrichment into ideation prompt` | integration | Downstream usage |
@@ -0,0 +1,149 @@
1
+ # Contract: GitHub MCP Adapter (Real Integration)
2
+
3
+ **Feature**: 003-mcp-transport-integration
4
+ **Module**: `src/develop/githubMcpAdapter.ts`
5
+ **Status**: Authoritative design document (replaces stub behavior from Feature 002)
6
+
7
+ ---
8
+
9
+ ## Overview
10
+
11
+ `GitHubMcpAdapter` wraps two GitHub MCP tool calls — `create_repository` and `push_files` — and applies graceful degradation when the GitHub MCP server is unavailable. This contract defines the real behavior replacing the stubs introduced in Feature 002.
12
+
13
+ ---
14
+
15
+ ## createRepository()
16
+
17
+ ### Call
18
+
19
+ ```typescript
20
+ mcpManager.callTool('github', 'create_repository', {
21
+ name: options.name, // repository name (slug)
22
+ description: options.description ?? '',
23
+ private: options.private ?? true,
24
+ }, { timeoutMs: 60_000 })
25
+ ```
26
+
27
+ ### Response Mapping
28
+
29
+ The GitHub MCP `create_repository` tool returns a JSON object representing the created repository. Field extraction priority:
30
+
31
+ | Field to Extract | Try These Response Keys (in order) |
32
+ |------------------|------------------------------------|
33
+ | `repoUrl` | `response.html_url`, `response.url`, `response.clone_url` |
34
+ | `repoName` | `response.name`, `response.full_name`, or fallback to `options.name` |
35
+
36
+ ### Success Return
37
+
38
+ ```typescript
39
+ { available: true, repoUrl: 'https://github.com/org/repo', repoName: 'repo' }
40
+ ```
41
+
42
+ ### Failure Return
43
+
44
+ ```typescript
45
+ { available: false, reason: '<error message>' }
46
+ ```
47
+
48
+ ### Conditions Returning `{ available: false }`
49
+
50
+ | Condition | Reason Logged |
51
+ |-----------|---------------|
52
+ | `isAvailable()` is `false` | `'GitHub MCP not available'` |
53
+ | `callTool` throws `McpTransportError` | Error message from transport |
54
+ | Response missing `html_url`, `url`, and `clone_url` | `'MCP response missing repository URL'` |
55
+
56
+ ---
57
+
58
+ ## pushFiles()
59
+
60
+ ### Pre-processing (ralphLoop.ts responsibility)
61
+
62
+ Before calling `pushFiles()`, the caller (Ralph Loop) MUST:
63
+ 1. Read each file's content from disk using `readFile(resolve(outputDir, filePath), 'utf-8')`.
64
+ 2. Skip files that fail to read — log a warning and omit them from the push.
65
+ 3. Skip files outside the output directory (path traversal check using `isPathWithinDirectory`).
66
+
67
+ The `PushFilesOptions.files` array MUST contain actual file content — never empty strings.
68
+
69
+ ### Call
70
+
71
+ ```typescript
72
+ mcpManager.callTool('github', 'push_files', {
73
+ owner: extractOwnerFromUrl(options.repoUrl), // extracted from repo URL
74
+ repo: extractRepoFromUrl(options.repoUrl), // extracted from repo URL
75
+ branch: options.branch ?? 'main',
76
+ message: options.commitMessage,
77
+ files: options.files.map(f => ({
78
+ path: f.path,
79
+ content: f.content, // actual file content (UTF-8 text)
80
+ })),
81
+ }, { timeoutMs: 60_000 })
82
+ ```
83
+
84
+ ### Response Mapping
85
+
86
+ | Field to Extract | Try These Response Keys |
87
+ |-----------------|------------------------|
88
+ | `commitSha` | `response.sha`, `response.commit.sha` |
89
+
90
+ ### Success Return
91
+
92
+ ```typescript
93
+ { available: true, commitSha: 'abc123def456' }
94
+ // commitSha is optional — may be undefined if the server doesn't return it
95
+ ```
96
+
97
+ ### Failure Return
98
+
99
+ ```typescript
100
+ { available: false, reason: '<error message>' }
101
+ ```
102
+
103
+ ---
104
+
105
+ ## Post-Scaffold Push (RalphLoop Responsibility)
106
+
107
+ The Ralph Loop is responsible for an **initial scaffold push** immediately after npm install completes and before entering the iteration loop:
108
+
109
+ ```
110
+ scaffold → npm install → push scaffold files → iteration 1 → iteration 2 → ...
111
+ ```
112
+
113
+ **When to push**: Only if `githubAdapter.isAvailable()` AND a repo was created (non-null `repoUrl`).
114
+
115
+ **Files to push**: All `scaffoldResult.createdFiles` (relative paths within `outputDir`).
116
+
117
+ **Content**: Read from disk at `resolve(outputDir, filePath)` — same pattern as iteration pushes.
118
+
119
+ **On failure**: Log warning and continue — scaffold push failure is not fatal.
120
+
121
+ ---
122
+
123
+ ## Graceful Degradation Rules
124
+
125
+ 1. When GitHub MCP is unavailable (`isAvailable()` returns `false`): both methods return `{ available: false }` immediately without attempting any tool call.
126
+ 2. When a tool call throws any error: catch, log at `warn` level, return `{ available: false, reason: err.message }`.
127
+ 3. When `createRepository` fails: the Ralph Loop continues with local-only output (no remote repo).
128
+ 4. When `pushFiles` fails: the local PoC is intact; the remote repo may be stale. Log the failure with iteration number.
129
+
130
+ ---
131
+
132
+ ## Acceptance Tests
133
+
134
+ | Test | Type | Description |
135
+ |------|------|-------------|
136
+ | `createRepository dispatches create_repository tool call` | unit | Verify callTool called with correct server/tool/args |
137
+ | `createRepository extracts repoUrl from html_url response field` | unit | Mock response with `html_url` |
138
+ | `createRepository extracts repoUrl from url response field` | unit | Mock response with `url` (fallback) |
139
+ | `createRepository returns available:false when MCP unavailable` | unit | `isAvailable()` returns false |
140
+ | `createRepository returns available:false on callTool error` | unit | Transport throws |
141
+ | `createRepository returns available:false when response has no URL` | unit | Mock response missing all URL fields |
142
+ | `pushFiles dispatches push_files with actual content` | unit | Verify `files[n].content` is non-empty string |
143
+ | `pushFiles extracts commitSha from response.sha` | unit | Mock response with `sha` |
144
+ | `pushFiles extracts commitSha from response.commit.sha` | unit | Mock response with nested sha |
145
+ | `pushFiles returns available:false when MCP unavailable` | unit | `isAvailable()` returns false |
146
+ | `pushFiles returns available:false on callTool error` | unit | Transport throws |
147
+ | `ralphLoop pushFiles sends non-empty file content` | integration | Verify content !== '' for all pushed files |
148
+ | `ralphLoop pushes scaffold files after npm install` | integration | Scaffold push happens before iteration 1 |
149
+ | `ralphLoop skips out-of-bounds paths before pushFiles` | integration | Path traversal attempt is logged and skipped |