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,425 @@
1
+ /**
2
+ * Phase handler tests.
3
+ *
4
+ * Validates that each phase handler:
5
+ * - Has the correct phase name
6
+ * - Builds a system prompt that includes phase-specific content
7
+ * - Returns references
8
+ * - Provides extractResult and isComplete logic
9
+ */
10
+ import { describe, it, expect } from 'vitest';
11
+ import { createPhaseHandler, getPhaseOrder, getNextPhase } from '../../../src/phases/phaseHandlers.js';
12
+ import { backtrackSession } from '../../../src/sessions/sessionManager.js';
13
+ function makeSession(overrides) {
14
+ return {
15
+ sessionId: 'test-session',
16
+ schemaVersion: '1.0.0',
17
+ createdAt: '2025-01-01T00:00:00Z',
18
+ updatedAt: '2025-01-01T00:00:00Z',
19
+ phase: 'Discover',
20
+ status: 'Active',
21
+ participants: [],
22
+ artifacts: { generatedFiles: [] },
23
+ ...overrides,
24
+ };
25
+ }
26
+ describe('phaseHandlers', () => {
27
+ describe('createPhaseHandler', () => {
28
+ it('creates a Discover handler', async () => {
29
+ const handler = createPhaseHandler('Discover');
30
+ expect(handler.phase).toBe('Discover');
31
+ await handler._preload();
32
+ const prompt = handler.buildSystemPrompt(makeSession());
33
+ expect(prompt).toContain('Discover');
34
+ });
35
+ it('creates an Ideate handler', async () => {
36
+ const handler = createPhaseHandler('Ideate');
37
+ expect(handler.phase).toBe('Ideate');
38
+ await handler._preload();
39
+ const prompt = handler.buildSystemPrompt(makeSession());
40
+ expect(prompt.length).toBeGreaterThan(50);
41
+ });
42
+ it('creates a Design handler', async () => {
43
+ const handler = createPhaseHandler('Design');
44
+ expect(handler.phase).toBe('Design');
45
+ await handler._preload();
46
+ const prompt = handler.buildSystemPrompt(makeSession());
47
+ expect(prompt.length).toBeGreaterThan(50);
48
+ });
49
+ it('creates a Select handler', async () => {
50
+ const handler = createPhaseHandler('Select');
51
+ expect(handler.phase).toBe('Select');
52
+ await handler._preload();
53
+ const prompt = handler.buildSystemPrompt(makeSession());
54
+ expect(prompt.length).toBeGreaterThan(50);
55
+ });
56
+ it('creates a Plan handler', async () => {
57
+ const handler = createPhaseHandler('Plan');
58
+ expect(handler.phase).toBe('Plan');
59
+ await handler._preload();
60
+ const prompt = handler.buildSystemPrompt(makeSession());
61
+ expect(prompt.length).toBeGreaterThan(50);
62
+ });
63
+ it('creates a Develop handler', async () => {
64
+ const handler = createPhaseHandler('Develop');
65
+ expect(handler.phase).toBe('Develop');
66
+ await handler._preload();
67
+ const prompt = handler.buildSystemPrompt(makeSession());
68
+ expect(prompt.length).toBeGreaterThan(50);
69
+ });
70
+ });
71
+ describe('Discover handler specifics', () => {
72
+ it('includes grounding references after preload', async () => {
73
+ const handler = createPhaseHandler('Discover');
74
+ await handler._preload();
75
+ const refs = handler.getReferences(makeSession());
76
+ expect(refs.length).toBeGreaterThan(0);
77
+ });
78
+ it('isComplete returns false without business context', () => {
79
+ const handler = createPhaseHandler('Discover');
80
+ expect(handler.isComplete(makeSession(), '')).toBe(false);
81
+ });
82
+ it('isComplete returns true with business context and workflow', () => {
83
+ const handler = createPhaseHandler('Discover');
84
+ const session = makeSession({
85
+ businessContext: {
86
+ businessDescription: 'Widget Co',
87
+ challenges: ['Growth'],
88
+ },
89
+ workflow: {
90
+ activities: [{ id: 'a1', name: 'Activity 1' }],
91
+ edges: [],
92
+ },
93
+ });
94
+ expect(handler.isComplete(session, '')).toBe(true);
95
+ });
96
+ // T063 — session naming via extractResult
97
+ it('extractResult sets session.name when sessionName is present in LLM response', () => {
98
+ const handler = createPhaseHandler('Discover');
99
+ const session = makeSession();
100
+ const response = '```json\n{"businessDescription": "Logistics Co", "challenges": ["Routing"], "sessionName": "Logistics AI Routing"}\n```';
101
+ const result = handler.extractResult(session, response);
102
+ expect(result.name).toBe('Logistics AI Routing');
103
+ });
104
+ it('extractResult does not set session.name when sessionName is absent from LLM response', () => {
105
+ const handler = createPhaseHandler('Discover');
106
+ const session = makeSession();
107
+ const response = '```json\n{"businessDescription": "Tech Co", "challenges": ["Scale"]}\n```';
108
+ const result = handler.extractResult(session, response);
109
+ expect(result.name).toBeUndefined();
110
+ });
111
+ it('extractResult does not overwrite existing session.name (first-write-wins)', () => {
112
+ const handler = createPhaseHandler('Discover');
113
+ const session = makeSession({ name: 'Original Name' });
114
+ const response = '```json\n{"businessDescription": "Retail Co", "challenges": ["Growth"], "sessionName": "New Name"}\n```';
115
+ const result = handler.extractResult(session, response);
116
+ // Should NOT include name in updates since session already has one
117
+ expect(result.name).toBeUndefined();
118
+ });
119
+ });
120
+ describe('Ideate handler specifics', () => {
121
+ it('includes business context in prompt when available', async () => {
122
+ const handler = createPhaseHandler('Ideate');
123
+ await handler._preload();
124
+ const session = makeSession({
125
+ businessContext: {
126
+ businessDescription: 'ACME Corp sells rockets',
127
+ challenges: ['Supply chain delays'],
128
+ },
129
+ });
130
+ const prompt = handler.buildSystemPrompt(session);
131
+ expect(prompt).toContain('ACME Corp sells rockets');
132
+ expect(prompt).toContain('Supply chain delays');
133
+ });
134
+ it('isComplete returns true when ideas exist', () => {
135
+ const handler = createPhaseHandler('Ideate');
136
+ const session = makeSession({
137
+ ideas: [
138
+ {
139
+ id: 'i1',
140
+ title: 'Smart Inventory',
141
+ description: 'AI-powered inventory management',
142
+ workflowStepIds: ['a1'],
143
+ },
144
+ ],
145
+ });
146
+ expect(handler.isComplete(session, '')).toBe(true);
147
+ });
148
+ });
149
+ describe('Select handler specifics', () => {
150
+ it('isComplete returns true when selection is confirmed', () => {
151
+ const handler = createPhaseHandler('Select');
152
+ const session = makeSession({
153
+ selection: {
154
+ ideaId: 'i1',
155
+ selectionRationale: 'Best fit',
156
+ confirmedByUser: true,
157
+ confirmedAt: '2025-01-01T00:00:00Z',
158
+ },
159
+ });
160
+ expect(handler.isComplete(session, '')).toBe(true);
161
+ });
162
+ it('isComplete returns false when selection not confirmed', () => {
163
+ const handler = createPhaseHandler('Select');
164
+ const session = makeSession({
165
+ selection: {
166
+ ideaId: 'i1',
167
+ selectionRationale: 'Best fit',
168
+ confirmedByUser: false,
169
+ },
170
+ });
171
+ expect(handler.isComplete(session, '')).toBe(false);
172
+ });
173
+ });
174
+ describe('getPhaseOrder', () => {
175
+ it('returns 6 phases in order', () => {
176
+ const order = getPhaseOrder();
177
+ expect(order).toEqual(['Discover', 'Ideate', 'Design', 'Select', 'Plan', 'Develop']);
178
+ });
179
+ });
180
+ describe('getNextPhase', () => {
181
+ it('returns Ideate after Discover', () => {
182
+ expect(getNextPhase('Discover')).toBe('Ideate');
183
+ });
184
+ it('returns null after Develop', () => {
185
+ expect(getNextPhase('Develop')).toBeNull();
186
+ });
187
+ it('returns null for Complete', () => {
188
+ expect(getNextPhase('Complete')).toBeNull();
189
+ });
190
+ });
191
+ describe('extractResult integration', () => {
192
+ it('Discover handler extracts business context from response', () => {
193
+ const handler = createPhaseHandler('Discover');
194
+ const session = makeSession();
195
+ const response = '```json\n{"businessDescription": "Tech Co", "challenges": ["Scale"]}\n```';
196
+ const result = handler.extractResult(session, response);
197
+ expect(result.businessContext).toBeDefined();
198
+ expect(result.businessContext.businessDescription).toBe('Tech Co');
199
+ });
200
+ it('Ideate handler extracts ideas from response', () => {
201
+ const handler = createPhaseHandler('Ideate');
202
+ const session = makeSession();
203
+ const response = '```json\n[{"id": "i1", "title": "AI Chat", "description": "Chatbot", "workflowStepIds": ["s1"]}]\n```';
204
+ const result = handler.extractResult(session, response);
205
+ expect(result.ideas).toHaveLength(1);
206
+ expect(result.ideas[0].title).toBe('AI Chat');
207
+ });
208
+ it('Ideate handler merges ideas without duplicates', () => {
209
+ const handler = createPhaseHandler('Ideate');
210
+ const session = makeSession({
211
+ ideas: [{ id: 'i1', title: 'Existing', description: 'Already there', workflowStepIds: ['s1'] }],
212
+ });
213
+ const response = '```json\n[{"id": "i1", "title": "Dup", "description": "Dup", "workflowStepIds": ["s1"]}, {"id": "i2", "title": "New", "description": "New one", "workflowStepIds": ["s2"]}]\n```';
214
+ const result = handler.extractResult(session, response);
215
+ expect(result.ideas).toHaveLength(2);
216
+ expect(result.ideas[0].title).toBe('Existing');
217
+ expect(result.ideas[1].title).toBe('New');
218
+ });
219
+ it('Design handler extracts evaluation from response', () => {
220
+ const handler = createPhaseHandler('Design');
221
+ const session = makeSession();
222
+ const response = '```json\n{"method": "feasibility-value-matrix", "ideas": [{"ideaId": "i1", "feasibility": 4, "value": 5}]}\n```';
223
+ const result = handler.extractResult(session, response);
224
+ expect(result.evaluation).toBeDefined();
225
+ expect(result.evaluation.method).toBe('feasibility-value-matrix');
226
+ });
227
+ it('Select handler extracts selection from response', () => {
228
+ const handler = createPhaseHandler('Select');
229
+ const session = makeSession();
230
+ const response = '```json\n{"ideaId": "i1", "selectionRationale": "Best ROI", "confirmedByUser": true}\n```';
231
+ const result = handler.extractResult(session, response);
232
+ expect(result.selection).toBeDefined();
233
+ expect(result.selection.ideaId).toBe('i1');
234
+ });
235
+ it('Plan handler extracts plan from response', () => {
236
+ const handler = createPhaseHandler('Plan');
237
+ const session = makeSession();
238
+ const response = '```json\n{"milestones": [{"id": "m1", "title": "Setup", "items": ["Init repo"]}]}\n```';
239
+ const result = handler.extractResult(session, response);
240
+ expect(result.plan).toBeDefined();
241
+ expect(result.plan.milestones).toHaveLength(1);
242
+ });
243
+ it('Develop handler extracts poc state from response', () => {
244
+ const handler = createPhaseHandler('Develop');
245
+ const session = makeSession();
246
+ const response = '```json\n{"repoSource": "local", "iterations": [{"iteration": 1, "startedAt": "2025-01-01T00:00:00Z", "outcome": "scaffold", "filesChanged": []}]}\n```';
247
+ const result = handler.extractResult(session, response);
248
+ expect(result.poc).toBeDefined();
249
+ expect(result.poc.iterations).toHaveLength(1);
250
+ });
251
+ it('returns empty object when response has no JSON', () => {
252
+ const handler = createPhaseHandler('Discover');
253
+ const result = handler.extractResult(makeSession(), 'Just plain text');
254
+ expect(result).toEqual({});
255
+ });
256
+ });
257
+ describe('backtrack + recompute (T040)', () => {
258
+ it('handlers detect cleared state as incomplete after backtrack', () => {
259
+ // Session that completed Discover and Ideate
260
+ const session = makeSession({
261
+ phase: 'Design',
262
+ businessContext: {
263
+ businessDescription: 'ACME',
264
+ challenges: ['Growth'],
265
+ },
266
+ workflow: {
267
+ activities: [{ id: 'a1', name: 'Step 1' }],
268
+ edges: [],
269
+ },
270
+ ideas: [
271
+ { id: 'i1', title: 'Idea A', description: 'Desc', workflowStepIds: ['a1'] },
272
+ ],
273
+ });
274
+ // Backtrack to Ideate: clears ideas (and anything downstream)
275
+ const result = backtrackSession(session, 'Ideate');
276
+ expect(result.success).toBe(true);
277
+ const backtracked = result.session;
278
+ const ideateHandler = createPhaseHandler('Ideate');
279
+ // Ideas were cleared, so handler says incomplete
280
+ expect(ideateHandler.isComplete(backtracked, '')).toBe(false);
281
+ // Discover data is preserved
282
+ expect(backtracked.businessContext).toBeDefined();
283
+ });
284
+ it('handlers recompute fresh data after backtrack', () => {
285
+ const session = makeSession({
286
+ phase: 'Design',
287
+ businessContext: {
288
+ businessDescription: 'ACME',
289
+ challenges: ['Growth'],
290
+ },
291
+ ideas: [
292
+ { id: 'old', title: 'Old Idea', description: 'Was here', workflowStepIds: ['a1'] },
293
+ ],
294
+ evaluation: {
295
+ method: 'feasibility-value-matrix',
296
+ ideas: [{ ideaId: 'old', feasibility: 3, value: 3 }],
297
+ },
298
+ });
299
+ // Backtrack to Ideate clears ideas + evaluation
300
+ const { session: backtracked } = backtrackSession(session, 'Ideate');
301
+ expect(backtracked.ideas).toBeUndefined();
302
+ expect(backtracked.evaluation).toBeUndefined();
303
+ // Re-running Ideate handler extracts fresh ideas
304
+ const handler = createPhaseHandler('Ideate');
305
+ const freshResponse = '```json\n[{"id": "new1", "title": "New Idea", "description": "Fresh", "workflowStepIds": ["a1"]}]\n```';
306
+ const result = handler.extractResult(backtracked, freshResponse);
307
+ expect(result.ideas).toHaveLength(1);
308
+ expect(result.ideas[0].id).toBe('new1');
309
+ });
310
+ });
311
+ // ── T074: getInitialMessage() ──────────────────────────────────────────
312
+ describe('getInitialMessage (T074)', () => {
313
+ const phases = ['Discover', 'Ideate', 'Design', 'Select', 'Plan', 'Develop'];
314
+ it('generates phase introduction for new sessions (no turns)', () => {
315
+ for (const phase of phases) {
316
+ const handler = createPhaseHandler(phase);
317
+ const session = makeSession({ phase, turns: [] });
318
+ const msg = handler.getInitialMessage(session);
319
+ expect(msg).toBeDefined();
320
+ expect(typeof msg).toBe('string');
321
+ expect(msg.length).toBeGreaterThan(0);
322
+ }
323
+ });
324
+ it('generates progress summary for resumed sessions (existing turns)', () => {
325
+ for (const phase of phases) {
326
+ const handler = createPhaseHandler(phase);
327
+ const session = makeSession({
328
+ phase,
329
+ turns: [
330
+ { phase, sequence: 1, role: 'user', content: 'Previous input', timestamp: '2025-01-01T00:00:00Z' },
331
+ { phase, sequence: 2, role: 'assistant', content: 'Previous response', timestamp: '2025-01-01T00:00:00Z' },
332
+ ],
333
+ });
334
+ const msg = handler.getInitialMessage(session);
335
+ expect(msg).toBeDefined();
336
+ expect(typeof msg).toBe('string');
337
+ expect(msg.length).toBeGreaterThan(0);
338
+ }
339
+ });
340
+ it('returns different messages for new vs resumed sessions', () => {
341
+ const handler = createPhaseHandler('Discover');
342
+ const newSession = makeSession({ phase: 'Discover', turns: [] });
343
+ const resumedSession = makeSession({
344
+ phase: 'Discover',
345
+ turns: [
346
+ { phase: 'Discover', sequence: 1, role: 'user', content: 'hello', timestamp: '2025-01-01T00:00:00Z' },
347
+ { phase: 'Discover', sequence: 2, role: 'assistant', content: 'hi', timestamp: '2025-01-01T00:00:00Z' },
348
+ ],
349
+ });
350
+ const newMsg = handler.getInitialMessage(newSession);
351
+ const resumedMsg = handler.getInitialMessage(resumedSession);
352
+ expect(newMsg).not.toBe(resumedMsg);
353
+ });
354
+ it('getInitialMessage exists on all 6 phase handlers', () => {
355
+ for (const phase of phases) {
356
+ const handler = createPhaseHandler(phase);
357
+ expect(typeof handler.getInitialMessage).toBe('function');
358
+ }
359
+ });
360
+ });
361
+ // T040: Verify Ideate handler uses renderSummarizedContext (not ad-hoc context)
362
+ describe('context summarizer integration', () => {
363
+ it('Ideate handler uses unified summarized context', async () => {
364
+ const handler = createPhaseHandler('Ideate');
365
+ await handler._preload();
366
+ const session = makeSession({
367
+ businessContext: {
368
+ businessDescription: 'Test Company',
369
+ challenges: ['Challenge A'],
370
+ },
371
+ });
372
+ const prompt = handler.buildSystemPrompt(session);
373
+ expect(prompt).toContain('Test Company');
374
+ expect(prompt).toContain('Prior Phase Context');
375
+ });
376
+ it('Design handler uses unified summarized context with ideas', async () => {
377
+ const handler = createPhaseHandler('Design');
378
+ await handler._preload();
379
+ const session = makeSession({
380
+ ideas: [
381
+ { id: 'idea-1', title: 'AI Bot', description: 'Smart assistant', workflowStepIds: [] },
382
+ ],
383
+ });
384
+ const prompt = handler.buildSystemPrompt(session);
385
+ expect(prompt).toContain('AI Bot');
386
+ expect(prompt).toContain('Prior Phase Context');
387
+ });
388
+ it('Select handler uses unified summarized context with evaluation', async () => {
389
+ const handler = createPhaseHandler('Select');
390
+ await handler._preload();
391
+ const session = makeSession({
392
+ evaluation: {
393
+ method: 'feasibility-value-matrix',
394
+ ideas: [{ ideaId: 'idea-1', feasibility: 8, value: 9 }],
395
+ },
396
+ });
397
+ const prompt = handler.buildSystemPrompt(session);
398
+ expect(prompt).toContain('feasibility-value-matrix');
399
+ expect(prompt).toContain('Prior Phase Context');
400
+ });
401
+ it('Plan handler uses unified summarized context with selection', async () => {
402
+ const handler = createPhaseHandler('Plan');
403
+ await handler._preload();
404
+ const session = makeSession({
405
+ selection: {
406
+ ideaId: 'idea-1',
407
+ selectionRationale: 'Best overall',
408
+ confirmedByUser: true,
409
+ },
410
+ });
411
+ const prompt = handler.buildSystemPrompt(session);
412
+ expect(prompt).toContain('idea-1');
413
+ expect(prompt).toContain('Prior Phase Context');
414
+ });
415
+ it('handlers omit Prior Phase Context section when session is empty', async () => {
416
+ for (const phase of ['Ideate', 'Design', 'Select', 'Plan', 'Develop']) {
417
+ const handler = createPhaseHandler(phase);
418
+ await handler._preload();
419
+ const prompt = handler.buildSystemPrompt(makeSession());
420
+ // Should not contain Prior Phase Context if session is empty
421
+ expect(prompt).not.toContain('Prior Phase Context');
422
+ }
423
+ });
424
+ });
425
+ });
@@ -0,0 +1,118 @@
1
+ /**
2
+ * Prompt loader tests.
3
+ *
4
+ * Validates that canonical prompts can be loaded, composed, and
5
+ * that reference documents are correctly mapped to phases.
6
+ */
7
+ import { describe, it, expect, beforeEach } from 'vitest';
8
+ import { buildSystemPrompt, getPhaseReferences, loadReference, clearPromptCache, listPrompts, listReferences, } from '../../../src/prompts/promptLoader.js';
9
+ describe('promptLoader', () => {
10
+ beforeEach(() => {
11
+ clearPromptCache();
12
+ });
13
+ describe('buildSystemPrompt', () => {
14
+ it('loads the base system prompt for Discover phase', async () => {
15
+ const prompt = await buildSystemPrompt('Discover');
16
+ expect(prompt).toContain('sofIA');
17
+ expect(prompt).toContain('AI Discovery Workshop');
18
+ });
19
+ it('includes phase-specific content for Discover', async () => {
20
+ const prompt = await buildSystemPrompt('Discover');
21
+ expect(prompt).toContain('Understand the Business');
22
+ expect(prompt).toContain('Choose a Topic');
23
+ expect(prompt).toContain('Map Workflow');
24
+ });
25
+ it('includes phase-specific content for Ideate', async () => {
26
+ const prompt = await buildSystemPrompt('Ideate');
27
+ expect(prompt).toContain('AI Envisioning Cards');
28
+ expect(prompt).toContain('Score Cards');
29
+ expect(prompt).toContain('Generate Ideas');
30
+ });
31
+ it('includes phase-specific content for Design', async () => {
32
+ const prompt = await buildSystemPrompt('Design');
33
+ expect(prompt).toContain('Evaluate Ideas');
34
+ expect(prompt).toContain('Feasibility');
35
+ expect(prompt).toContain('BXT');
36
+ });
37
+ it('includes phase-specific content for Select', async () => {
38
+ const prompt = await buildSystemPrompt('Select');
39
+ expect(prompt).toContain('Rank');
40
+ expect(prompt).toContain('Recommend');
41
+ expect(prompt).toContain('User Confirmation');
42
+ });
43
+ it('includes phase-specific content for Plan', async () => {
44
+ const prompt = await buildSystemPrompt('Plan');
45
+ expect(prompt).toContain('milestone');
46
+ expect(prompt).toContain('Architecture');
47
+ expect(prompt).toContain('PoC');
48
+ });
49
+ it('includes phase-specific content for Develop', async () => {
50
+ const prompt = await buildSystemPrompt('Develop');
51
+ expect(prompt).toContain('PoC Requirements');
52
+ expect(prompt).toContain('Success Criteria');
53
+ });
54
+ it('returns only system prompt for Complete phase', async () => {
55
+ const prompt = await buildSystemPrompt('Complete');
56
+ // Complete phase gets only the base system prompt
57
+ expect(prompt).toContain('sofIA');
58
+ expect(prompt).not.toContain('Understand the Business');
59
+ });
60
+ it('caches prompts across calls', async () => {
61
+ const prompt1 = await buildSystemPrompt('Discover');
62
+ const prompt2 = await buildSystemPrompt('Discover');
63
+ expect(prompt1).toBe(prompt2);
64
+ });
65
+ });
66
+ describe('getPhaseReferences', () => {
67
+ it('returns reference paths for Discover phase', async () => {
68
+ const refs = await getPhaseReferences('Discover');
69
+ expect(refs.length).toBeGreaterThan(0);
70
+ expect(refs.some((r) => r.includes('facilitator_persona'))).toBe(true);
71
+ expect(refs.some((r) => r.includes('guardrails'))).toBe(true);
72
+ });
73
+ it('includes design thinking docs for Ideate phase', async () => {
74
+ const refs = await getPhaseReferences('Ideate');
75
+ expect(refs.some((r) => r.includes('design_thinking_persona'))).toBe(true);
76
+ expect(refs.some((r) => r.includes('design_thinking.md'))).toBe(true);
77
+ });
78
+ it('includes document generator for Complete phase', async () => {
79
+ const refs = await getPhaseReferences('Complete');
80
+ expect(refs.some((r) => r.includes('document_generator'))).toBe(true);
81
+ });
82
+ });
83
+ describe('loadReference', () => {
84
+ it('loads facilitator persona reference', async () => {
85
+ const content = await loadReference('facilitatorPersona');
86
+ expect(content).toContain('AI Workshop Facilitator');
87
+ });
88
+ it('loads design thinking reference', async () => {
89
+ const content = await loadReference('designThinking');
90
+ expect(content.length).toBeGreaterThan(100);
91
+ });
92
+ it('loads guardrails reference', async () => {
93
+ const content = await loadReference('guardrails');
94
+ expect(content).toContain('Guardrails');
95
+ });
96
+ });
97
+ describe('listPrompts', () => {
98
+ it('returns all prompt names', () => {
99
+ const prompts = listPrompts();
100
+ expect(prompts).toContain('system');
101
+ expect(prompts).toContain('discover');
102
+ expect(prompts).toContain('ideate');
103
+ expect(prompts).toContain('design');
104
+ expect(prompts).toContain('select');
105
+ expect(prompts).toContain('plan');
106
+ expect(prompts).toContain('develop');
107
+ });
108
+ });
109
+ describe('listReferences', () => {
110
+ it('returns all reference document keys', () => {
111
+ const refs = listReferences();
112
+ expect(refs).toContain('designThinking');
113
+ expect(refs).toContain('facilitatorPersona');
114
+ expect(refs).toContain('guardrails');
115
+ expect(refs).toContain('documentGenerator');
116
+ });
117
+ });
118
+ });