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,115 @@
1
+ /**
2
+ * Integration test: Export fallback flow.
3
+ *
4
+ * Tests the full export pipeline with null structured data but present
5
+ * conversation turns — verifies that all phase files are generated.
6
+ */
7
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
8
+ import { mkdtemp, rm, readFile, readdir } from 'node:fs/promises';
9
+ import { join } from 'node:path';
10
+ import { tmpdir } from 'node:os';
11
+
12
+ import { exportSession } from '../../src/sessions/exportWriter.js';
13
+ import type { WorkshopSession } from '../../src/shared/schemas/session.js';
14
+
15
+ let tmpDir: string;
16
+
17
+ beforeEach(async () => {
18
+ tmpDir = await mkdtemp(join(tmpdir(), 'sofia-export-fallback-'));
19
+ });
20
+
21
+ afterEach(async () => {
22
+ await rm(tmpDir, { recursive: true, force: true });
23
+ });
24
+
25
+ describe('export fallback flow', () => {
26
+ it('generates 6 markdown files when all phases have turns but no structured data', async () => {
27
+ const now = new Date().toISOString();
28
+ const phases = ['Discover', 'Ideate', 'Design', 'Select', 'Plan', 'Develop'] as const;
29
+
30
+ const turns = phases.flatMap((phase, i) => [
31
+ {
32
+ phase,
33
+ sequence: i * 2 + 1,
34
+ role: 'user' as const,
35
+ content: `Tell me about the ${phase} phase`,
36
+ timestamp: now,
37
+ },
38
+ {
39
+ phase,
40
+ sequence: i * 2 + 2,
41
+ role: 'assistant' as const,
42
+ content: `Here is information about the ${phase} phase.`,
43
+ timestamp: now,
44
+ },
45
+ ]);
46
+
47
+ const session: WorkshopSession = {
48
+ sessionId: 'fallback-test',
49
+ schemaVersion: '1.0.0',
50
+ createdAt: now,
51
+ updatedAt: now,
52
+ phase: 'Complete',
53
+ status: 'Completed',
54
+ participants: [],
55
+ artifacts: { generatedFiles: [] },
56
+ turns,
57
+ // Discover has conversation fallback built-in
58
+ businessContext: {
59
+ businessDescription: 'Test Company',
60
+ challenges: ['Testing'],
61
+ },
62
+ // All other structured fields are null/undefined
63
+ };
64
+
65
+ await exportSession(session, tmpDir);
66
+
67
+ const files = await readdir(tmpDir);
68
+ expect(files).toContain('discover.md');
69
+ expect(files).toContain('ideate.md');
70
+ expect(files).toContain('design.md');
71
+ expect(files).toContain('select.md');
72
+ expect(files).toContain('plan.md');
73
+ expect(files).toContain('develop.md');
74
+ expect(files).toContain('summary.json');
75
+
76
+ // Verify each file has conversation content
77
+ for (const phase of phases) {
78
+ const content = await readFile(join(tmpDir, `${phase.toLowerCase()}.md`), 'utf-8');
79
+ expect(content).toContain('## Conversation');
80
+ }
81
+
82
+ // Verify summary.json lists all files
83
+ const summaryRaw = await readFile(join(tmpDir, 'summary.json'), 'utf-8');
84
+ const summary = JSON.parse(summaryRaw) as { files: Array<{ path: string }>; highlights?: string[] };
85
+ const mdFiles = summary.files.filter((f) => f.path.endsWith('.md'));
86
+ expect(mdFiles.length).toBe(6);
87
+
88
+ // Verify highlights exist
89
+ expect(summary.highlights).toBeDefined();
90
+ expect(summary.highlights!.length).toBeGreaterThan(0);
91
+ });
92
+
93
+ it('returns null for phase with neither structured data nor turns', async () => {
94
+ const now = new Date().toISOString();
95
+ const session: WorkshopSession = {
96
+ sessionId: 'empty-test',
97
+ schemaVersion: '1.0.0',
98
+ createdAt: now,
99
+ updatedAt: now,
100
+ phase: 'Discover',
101
+ status: 'Active',
102
+ participants: [],
103
+ artifacts: { generatedFiles: [] },
104
+ turns: [],
105
+ };
106
+
107
+ await exportSession(session, tmpDir);
108
+ const files = await readdir(tmpDir);
109
+
110
+ // Only summary.json should be generated — no phase files
111
+ expect(files).toContain('summary.json');
112
+ const mdFiles = files.filter((f) => f.endsWith('.md'));
113
+ expect(mdFiles).toHaveLength(0);
114
+ });
115
+ });
@@ -0,0 +1,231 @@
1
+ /**
2
+ * T042: Integration test for MCP degradation flow.
3
+ *
4
+ * Configures McpManager with servers marked unavailable (or stub transports
5
+ * that throw), runs GitHubMcpAdapter + McpContextEnricher calls, and asserts
6
+ * graceful degradation (no throws; adapters return { available: false, reason }
7
+ * or fallback context) per US1 Acceptance Scenario 4 and FR-013.
8
+ */
9
+ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
10
+
11
+ import { McpManager } from '../../src/mcp/mcpManager.js';
12
+ import type { McpConfig } from '../../src/mcp/mcpManager.js';
13
+ import { GitHubMcpAdapter } from '../../src/develop/githubMcpAdapter.js';
14
+ import { McpContextEnricher } from '../../src/develop/mcpContextEnricher.js';
15
+
16
+ vi.mock('../../src/mcp/webSearch.js', () => ({
17
+ isWebSearchConfigured: vi.fn(() => false),
18
+ }));
19
+
20
+ // ── Helpers ──────────────────────────────────────────────────────────────────
21
+
22
+ function makeEmptyConfig(): McpConfig {
23
+ return { servers: {} };
24
+ }
25
+
26
+ function makeConfigWithServers(): McpConfig {
27
+ return {
28
+ servers: {
29
+ github: {
30
+ name: 'github',
31
+ type: 'http' as const,
32
+ url: 'https://api.github.com/mcp',
33
+ },
34
+ context7: {
35
+ name: 'context7',
36
+ type: 'stdio' as const,
37
+ command: 'npx',
38
+ args: ['-y', '@upstash/context7-mcp'],
39
+ },
40
+ azure: {
41
+ name: 'azure',
42
+ type: 'stdio' as const,
43
+ command: 'npx',
44
+ args: ['-y', '@azure/mcp'],
45
+ },
46
+ },
47
+ };
48
+ }
49
+
50
+ // ── Tests ────────────────────────────────────────────────────────────────────
51
+
52
+ describe('MCP Degradation Flow (integration)', () => {
53
+ let originalGithubToken: string | undefined;
54
+
55
+ beforeEach(() => {
56
+ originalGithubToken = process.env.GITHUB_TOKEN;
57
+ });
58
+
59
+ afterEach(() => {
60
+ if (originalGithubToken !== undefined) {
61
+ process.env.GITHUB_TOKEN = originalGithubToken;
62
+ } else {
63
+ delete process.env.GITHUB_TOKEN;
64
+ }
65
+ vi.restoreAllMocks();
66
+ });
67
+
68
+ describe('GitHubMcpAdapter graceful degradation', () => {
69
+ it('returns available:false when GitHub MCP is not configured', async () => {
70
+ const manager = new McpManager(makeEmptyConfig());
71
+ const adapter = new GitHubMcpAdapter(manager);
72
+
73
+ expect(adapter.isAvailable()).toBe(false);
74
+
75
+ const createResult = await adapter.createRepository({ name: 'test-poc' });
76
+ expect(createResult.available).toBe(false);
77
+ if (!createResult.available) {
78
+ expect(createResult.reason).toBeDefined();
79
+ }
80
+
81
+ const pushResult = await adapter.pushFiles({
82
+ repoUrl: 'https://github.com/acme/test',
83
+ files: [{ path: 'index.ts', content: 'hello' }],
84
+ commitMessage: 'init',
85
+ });
86
+ expect(pushResult.available).toBe(false);
87
+ if (!pushResult.available) {
88
+ expect(pushResult.reason).toBeDefined();
89
+ }
90
+ });
91
+
92
+ it('returns available:false when GitHub is configured but not connected', async () => {
93
+ const manager = new McpManager(makeConfigWithServers());
94
+ // Do NOT call markConnected — server is configured but unavailable
95
+ const adapter = new GitHubMcpAdapter(manager);
96
+
97
+ expect(adapter.isAvailable()).toBe(false);
98
+
99
+ const createResult = await adapter.createRepository({ name: 'test-poc' });
100
+ expect(createResult.available).toBe(false);
101
+ });
102
+
103
+ it('never throws from createRepository or pushFiles', async () => {
104
+ const manager = new McpManager(makeConfigWithServers());
105
+ manager.markConnected('github');
106
+
107
+ // Stub callTool to throw
108
+ vi.spyOn(manager, 'callTool').mockRejectedValue(new Error('network crash'));
109
+
110
+ const adapter = new GitHubMcpAdapter(manager);
111
+
112
+ // Should not throw
113
+ const createResult = await adapter.createRepository({ name: 'test-poc' });
114
+ expect(createResult.available).toBe(false);
115
+ if (!createResult.available) {
116
+ expect(createResult.reason).toBeDefined();
117
+ }
118
+
119
+ const pushResult = await adapter.pushFiles({
120
+ repoUrl: 'https://github.com/acme/test',
121
+ files: [{ path: 'index.ts', content: 'hello' }],
122
+ commitMessage: 'init',
123
+ });
124
+ expect(pushResult.available).toBe(false);
125
+ });
126
+ });
127
+
128
+ describe('McpContextEnricher graceful degradation', () => {
129
+ it('returns empty context when all services unavailable', async () => {
130
+ const manager = new McpManager(makeEmptyConfig());
131
+ const enricher = new McpContextEnricher(manager);
132
+
133
+ const result = await enricher.enrich({
134
+ dependencies: ['express', 'zod'],
135
+ architectureNotes: 'Use Azure Cosmos DB',
136
+ stuckIterations: 3,
137
+ failingTests: ['test fails with TypeError'],
138
+ });
139
+
140
+ expect(result.combined).toBe('');
141
+ expect(result.libraryDocs).toBeUndefined();
142
+ expect(result.azureGuidance).toBeUndefined();
143
+ expect(result.webSearchResults).toBeUndefined();
144
+ });
145
+
146
+ it('returns empty context when servers configured but not connected', async () => {
147
+ const manager = new McpManager(makeConfigWithServers());
148
+ // Not marking any server as connected
149
+ const enricher = new McpContextEnricher(manager);
150
+
151
+ const result = await enricher.enrich({
152
+ dependencies: ['express'],
153
+ architectureNotes: 'Use Azure Functions',
154
+ });
155
+
156
+ expect(result.combined).toBe('');
157
+ expect(result.libraryDocs).toBeUndefined();
158
+ expect(result.azureGuidance).toBeUndefined();
159
+ });
160
+
161
+ it('returns fallback context when callTool throws for all services', async () => {
162
+ const manager = new McpManager(makeConfigWithServers());
163
+ manager.markConnected('context7');
164
+ manager.markConnected('azure');
165
+
166
+ // Stub callTool to throw for all calls
167
+ vi.spyOn(manager, 'callTool').mockRejectedValue(new Error('transport broken'));
168
+
169
+ const enricher = new McpContextEnricher(manager);
170
+
171
+ const result = await enricher.enrich({
172
+ dependencies: ['express'],
173
+ architectureNotes: 'Use Azure Cosmos DB for data',
174
+ });
175
+
176
+ // Context7 should fall back to npm links
177
+ if (result.libraryDocs) {
178
+ expect(result.libraryDocs).toContain('npmjs.com');
179
+ }
180
+
181
+ // Azure should fall back to static guidance
182
+ if (result.azureGuidance) {
183
+ expect(result.azureGuidance).toContain('DefaultAzureCredential');
184
+ }
185
+ });
186
+
187
+ it('never throws from enrich()', async () => {
188
+ const manager = new McpManager(makeConfigWithServers());
189
+ manager.markConnected('context7');
190
+ manager.markConnected('azure');
191
+
192
+ vi.spyOn(manager, 'callTool').mockRejectedValue(new Error('catastrophic'));
193
+
194
+ const enricher = new McpContextEnricher(manager);
195
+
196
+ // Should not throw
197
+ const result = await enricher.enrich({
198
+ dependencies: ['express', 'zod'],
199
+ architectureNotes: 'Use Azure Cosmos DB',
200
+ stuckIterations: 5,
201
+ failingTests: ['test fails'],
202
+ });
203
+
204
+ // Should still return a valid EnrichedContext
205
+ expect(result).toHaveProperty('combined');
206
+ expect(typeof result.combined).toBe('string');
207
+ });
208
+ });
209
+
210
+ describe('Combined adapter + enricher degradation', () => {
211
+ it('full workflow with all MCP unavailable returns graceful defaults', async () => {
212
+ const manager = new McpManager(makeEmptyConfig());
213
+ const adapter = new GitHubMcpAdapter(manager);
214
+ const enricher = new McpContextEnricher(manager);
215
+
216
+ // Adapter: not available
217
+ expect(adapter.isAvailable()).toBe(false);
218
+ const repoResult = await adapter.createRepository({ name: 'test' });
219
+ expect(repoResult.available).toBe(false);
220
+
221
+ // Enricher: empty context
222
+ const contextResult = await enricher.enrich({
223
+ dependencies: ['express'],
224
+ architectureNotes: 'Use Azure',
225
+ stuckIterations: 3,
226
+ failingTests: ['test fails'],
227
+ });
228
+ expect(contextResult.combined).toBe('');
229
+ });
230
+ });
231
+ });
@@ -0,0 +1,178 @@
1
+ /**
2
+ * T011: Integration test for MCP transport flow.
3
+ *
4
+ * Spawns a minimal JSON-RPC echo server as a child process, verifies that
5
+ * StdioMcpTransport can connect and round-trip a `tools/call` request,
6
+ * and verifies McpManager.callTool() dispatches through StdioMcpTransport
7
+ * for stdio config.
8
+ */
9
+ import { describe, it, expect, afterEach } from 'vitest';
10
+ import { writeFile, mkdtemp, rm } from 'node:fs/promises';
11
+ import { join } from 'node:path';
12
+ import { tmpdir } from 'node:os';
13
+ import pino from 'pino';
14
+
15
+ import { StdioMcpTransport } from '../../src/mcp/mcpTransport.js';
16
+ import { McpManager } from '../../src/mcp/mcpManager.js';
17
+ import type { McpConfig, StdioServerConfig } from '../../src/mcp/mcpManager.js';
18
+
19
+ // ── Helpers ──────────────────────────────────────────────────────────────────
20
+
21
+ const silentLogger = pino({ level: 'silent' });
22
+
23
+ /**
24
+ * Minimal JSON-RPC echo server script.
25
+ * Handles `initialize` handshake and echoes `tools/call` params back.
26
+ */
27
+ const ECHO_SERVER_SCRIPT = `
28
+ const readline = require('readline');
29
+ const rl = readline.createInterface({ input: process.stdin, terminal: false });
30
+
31
+ rl.on('line', (line) => {
32
+ let msg;
33
+ try { msg = JSON.parse(line); } catch { return; }
34
+
35
+ if (msg.method === 'initialize') {
36
+ const response = {
37
+ jsonrpc: '2.0',
38
+ id: msg.id,
39
+ result: {
40
+ protocolVersion: '2024-11-05',
41
+ capabilities: { tools: {} },
42
+ serverInfo: { name: 'echo-server', version: '0.1.0' },
43
+ },
44
+ };
45
+ process.stdout.write(JSON.stringify(response) + '\\n');
46
+ return;
47
+ }
48
+
49
+ if (msg.method === 'tools/call') {
50
+ const result = {
51
+ jsonrpc: '2.0',
52
+ id: msg.id,
53
+ result: {
54
+ content: [{ type: 'text', text: JSON.stringify(msg.params) }],
55
+ },
56
+ };
57
+ process.stdout.write(JSON.stringify(result) + '\\n');
58
+ return;
59
+ }
60
+ });
61
+ `;
62
+
63
+ let tmpDir: string | undefined;
64
+
65
+ async function createEchoServer(): Promise<string> {
66
+ tmpDir = await mkdtemp(join(tmpdir(), 'mcp-echo-'));
67
+ const scriptPath = join(tmpDir, 'echo-server.js');
68
+ await writeFile(scriptPath, ECHO_SERVER_SCRIPT, 'utf-8');
69
+ return scriptPath;
70
+ }
71
+
72
+ function makeStdioConfig(name: string, scriptPath: string): StdioServerConfig {
73
+ return {
74
+ name,
75
+ type: 'stdio' as const,
76
+ command: 'node',
77
+ args: [scriptPath],
78
+ };
79
+ }
80
+
81
+ // ── Tests ────────────────────────────────────────────────────────────────────
82
+
83
+ describe('MCP Transport Flow (integration)', () => {
84
+ let transport: StdioMcpTransport | undefined;
85
+ let manager: McpManager | undefined;
86
+
87
+ afterEach(async () => {
88
+ if (transport?.isConnected()) {
89
+ await transport.disconnect().catch(() => {});
90
+ }
91
+ transport = undefined;
92
+
93
+ if (manager) {
94
+ await manager.disconnectAll().catch(() => {});
95
+ }
96
+ manager = undefined;
97
+
98
+ if (tmpDir) {
99
+ await rm(tmpDir, { recursive: true, force: true }).catch(() => {});
100
+ tmpDir = undefined;
101
+ }
102
+ });
103
+
104
+ it('StdioMcpTransport connects and round-trips a tools/call request', async () => {
105
+ const scriptPath = await createEchoServer();
106
+
107
+ transport = new StdioMcpTransport(makeStdioConfig('echo-test', scriptPath), silentLogger);
108
+
109
+ await transport.connect();
110
+ expect(transport.isConnected()).toBe(true);
111
+
112
+ const response = await transport.callTool('test-tool', { greeting: 'hello' }, 10_000);
113
+
114
+ expect(response.content).toBeDefined();
115
+
116
+ const content =
117
+ typeof response.content === 'string'
118
+ ? (JSON.parse(response.content) as Record<string, unknown>)
119
+ : response.content;
120
+
121
+ expect(content).toHaveProperty('name', 'test-tool');
122
+ expect(content).toHaveProperty('arguments');
123
+ const args = content.arguments as Record<string, unknown>;
124
+ expect(args).toHaveProperty('greeting', 'hello');
125
+
126
+ await transport.disconnect();
127
+ expect(transport.isConnected()).toBe(false);
128
+ }, 15_000);
129
+
130
+ it('McpManager.callTool() dispatches through StdioMcpTransport for stdio config', async () => {
131
+ const scriptPath = await createEchoServer();
132
+
133
+ const config: McpConfig = {
134
+ servers: {
135
+ 'echo-server': makeStdioConfig('echo-server', scriptPath),
136
+ },
137
+ };
138
+ manager = new McpManager(config, silentLogger);
139
+ manager.markConnected('echo-server');
140
+
141
+ const result = await manager.callTool(
142
+ 'echo-server',
143
+ 'ping-tool',
144
+ { message: 'pong' },
145
+ { timeoutMs: 10_000 },
146
+ );
147
+
148
+ expect(result).toBeDefined();
149
+ expect(result).toHaveProperty('name', 'ping-tool');
150
+ expect(result).toHaveProperty('arguments');
151
+ const args = result.arguments as Record<string, unknown>;
152
+ expect(args).toHaveProperty('message', 'pong');
153
+ }, 15_000);
154
+
155
+ it('echo server round-trips multiple sequential calls', async () => {
156
+ const scriptPath = await createEchoServer();
157
+
158
+ transport = new StdioMcpTransport(makeStdioConfig('echo-multi', scriptPath), silentLogger);
159
+
160
+ await transport.connect();
161
+
162
+ const r1 = await transport.callTool('tool-a', { n: 1 }, 10_000);
163
+ const c1 =
164
+ typeof r1.content === 'string'
165
+ ? (JSON.parse(r1.content) as Record<string, unknown>)
166
+ : r1.content;
167
+ expect((c1.arguments as Record<string, unknown>).n).toBe(1);
168
+
169
+ const r2 = await transport.callTool('tool-b', { n: 2 }, 10_000);
170
+ const c2 =
171
+ typeof r2.content === 'string'
172
+ ? (JSON.parse(r2.content) as Record<string, unknown>)
173
+ : r2.content;
174
+ expect((c2.arguments as Record<string, unknown>).n).toBe(2);
175
+
176
+ await transport.disconnect();
177
+ }, 15_000);
178
+ });