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,452 @@
1
+ /**
2
+ * End-to-end interactive simulation with Zava Industries script.
3
+ *
4
+ * This test simulates a complete workshop session using the Zava Industries
5
+ * agent interaction script. It exercises the full code path:
6
+ * - All 6 workshop phases (Discover → Ideate → Design → Select → Plan → Develop)
7
+ * - ConversationLoop with post-phase summarization
8
+ * - Phase boundary enforcement
9
+ * - Context summarization across phases
10
+ * - Export with conversation fallback
11
+ *
12
+ * Uses a fake CopilotClient that returns scripted LLM responses with
13
+ * embedded JSON blocks for structured data extraction.
14
+ */
15
+ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
16
+ import { mkdtemp, rm, readFile, readdir } from 'node:fs/promises';
17
+ import { join } from 'node:path';
18
+ import { tmpdir } from 'node:os';
19
+ import { ConversationLoop } from '../../src/loop/conversationLoop.js';
20
+ import { createPhaseHandler, getPhaseOrder } from '../../src/phases/phaseHandlers.js';
21
+ import { exportSession } from '../../src/sessions/exportWriter.js';
22
+ import { buildSummarizedContext, renderSummarizedContext } from '../../src/phases/contextSummarizer.js';
23
+ // ── Zava scripted responses ─────────────────────────────────────────────────
24
+ const ZAVA_USER_INPUTS = {
25
+ Discover: [
26
+ 'We are Zava Industries, a mid-premium fashion company based in Milan. Our biggest challenge is speed in trend analysis.',
27
+ "I'd like to focus on Trend Intelligence and Signal Aggregation.",
28
+ 'done',
29
+ ],
30
+ Ideate: [
31
+ 'I love these ideas: TrendLens, TrendPulse Dashboard, AutoBrief Generator, Celebrity Impact Tracker, Trend Predictor.',
32
+ 'done',
33
+ ],
34
+ Design: [
35
+ 'TrendLens feasibility=3, value=5. TrendPulse feasibility=4, value=5. AutoBrief feasibility=4, value=3.',
36
+ 'done',
37
+ ],
38
+ Select: [
39
+ 'I want to proceed with TrendPulse Dashboard with integrated TrendLens.',
40
+ 'done',
41
+ ],
42
+ Plan: [
43
+ 'Azure Functions backend, Azure Cognitive Services for image analysis, React frontend. 4 week PoC.',
44
+ 'done',
45
+ ],
46
+ Develop: [
47
+ 'TypeScript + Node.js backend, React dashboard. Must run locally for PoC.',
48
+ 'done',
49
+ ],
50
+ Complete: [],
51
+ };
52
+ // LLM responses that include JSON blocks for extraction
53
+ const ZAVA_LLM_RESPONSES = {
54
+ Discover: [
55
+ `Great! Let me help you explore Zava Industries' challenges.
56
+
57
+ \`\`\`json
58
+ {
59
+ "businessDescription": "Zava Industries is a mid-premium fashion company based in Milan specializing in trend-driven clothing for ages 20-55",
60
+ "challenges": ["Speed of trend analysis", "Manual data gathering", "Scattered data across tools", "Slow trend-to-retail cycle"],
61
+ "constraints": ["Azure-based infrastructure"],
62
+ "successMetrics": [{"name": "Trend detection lead time", "value": "<1 week"}, {"name": "Collection hit rate", "value": "50%+"}]
63
+ }
64
+ \`\`\`
65
+
66
+ I understand your situation. Let's map out your workflow.`,
67
+ `Excellent choice! Here's the workflow map:
68
+
69
+ \`\`\`json
70
+ {
71
+ "activities": [
72
+ {"id": "s1", "name": "Social Media Scanning"},
73
+ {"id": "s2", "name": "Celebrity Monitoring"},
74
+ {"id": "s3", "name": "Runway Tracking"},
75
+ {"id": "s4", "name": "Competitor Analysis"},
76
+ {"id": "s5", "name": "Signal Consolidation"},
77
+ {"id": "s6", "name": "Trend Scoring"},
78
+ {"id": "s7", "name": "Design Brief Creation"},
79
+ {"id": "s8", "name": "Designer Feedback Loop"}
80
+ ],
81
+ "edges": [
82
+ {"fromStepId": "s1", "toStepId": "s5"},
83
+ {"fromStepId": "s2", "toStepId": "s5"},
84
+ {"fromStepId": "s3", "toStepId": "s5"},
85
+ {"fromStepId": "s4", "toStepId": "s5"},
86
+ {"fromStepId": "s5", "toStepId": "s6"},
87
+ {"fromStepId": "s6", "toStepId": "s7"},
88
+ {"fromStepId": "s7", "toStepId": "s8"}
89
+ ]
90
+ }
91
+ \`\`\``,
92
+ `Great! The Discover phase is complete. Let's move on.`,
93
+ ],
94
+ Ideate: [
95
+ `Here are the AI-powered ideas based on Zava's workflow:
96
+
97
+ \`\`\`json
98
+ [
99
+ {"id": "idea-1", "title": "TrendLens", "description": "AI visual analyzer for social media and celebrity photos extracting fashion attributes in near-real-time", "workflowStepIds": ["s1", "s2", "s3"]},
100
+ {"id": "idea-2", "title": "TrendPulse Dashboard", "description": "Unified real-time dashboard aggregating all trend signals with scores and lifecycle indicators", "workflowStepIds": ["s5", "s6"]},
101
+ {"id": "idea-3", "title": "AutoBrief Generator", "description": "AI that creates design briefs from detected trends including visual mood boards", "workflowStepIds": ["s7", "s8"]},
102
+ {"id": "idea-4", "title": "Celebrity Impact Tracker", "description": "AI correlating celebrity outfit appearances with social media engagement spikes", "workflowStepIds": ["s2"]},
103
+ {"id": "idea-5", "title": "Trend Predictor", "description": "Predictive model estimating trend lifecycle and commercial potential", "workflowStepIds": ["s6"]}
104
+ ]
105
+ \`\`\`
106
+
107
+ These ideas address your core bottleneck of manual trend analysis.`,
108
+ `Great selection! Let's proceed to Design.`,
109
+ ],
110
+ Design: [
111
+ `Here's the evaluation using a feasibility-value matrix:
112
+
113
+ \`\`\`json
114
+ {
115
+ "ideas": [
116
+ {"ideaId": "idea-1", "feasibility": 3, "value": 5, "risks": ["Social media API limits", "Fashion-domain CV accuracy"], "dataNeeded": ["Social media images", "Runway photos"]},
117
+ {"ideaId": "idea-2", "feasibility": 4, "value": 5, "risks": ["Change management", "Data integration complexity"], "dataNeeded": ["All source feeds", "Historical sales data"]},
118
+ {"ideaId": "idea-3", "feasibility": 4, "value": 3, "risks": ["Design quality expectations"], "dataNeeded": ["Trend data", "Existing briefs"]},
119
+ {"ideaId": "idea-4", "feasibility": 3, "value": 4, "risks": ["Celebrity data availability"], "dataNeeded": ["Celebrity feeds", "Social engagement data"]},
120
+ {"ideaId": "idea-5", "feasibility": 2, "value": 5, "risks": ["Historical data requirements"], "dataNeeded": ["Multi-year trend data"]}
121
+ ],
122
+ "method": "feasibility-value-matrix"
123
+ }
124
+ \`\`\`
125
+
126
+ \`\`\`mermaid
127
+ graph TD
128
+ A[Social Media APIs] --> B[TrendLens Vision AI]
129
+ B --> C[Signal Store]
130
+ D[Celebrity Feeds] --> B
131
+ E[Runway Data] --> B
132
+ C --> F[TrendPulse Dashboard]
133
+ F --> G[Trend Scoring Engine]
134
+ G --> H[Design Brief Generator]
135
+ \`\`\``,
136
+ `The Design phase is complete. Let's select the best idea.`,
137
+ ],
138
+ Select: [
139
+ `Based on the evaluation, I recommend **TrendPulse Dashboard with integrated TrendLens**:
140
+
141
+ \`\`\`json
142
+ {
143
+ "ideaId": "idea-2",
144
+ "selectionRationale": "TrendPulse Dashboard has the best combined feasibility (4) and value (5) score. Integrating TrendLens visual AI gives it unique competitive advantage. It addresses the core bottleneck of manual data gathering and slow consolidation.",
145
+ "confirmedByUser": true,
146
+ "confirmedAt": "2026-03-04T07:00:00Z"
147
+ }
148
+ \`\`\``,
149
+ `Selection confirmed. Moving to Planning.`,
150
+ ],
151
+ Plan: [
152
+ `Here's the implementation plan:
153
+
154
+ \`\`\`json
155
+ {
156
+ "milestones": [
157
+ {"id": "m1", "title": "Foundation & Data Pipeline", "items": ["Set up Azure Functions project", "Create Instagram API connector", "Set up Cosmos DB schema"]},
158
+ {"id": "m2", "title": "Visual AI Integration", "items": ["Integrate Azure Cognitive Services", "Build fashion attribute extractor", "Create trend signal storage"]},
159
+ {"id": "m3", "title": "Dashboard & Scoring", "items": ["Build React dashboard", "Implement trend frequency charts", "Add scoring algorithm"]},
160
+ {"id": "m4", "title": "Integration & Testing", "items": ["Connect all components", "Run with 100+ test images", "Measure accuracy against 70% target"]}
161
+ ],
162
+ "architectureNotes": "Azure Functions + Azure Cognitive Services + Cosmos DB + React. TypeScript throughout.",
163
+ "dependencies": ["Instagram Graph API access", "Azure Cognitive Services subscription", "Cosmos DB instance"]
164
+ }
165
+ \`\`\``,
166
+ `The Plan phase is complete. Ready for PoC development.`,
167
+ ],
168
+ Develop: [
169
+ `PoC requirements captured:
170
+
171
+ \`\`\`json
172
+ {
173
+ "repoSource": "local",
174
+ "techStack": {
175
+ "language": "TypeScript",
176
+ "runtime": "Node.js 22",
177
+ "testRunner": "vitest",
178
+ "framework": "React + Azure Functions",
179
+ "buildCommand": "npm run build"
180
+ },
181
+ "iterations": []
182
+ }
183
+ \`\`\``,
184
+ `PoC specification complete. Run \`sofia dev\` to generate the code.`,
185
+ ],
186
+ Complete: [],
187
+ };
188
+ // ── Test infrastructure ──────────────────────────────────────────────────────
189
+ function createScriptedClient(phase) {
190
+ let responseIndex = 0;
191
+ const responses = ZAVA_LLM_RESPONSES[phase];
192
+ return {
193
+ createSession: vi.fn().mockImplementation(async (_opts) => {
194
+ return {
195
+ send: vi.fn().mockImplementation(async function* () {
196
+ const text = responses[Math.min(responseIndex, responses.length - 1)];
197
+ responseIndex++;
198
+ yield { type: 'TextDelta', text };
199
+ }),
200
+ };
201
+ }),
202
+ };
203
+ }
204
+ function createScriptedIO(phase) {
205
+ const inputs = [...ZAVA_USER_INPUTS[phase]];
206
+ let inputIndex = 0;
207
+ return {
208
+ write: vi.fn(),
209
+ writeActivity: vi.fn(),
210
+ writeToolSummary: vi.fn(),
211
+ readInput: vi.fn().mockImplementation(async () => {
212
+ if (inputIndex < inputs.length) {
213
+ return inputs[inputIndex++];
214
+ }
215
+ return null;
216
+ }),
217
+ showDecisionGate: vi.fn().mockResolvedValue({ choice: 'continue' }),
218
+ isJsonMode: false,
219
+ isTTY: false,
220
+ };
221
+ }
222
+ // ── Test suite ───────────────────────────────────────────────────────────────
223
+ describe('Zava Industries E2E Simulation', () => {
224
+ let tmpDir;
225
+ beforeEach(async () => {
226
+ tmpDir = await mkdtemp(join(tmpdir(), 'sofia-zava-e2e-'));
227
+ });
228
+ afterEach(async () => {
229
+ await rm(tmpDir, { recursive: true, force: true });
230
+ });
231
+ it('completes a full 6-phase workshop and produces complete export', async () => {
232
+ let session = {
233
+ sessionId: 'zava-e2e-sim',
234
+ schemaVersion: '1.0.0',
235
+ createdAt: new Date().toISOString(),
236
+ updatedAt: new Date().toISOString(),
237
+ phase: 'Discover',
238
+ status: 'Active',
239
+ participants: [],
240
+ artifacts: { generatedFiles: [] },
241
+ turns: [],
242
+ };
243
+ const phases = getPhaseOrder(); // Discover, Ideate, Design, Select, Plan, Develop
244
+ for (const phase of phases) {
245
+ session.phase = phase;
246
+ // Create a client that returns scripted responses for this phase
247
+ const client = createScriptedClient(phase);
248
+ const io = createScriptedIO(phase);
249
+ // Create and preload the handler
250
+ const handler = createPhaseHandler(phase);
251
+ await handler._preload();
252
+ const initialMessage = handler.getInitialMessage?.(session);
253
+ const loop = new ConversationLoop({
254
+ client,
255
+ io,
256
+ session,
257
+ phaseHandler: handler,
258
+ initialMessage,
259
+ onSessionUpdate: async (updated) => {
260
+ session = updated;
261
+ },
262
+ });
263
+ session = await loop.run();
264
+ session.updatedAt = new Date().toISOString();
265
+ }
266
+ // ── Verify structured data extraction ──────────────────────────────
267
+ // Discover phase
268
+ expect(session.businessContext).toBeDefined();
269
+ expect(session.businessContext.businessDescription).toContain('Zava Industries');
270
+ expect(session.businessContext.challenges.length).toBeGreaterThan(0);
271
+ expect(session.workflow).toBeDefined();
272
+ expect(session.workflow.activities.length).toBeGreaterThanOrEqual(6);
273
+ expect(session.workflow.edges.length).toBeGreaterThan(0);
274
+ // Ideate phase
275
+ expect(session.ideas).toBeDefined();
276
+ expect(session.ideas.length).toBeGreaterThanOrEqual(3);
277
+ expect(session.ideas.some((i) => i.title.includes('TrendLens'))).toBe(true);
278
+ expect(session.ideas.some((i) => i.title.includes('TrendPulse'))).toBe(true);
279
+ // Design phase
280
+ expect(session.evaluation).toBeDefined();
281
+ expect(session.evaluation.method).toBe('feasibility-value-matrix');
282
+ expect(session.evaluation.ideas.length).toBeGreaterThanOrEqual(3);
283
+ // Select phase
284
+ expect(session.selection).toBeDefined();
285
+ expect(session.selection.ideaId).toBe('idea-2');
286
+ expect(session.selection.confirmedByUser).toBe(true);
287
+ // Plan phase
288
+ expect(session.plan).toBeDefined();
289
+ expect(session.plan.milestones.length).toBeGreaterThanOrEqual(3);
290
+ expect(session.plan.architectureNotes).toContain('Azure');
291
+ // Develop phase
292
+ expect(session.poc).toBeDefined();
293
+ expect(session.poc.repoSource).toBe('local');
294
+ expect(session.poc.techStack).toBeDefined();
295
+ expect(session.poc.techStack.language).toBe('TypeScript');
296
+ // ── Verify conversation turns captured ──────────────────────────────
297
+ expect(session.turns).toBeDefined();
298
+ expect(session.turns.length).toBeGreaterThan(0);
299
+ for (const phase of phases) {
300
+ const phaseTurns = session.turns.filter((t) => t.phase === phase);
301
+ expect(phaseTurns.length).toBeGreaterThan(0);
302
+ }
303
+ // ── Verify context summarization works ──────────────────────────────
304
+ const ctx = buildSummarizedContext(session);
305
+ expect(ctx.businessSummary).toContain('Zava');
306
+ expect(ctx.ideaSummaries).toBeDefined();
307
+ expect(ctx.evaluationSummary).toBeDefined();
308
+ expect(ctx.selectionSummary).toContain('idea-2');
309
+ expect(ctx.planMilestones).toBeDefined();
310
+ const rendered = renderSummarizedContext(ctx);
311
+ expect(rendered).toContain('Prior Phase Context');
312
+ expect(rendered).toContain('Zava');
313
+ // ── Export and verify all 6 phase files generated ───────────────────
314
+ await exportSession(session, tmpDir);
315
+ const files = await readdir(tmpDir);
316
+ expect(files).toContain('discover.md');
317
+ expect(files).toContain('ideate.md');
318
+ expect(files).toContain('design.md');
319
+ expect(files).toContain('select.md');
320
+ expect(files).toContain('plan.md');
321
+ expect(files).toContain('develop.md');
322
+ expect(files).toContain('summary.json');
323
+ // Verify summary.json
324
+ const summaryRaw = await readFile(join(tmpDir, 'summary.json'), 'utf-8');
325
+ const summary = JSON.parse(summaryRaw);
326
+ expect(summary.files.filter((f) => f.path.endsWith('.md')).length).toBe(6);
327
+ expect(summary.highlights).toBeDefined();
328
+ expect(summary.highlights.length).toBeGreaterThan(0);
329
+ expect(summary.highlights.some((h) => h.includes('Zava'))).toBe(true);
330
+ // Verify export files have content
331
+ for (const phase of phases) {
332
+ const content = await readFile(join(tmpDir, `${phase.toLowerCase()}.md`), 'utf-8');
333
+ expect(content.length).toBeGreaterThan(50);
334
+ expect(content).toContain(`# ${phase} Phase`);
335
+ }
336
+ // Verify ideate.md has both structured ideas and conversation
337
+ const ideateContent = await readFile(join(tmpDir, 'ideate.md'), 'utf-8');
338
+ expect(ideateContent).toContain('## Ideas');
339
+ expect(ideateContent).toContain('TrendLens');
340
+ expect(ideateContent).toContain('## Conversation');
341
+ // Verify design.md has evaluation data
342
+ const designContent = await readFile(join(tmpDir, 'design.md'), 'utf-8');
343
+ expect(designContent).toContain('## Evaluation');
344
+ expect(designContent).toContain('feasibility-value-matrix');
345
+ }, 30000); // 30 second timeout
346
+ it('phase boundary instruction is injected into system prompts', async () => {
347
+ const session = {
348
+ sessionId: 'boundary-test',
349
+ schemaVersion: '1.0.0',
350
+ createdAt: new Date().toISOString(),
351
+ updatedAt: new Date().toISOString(),
352
+ phase: 'Ideate',
353
+ status: 'Active',
354
+ participants: [],
355
+ artifacts: { generatedFiles: [] },
356
+ turns: [],
357
+ };
358
+ const capturedPrompts = [];
359
+ const client = {
360
+ createSession: vi.fn().mockImplementation(async (opts) => {
361
+ if (opts?.systemPrompt)
362
+ capturedPrompts.push(opts.systemPrompt);
363
+ return {
364
+ send: vi.fn().mockImplementation(async function* () {
365
+ yield { type: 'TextDelta', text: 'Response' };
366
+ }),
367
+ };
368
+ }),
369
+ };
370
+ const io = {
371
+ write: vi.fn(),
372
+ writeActivity: vi.fn(),
373
+ writeToolSummary: vi.fn(),
374
+ readInput: vi.fn().mockResolvedValue(null),
375
+ showDecisionGate: vi.fn().mockResolvedValue({ choice: 'continue' }),
376
+ isJsonMode: false,
377
+ isTTY: false,
378
+ };
379
+ const handler = createPhaseHandler('Ideate');
380
+ await handler._preload();
381
+ const loop = new ConversationLoop({
382
+ client,
383
+ io,
384
+ session,
385
+ phaseHandler: handler,
386
+ initialMessage: 'Start ideation.',
387
+ });
388
+ await loop.run();
389
+ // First captured prompt should be for the conversation (contains boundary)
390
+ expect(capturedPrompts[0]).toContain('You are in the Ideate phase');
391
+ expect(capturedPrompts[0]).toContain('Do NOT introduce or begin the next phase');
392
+ });
393
+ it('summarization fallback activates when inline extraction returns empty', async () => {
394
+ const session = {
395
+ sessionId: 'summarize-fallback-test',
396
+ schemaVersion: '1.0.0',
397
+ createdAt: new Date().toISOString(),
398
+ updatedAt: new Date().toISOString(),
399
+ phase: 'Ideate',
400
+ status: 'Active',
401
+ participants: [],
402
+ artifacts: { generatedFiles: [] },
403
+ turns: [],
404
+ };
405
+ let callCount = 0;
406
+ const client = {
407
+ createSession: vi.fn().mockImplementation(async () => ({
408
+ send: vi.fn().mockImplementation(async function* () {
409
+ callCount++;
410
+ if (callCount <= 2) {
411
+ // Main conversation — no JSON blocks (extraction will fail)
412
+ yield { type: 'TextDelta', text: 'Here are some creative ideas for your fashion business.' };
413
+ }
414
+ else {
415
+ // Summarization call — returns proper JSON
416
+ yield {
417
+ type: 'TextDelta',
418
+ text: '```json\n[{"id":"idea-1","title":"TrendLens","description":"Visual AI","workflowStepIds":["s1"]}]\n```',
419
+ };
420
+ }
421
+ }),
422
+ })),
423
+ };
424
+ const io = {
425
+ write: vi.fn(),
426
+ writeActivity: vi.fn(),
427
+ writeToolSummary: vi.fn(),
428
+ readInput: vi.fn()
429
+ .mockResolvedValueOnce('brainstorm ideas')
430
+ .mockResolvedValue(null),
431
+ showDecisionGate: vi.fn().mockResolvedValue({ choice: 'continue' }),
432
+ isJsonMode: false,
433
+ isTTY: false,
434
+ };
435
+ const handler = createPhaseHandler('Ideate');
436
+ await handler._preload();
437
+ const loop = new ConversationLoop({
438
+ client,
439
+ io,
440
+ session,
441
+ phaseHandler: handler,
442
+ initialMessage: 'Start ideation.',
443
+ });
444
+ const result = await loop.run();
445
+ // Summarization should have been invoked (3+ createSession calls)
446
+ expect(callCount).toBeGreaterThanOrEqual(3);
447
+ // Ideas should be populated via summarization fallback
448
+ expect(result.ideas).toBeDefined();
449
+ expect(result.ideas.length).toBeGreaterThanOrEqual(1);
450
+ expect(result.ideas[0].title).toBe('TrendLens');
451
+ });
452
+ });
@@ -0,0 +1,3 @@
1
+ export function add(a, b) {
2
+ return a + b;
3
+ }
@@ -0,0 +1,6 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ describe('failing', () => {
3
+ it('fails intentionally', () => {
4
+ expect(1).toBe(2);
5
+ });
6
+ });
@@ -0,0 +1,8 @@
1
+ import { describe, it } from 'vitest';
2
+ describe('hanging', () => {
3
+ it('hangs indefinitely', async () => {
4
+ await new Promise(() => {
5
+ // This promise never resolves — simulates a hanging test
6
+ });
7
+ });
8
+ });
@@ -0,0 +1,10 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { add } from '../src/add.js';
3
+ describe('add', () => {
4
+ it('adds two numbers', () => {
5
+ expect(add(1, 2)).toBe(3);
6
+ });
7
+ it('adds negative numbers', () => {
8
+ expect(add(-1, -2)).toBe(-3);
9
+ });
10
+ });
@@ -0,0 +1,6 @@
1
+ import { defineConfig } from 'vitest/config';
2
+ export default defineConfig({
3
+ test: {
4
+ include: ['tests/**/*.test.ts'],
5
+ },
6
+ });
@@ -0,0 +1,138 @@
1
+ /**
2
+ * T075: Integration test for auto-start conversation wiring.
3
+ *
4
+ * Verifies that the workshop flow sends an initial message at phase start
5
+ * so the LLM speaks first, and the user never has to initiate.
6
+ */
7
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
8
+ import { mkdtemp, rm } from 'node:fs/promises';
9
+ import { join } from 'node:path';
10
+ import { tmpdir } from 'node:os';
11
+ import { ConversationLoop } from '../../src/loop/conversationLoop.js';
12
+ import { createFakeCopilotClient } from '../../src/shared/copilotClient.js';
13
+ import { SessionStore } from '../../src/sessions/sessionStore.js';
14
+ import { createPhaseHandler } from '../../src/phases/phaseHandlers.js';
15
+ // ── Helpers ──────────────────────────────────────────────────────────────────
16
+ function createTestSession(overrides) {
17
+ const now = new Date().toISOString();
18
+ return {
19
+ sessionId: 'test-autostart',
20
+ schemaVersion: '1.0.0',
21
+ createdAt: now,
22
+ updatedAt: now,
23
+ phase: 'Discover',
24
+ status: 'Active',
25
+ participants: [],
26
+ artifacts: { generatedFiles: [] },
27
+ turns: [],
28
+ ...overrides,
29
+ };
30
+ }
31
+ function createScriptedIO(inputs, decisionGateChoice = { choice: 'continue' }) {
32
+ let inputIdx = 0;
33
+ const output = [];
34
+ const activityLog = [];
35
+ return {
36
+ write(text) {
37
+ output.push(text);
38
+ },
39
+ writeActivity(text) {
40
+ activityLog.push(text);
41
+ },
42
+ writeToolSummary(_toolName, _summary) {
43
+ // no-op
44
+ },
45
+ async readInput(_prompt) {
46
+ if (inputIdx >= inputs.length)
47
+ return null;
48
+ return inputs[inputIdx++];
49
+ },
50
+ async showDecisionGate(_phase) {
51
+ return decisionGateChoice;
52
+ },
53
+ isJsonMode: false,
54
+ isTTY: true,
55
+ output,
56
+ activityLog,
57
+ };
58
+ }
59
+ // ── Tests ────────────────────────────────────────────────────────────────────
60
+ describe('Auto-start conversation integration (T075)', () => {
61
+ let tmpDir;
62
+ let store;
63
+ beforeEach(async () => {
64
+ tmpDir = await mkdtemp(join(tmpdir(), 'sofia-autostart-'));
65
+ store = new SessionStore(tmpDir);
66
+ process.removeAllListeners('SIGINT');
67
+ });
68
+ afterEach(async () => {
69
+ await rm(tmpDir, { recursive: true, force: true });
70
+ });
71
+ it('workshop flow sends initial message at phase start, LLM speaks first', async () => {
72
+ const session = createTestSession();
73
+ await store.save(session);
74
+ const client = createFakeCopilotClient([
75
+ { role: 'assistant', content: 'Welcome! Tell me about your business and challenges.' },
76
+ { role: 'assistant', content: 'Thanks for sharing. Let me identify key topics.' },
77
+ ]);
78
+ const io = createScriptedIO(['We sell widgets online']);
79
+ const handler = createPhaseHandler('Discover');
80
+ await handler._preload();
81
+ // Get initial message from handler
82
+ const initialMessage = handler.getInitialMessage(session);
83
+ expect(initialMessage).toBeDefined();
84
+ const loop = new ConversationLoop({
85
+ client,
86
+ io,
87
+ session,
88
+ phaseHandler: handler,
89
+ initialMessage,
90
+ onSessionUpdate: async (s) => {
91
+ await store.save(s);
92
+ },
93
+ });
94
+ const result = await loop.run();
95
+ // First turn should be the auto-start initial message, not user input
96
+ expect(result.turns).toBeDefined();
97
+ expect(result.turns.length).toBeGreaterThanOrEqual(2);
98
+ expect(result.turns[0].role).toBe('user');
99
+ expect(result.turns[0].content).toBe(initialMessage);
100
+ expect(result.turns[1].role).toBe('assistant');
101
+ expect(result.turns[1].content).toBe('Welcome! Tell me about your business and challenges.');
102
+ // LLM greeting should appear in output
103
+ const allOutput = io.output.join('');
104
+ expect(allOutput).toContain('Welcome!');
105
+ });
106
+ it('auto-start with resumed session includes progress context', async () => {
107
+ const session = createTestSession({
108
+ turns: [
109
+ { phase: 'Discover', sequence: 1, role: 'user', content: 'Previous input', timestamp: '2025-01-01T00:00:00Z' },
110
+ { phase: 'Discover', sequence: 2, role: 'assistant', content: 'Previous response', timestamp: '2025-01-01T00:00:00Z' },
111
+ ],
112
+ });
113
+ const originalTurnCount = session.turns.length;
114
+ await store.save(session);
115
+ const client = createFakeCopilotClient([
116
+ { role: 'assistant', content: 'Welcome back! Last time we discussed your business. Let me continue.' },
117
+ ]);
118
+ const io = createScriptedIO([]);
119
+ const handler = createPhaseHandler('Discover');
120
+ await handler._preload();
121
+ const initialMessage = handler.getInitialMessage(session);
122
+ expect(initialMessage).toBeDefined();
123
+ // Resumed session message should be different from new session message
124
+ const newSessionMsg = handler.getInitialMessage(createTestSession());
125
+ expect(initialMessage).not.toBe(newSessionMsg);
126
+ const loop = new ConversationLoop({
127
+ client,
128
+ io,
129
+ session,
130
+ phaseHandler: handler,
131
+ initialMessage,
132
+ });
133
+ const result = await loop.run();
134
+ // Should have the auto-start turns appended to existing turns
135
+ // Note: the loop mutates the turns array in-place, so we compare against the captured count
136
+ expect(result.turns.length).toBeGreaterThan(originalTurnCount);
137
+ });
138
+ });