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,131 @@
1
+ /**
2
+ * Error classifier tests (T055).
3
+ *
4
+ * Validates centralized error classification and user-facing messages:
5
+ * - Maps known error codes to categories
6
+ * - Provides actionable messages
7
+ * - Handles unknown errors gracefully
8
+ * - Supports MCP, network, auth, and session errors
9
+ */
10
+ import { describe, it, expect } from 'vitest';
11
+ import { classifyError, toUserMessage, } from '../../../src/shared/errorClassifier.js';
12
+ describe('errorClassifier', () => {
13
+ describe('classifyError', () => {
14
+ it('classifies ECONNREFUSED as connection error', () => {
15
+ const err = Object.assign(new Error('connect ECONNREFUSED'), { code: 'ECONNREFUSED' });
16
+ const result = classifyError(err);
17
+ expect(result.category).toBe('connection');
18
+ expect(result.recoverable).toBe(true);
19
+ });
20
+ it('classifies ENOTFOUND as dns error', () => {
21
+ const err = Object.assign(new Error('getaddrinfo ENOTFOUND'), { code: 'ENOTFOUND' });
22
+ const result = classifyError(err);
23
+ expect(result.category).toBe('dns');
24
+ expect(result.recoverable).toBe(true);
25
+ });
26
+ it('classifies ETIMEDOUT as timeout error', () => {
27
+ const err = Object.assign(new Error('connect ETIMEDOUT'), { code: 'ETIMEDOUT' });
28
+ const result = classifyError(err);
29
+ expect(result.category).toBe('timeout');
30
+ expect(result.recoverable).toBe(true);
31
+ });
32
+ it('classifies 401 as auth error', () => {
33
+ const err = Object.assign(new Error('Unauthorized'), { statusCode: 401 });
34
+ const result = classifyError(err);
35
+ expect(result.category).toBe('auth');
36
+ expect(result.recoverable).toBe(false);
37
+ });
38
+ it('classifies 403 as auth error', () => {
39
+ const err = Object.assign(new Error('Forbidden'), { statusCode: 403 });
40
+ const result = classifyError(err);
41
+ expect(result.category).toBe('auth');
42
+ });
43
+ it('classifies 429 as rate-limit error', () => {
44
+ const err = Object.assign(new Error('Too Many Requests'), { statusCode: 429 });
45
+ const result = classifyError(err);
46
+ expect(result.category).toBe('rate-limit');
47
+ expect(result.recoverable).toBe(true);
48
+ });
49
+ it('classifies ENOENT as not-found error', () => {
50
+ const err = Object.assign(new Error('ENOENT: no such file'), { code: 'ENOENT' });
51
+ const result = classifyError(err);
52
+ expect(result.category).toBe('not-found');
53
+ });
54
+ it('classifies session validation errors', () => {
55
+ const err = new Error('Invalid session: missing required field');
56
+ err.name = 'ZodError';
57
+ const result = classifyError(err);
58
+ expect(result.category).toBe('validation');
59
+ });
60
+ it('classifies unknown errors as internal', () => {
61
+ const err = new Error('Something unexpected happened');
62
+ const result = classifyError(err);
63
+ expect(result.category).toBe('internal');
64
+ expect(result.recoverable).toBe(false);
65
+ });
66
+ it('classifies MCP-related errors', () => {
67
+ const err = new Error('MCP server workiq failed to start');
68
+ const result = classifyError(err);
69
+ expect(result.category).toBe('mcp');
70
+ });
71
+ it('handles non-Error objects', () => {
72
+ const result = classifyError('string error');
73
+ expect(result.category).toBe('internal');
74
+ expect(result.originalError).toBe('string error');
75
+ });
76
+ });
77
+ describe('toUserMessage', () => {
78
+ it('returns actionable message for connection errors', () => {
79
+ const classification = {
80
+ category: 'connection',
81
+ recoverable: true,
82
+ message: 'Connection refused',
83
+ originalError: new Error('ECONNREFUSED'),
84
+ };
85
+ const msg = toUserMessage(classification);
86
+ expect(msg).toContain('connection');
87
+ });
88
+ it('returns actionable message for auth errors', () => {
89
+ const classification = {
90
+ category: 'auth',
91
+ recoverable: false,
92
+ message: 'Unauthorized',
93
+ originalError: new Error('401'),
94
+ };
95
+ const msg = toUserMessage(classification);
96
+ expect(msg).toContain('auth');
97
+ });
98
+ it('returns actionable message for timeout errors', () => {
99
+ const classification = {
100
+ category: 'timeout',
101
+ recoverable: true,
102
+ message: 'Request timed out',
103
+ originalError: new Error('ETIMEDOUT'),
104
+ };
105
+ const msg = toUserMessage(classification);
106
+ expect(msg).toContain('timed out');
107
+ });
108
+ it('returns generic message for internal errors', () => {
109
+ const classification = {
110
+ category: 'internal',
111
+ recoverable: false,
112
+ message: 'Unexpected error',
113
+ originalError: new Error('kaboom'),
114
+ };
115
+ const msg = toUserMessage(classification);
116
+ expect(msg.length).toBeGreaterThan(0);
117
+ });
118
+ it('does not include stack traces', () => {
119
+ const err = new Error('test');
120
+ err.stack = 'Error: test\n at something.js:1:2';
121
+ const classification = {
122
+ category: 'internal',
123
+ recoverable: false,
124
+ message: 'test',
125
+ originalError: err,
126
+ };
127
+ const msg = toUserMessage(classification);
128
+ expect(msg).not.toContain('at something');
129
+ });
130
+ });
131
+ });
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Unit tests for event model.
3
+ */
4
+ import { describe, it, expect } from 'vitest';
5
+ import { createTextDeltaEvent, createActivityEvent, createToolCallEvent, createToolResultEvent, createPhaseChangedEvent, createErrorEvent, } from '../../../src/shared/events.js';
6
+ describe('event model', () => {
7
+ it('createTextDeltaEvent creates a valid event', () => {
8
+ const event = createTextDeltaEvent('Hello ');
9
+ expect(event.type).toBe('TextDelta');
10
+ expect(event.text).toBe('Hello ');
11
+ expect(event.timestamp).toBeTruthy();
12
+ });
13
+ it('createActivityEvent creates a valid event', () => {
14
+ const event = createActivityEvent('Connecting to MCP...');
15
+ expect(event.type).toBe('Activity');
16
+ expect(event.message).toBe('Connecting to MCP...');
17
+ });
18
+ it('createToolCallEvent includes tool name and args', () => {
19
+ const event = createToolCallEvent('web.search', { query: 'AI trends' });
20
+ expect(event.type).toBe('ToolCall');
21
+ expect(event.toolName).toBe('web.search');
22
+ expect(event.args).toEqual({ query: 'AI trends' });
23
+ });
24
+ it('createToolResultEvent includes tool name and result', () => {
25
+ const event = createToolResultEvent('web.search', { results: [] });
26
+ expect(event.type).toBe('ToolResult');
27
+ expect(event.toolName).toBe('web.search');
28
+ });
29
+ it('createPhaseChangedEvent includes old and new phase', () => {
30
+ const event = createPhaseChangedEvent('Discover', 'Ideate');
31
+ expect(event.type).toBe('PhaseChanged');
32
+ expect(event.fromPhase).toBe('Discover');
33
+ expect(event.toPhase).toBe('Ideate');
34
+ });
35
+ it('createErrorEvent includes code and message', () => {
36
+ const event = createErrorEvent('MCP_TIMEOUT', 'WorkIQ timed out');
37
+ expect(event.type).toBe('Error');
38
+ expect(event.code).toBe('MCP_TIMEOUT');
39
+ expect(event.message).toBe('WorkIQ timed out');
40
+ });
41
+ it('all events have a timestamp', () => {
42
+ const events = [
43
+ createTextDeltaEvent('x'),
44
+ createActivityEvent('y'),
45
+ createToolCallEvent('t', {}),
46
+ createToolResultEvent('t', {}),
47
+ createPhaseChangedEvent('Discover', 'Ideate'),
48
+ createErrorEvent('E', 'msg'),
49
+ ];
50
+ for (const e of events) {
51
+ expect(e.timestamp).toBeTruthy();
52
+ expect(typeof e.timestamp).toBe('string');
53
+ }
54
+ });
55
+ });
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Unit tests for markdown renderer.
3
+ */
4
+ import { describe, it, expect } from 'vitest';
5
+ import { renderMarkdown } from '../../../src/shared/markdownRenderer.js';
6
+ describe('renderMarkdown', () => {
7
+ it('renders a heading', () => {
8
+ const output = renderMarkdown('# Hello World');
9
+ expect(output).toBeTruthy();
10
+ expect(output.length).toBeGreaterThan(0);
11
+ });
12
+ it('renders a list', () => {
13
+ const output = renderMarkdown('- One\n- Two\n- Three');
14
+ expect(output).toContain('One');
15
+ expect(output).toContain('Two');
16
+ });
17
+ it('renders a code block', () => {
18
+ const output = renderMarkdown('```json\n{"key": "value"}\n```');
19
+ expect(output).toContain('key');
20
+ });
21
+ it('returns plain text in non-TTY mode', () => {
22
+ const output = renderMarkdown('# Hello World', { isTTY: false });
23
+ // Should not contain ANSI codes in non-TTY mode
24
+ expect(output).toContain('Hello World');
25
+ });
26
+ it('handles empty string', () => {
27
+ const output = renderMarkdown('');
28
+ expect(output).toBe('');
29
+ });
30
+ it('handles raw Markdown preservation in non-TTY json mode', () => {
31
+ const output = renderMarkdown('# Title\n\nBody text', { isTTY: false, jsonMode: true });
32
+ // In json mode, return raw markdown
33
+ expect(output).toContain('# Title');
34
+ });
35
+ });
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Tests for markdownRenderer handling of partial/incremental chunks (T081).
3
+ *
4
+ * Verifies that renderMarkdown doesn't crash on partial markdown input
5
+ * (split headings, incomplete bold, partial tables).
6
+ */
7
+ import { describe, it, expect } from 'vitest';
8
+ import { renderMarkdown } from '../../../src/shared/markdownRenderer.js';
9
+ describe('renderMarkdown incremental chunk handling (T081)', () => {
10
+ it('handles a partial heading (no newline)', () => {
11
+ // During streaming, a heading might arrive without a trailing newline
12
+ const result = renderMarkdown('## Start of head', { isTTY: true });
13
+ expect(result).toBeTruthy();
14
+ expect(result).toContain('Start of head');
15
+ });
16
+ it('handles incomplete bold syntax', () => {
17
+ // Bold started but not closed
18
+ const result = renderMarkdown('Some **bold text without', { isTTY: true });
19
+ expect(result).toBeTruthy();
20
+ expect(result).toContain('bold text without');
21
+ });
22
+ it('handles incomplete code block', () => {
23
+ // Code block opened but not closed
24
+ const result = renderMarkdown('```typescript\nconst x = 1;\n', { isTTY: true });
25
+ expect(result).toBeTruthy();
26
+ expect(result).toContain('const x = 1');
27
+ });
28
+ it('handles partial table row', () => {
29
+ const result = renderMarkdown('| Column 1 | Column 2 |\n| ----', { isTTY: true });
30
+ expect(result).toBeTruthy();
31
+ });
32
+ it('handles empty chunk', () => {
33
+ const result = renderMarkdown('', { isTTY: true });
34
+ expect(result).toBe('');
35
+ });
36
+ it('handles single character chunk', () => {
37
+ const result = renderMarkdown('H', { isTTY: true });
38
+ expect(result).toBeTruthy();
39
+ });
40
+ it('handles newline-only chunk without throwing', () => {
41
+ const result = renderMarkdown('\n', { isTTY: true });
42
+ // A newline-only chunk may produce empty string; it must not throw
43
+ expect(typeof result).toBe('string');
44
+ });
45
+ it('handles incomplete link syntax', () => {
46
+ const result = renderMarkdown('Click [here](http://example', { isTTY: true });
47
+ expect(result).toBeTruthy();
48
+ });
49
+ it('handles partial list item', () => {
50
+ const result = renderMarkdown('- Item one\n- Item tw', { isTTY: true });
51
+ expect(result).toBeTruthy();
52
+ expect(result).toContain('Item one');
53
+ });
54
+ it('renders complete markdown correctly in TTY mode', () => {
55
+ const md = '## Title\n\n- **Bold item**\n- Regular item\n\n```js\nconst x = 1;\n```\n';
56
+ const result = renderMarkdown(md, { isTTY: true });
57
+ expect(result).toContain('Title');
58
+ expect(result).toContain('Bold item');
59
+ expect(result).toContain('Regular item');
60
+ });
61
+ it('returns raw markdown in JSON mode regardless of content', () => {
62
+ const md = '## Partial **heading';
63
+ const result = renderMarkdown(md, { isTTY: true, jsonMode: true });
64
+ expect(result).toBe(md);
65
+ });
66
+ it('handles non-TTY mode with partial markdown', () => {
67
+ const result = renderMarkdown('**incomplete bold', { isTTY: false });
68
+ expect(result).toBeTruthy();
69
+ });
70
+ });
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Unit tests for table renderer.
3
+ */
4
+ import { describe, it, expect } from 'vitest';
5
+ import { renderTable } from '../../../src/shared/tableRenderer.js';
6
+ describe('renderTable', () => {
7
+ it('renders a simple table', () => {
8
+ const output = renderTable({
9
+ head: ['Name', 'Score'],
10
+ rows: [
11
+ ['Idea A', '85'],
12
+ ['Idea B', '72'],
13
+ ],
14
+ });
15
+ expect(output).toContain('Name');
16
+ expect(output).toContain('Score');
17
+ expect(output).toContain('Idea A');
18
+ expect(output).toContain('85');
19
+ });
20
+ it('handles empty rows', () => {
21
+ const output = renderTable({
22
+ head: ['Col1'],
23
+ rows: [],
24
+ });
25
+ expect(output).toContain('Col1');
26
+ });
27
+ it('renders without headers', () => {
28
+ const output = renderTable({
29
+ rows: [['a', 'b'], ['c', 'd']],
30
+ });
31
+ expect(output).toContain('a');
32
+ expect(output).toContain('d');
33
+ });
34
+ });
@@ -0,0 +1,14 @@
1
+ import { defineConfig } from 'vitest/config';
2
+ export default defineConfig({
3
+ test: {
4
+ globals: true,
5
+ setupFiles: ['tests/setup/loadEnv.ts'],
6
+ include: ['tests/**/*.{test,spec}.ts'],
7
+ exclude: ['tests/live/**', 'tests/fixtures/**'],
8
+ coverage: {
9
+ enabled: true,
10
+ provider: 'v8',
11
+ },
12
+ testTimeout: 10_000, // Default timeout for tests (can be overridden per test)
13
+ },
14
+ });
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Vitest config for live (slow) tests that hit the real Copilot SDK.
3
+ * Run with: npm run test:live
4
+ */
5
+ import { defineConfig } from 'vitest/config';
6
+ export default defineConfig({
7
+ test: {
8
+ globals: true,
9
+ setupFiles: ['tests/setup/loadEnv.ts'],
10
+ include: ['tests/live/**/*.{test,spec}.ts'],
11
+ testTimeout: 120_000,
12
+ hookTimeout: 60_000,
13
+ coverage: {
14
+ enabled: true,
15
+ provider: 'v8',
16
+ },
17
+ },
18
+ });
package/docs/README.md ADDED
@@ -0,0 +1,35 @@
1
+ # sofIA CLI Documentation
2
+
3
+ sofIA is an AI Discovery Workshop CLI that guides facilitators through the structured process of discovering, ideating, designing, selecting, and planning AI solutions for business needs.
4
+
5
+ ## Table of Contents
6
+
7
+ - [CLI Usage](./cli-usage.md) — Commands, flags, and examples
8
+ - [Session Model](./session-model.md) — Session lifecycle, phases, and persistence
9
+ - [Export Format](./export-format.md) — Exported artifacts and summary JSON structure
10
+ - [Environment Variables](./environment.md) — Configuration via environment
11
+ - [Architecture](./architecture.md) — Module overview and data flow
12
+
13
+ ## Quick Start
14
+
15
+ ```bash
16
+ # Install dependencies
17
+ npm install
18
+
19
+ # Start an interactive workshop
20
+ npm run start -- workshop
21
+
22
+ # Check session status
23
+ npm run start -- status
24
+
25
+ # Generate a PoC from a completed session
26
+ npm run start -- dev --session <id>
27
+
28
+ # Export session artifacts
29
+ npm run start -- export --session <id>
30
+ ```
31
+
32
+ For the full specification, see:
33
+
34
+ - Workshop phases (Discover → Plan): [specs/001-cli-workshop-rebuild/](../specs/001-cli-workshop-rebuild/)
35
+ - PoC generation & Ralph loop (Develop): [specs/002-poc-generation/](../specs/002-poc-generation/)
@@ -0,0 +1,169 @@
1
+ # Architecture
2
+
3
+ ## Module Overview
4
+
5
+ ```
6
+ src/
7
+ ├── cli/ # CLI entrypoints and command handlers
8
+ │ ├── index.ts # Main entrypoint (commander setup)
9
+ │ ├── workshopCommand.ts # Interactive workshop menu and flow
10
+ │ ├── developCommand.ts # `sofia dev` — PoC generation handler
11
+ │ ├── statusCommand.ts # Session status display
12
+ │ ├── exportCommand.ts # Artifact export handler
13
+ │ ├── directCommands.ts # Non-interactive direct command mode
14
+ │ ├── ioContext.ts # TTY/non-TTY detection, JSON mode, I/O
15
+ │ └── preflight.ts # Pre-flight environment checks
16
+ ├── develop/ # PoC generation & Ralph loop
17
+ │ ├── index.ts # Barrel export
18
+ │ ├── ralphLoop.ts # Autonomous iteration orchestrator
19
+ │ ├── pocScaffolder.ts # PoC project scaffolding + output validation
20
+ │ ├── codeGenerator.ts # LLM-driven code generation & prompt building
21
+ │ ├── testRunner.ts # Test execution and result parsing
22
+ │ ├── mcpContextEnricher.ts# MCP-driven context enrichment (Context7, Azure, web search)
23
+ │ └── githubMcpAdapter.ts # GitHub MCP repo creation adapter
24
+ ├── loop/
25
+ │ └── conversationLoop.ts # Multi-turn conversation orchestrator
26
+ ├── phases/
27
+ │ ├── phaseHandlers.ts # Phase handler factory (one per phase)
28
+ │ └── phaseExtractors.ts # JSON block extraction + Zod validation
29
+ ├── sessions/
30
+ │ ├── sessionStore.ts # Read/write session JSON files
31
+ │ ├── sessionManager.ts # Backtracking, phase transitions
32
+ │ ├── exportWriter.ts # Markdown + summary.json generation
33
+ │ └── exportPaths.ts # Export directory path resolution
34
+ ├── mcp/
35
+ │ ├── mcpManager.ts # MCP server connection manager
36
+ │ └── webSearch.ts # Azure AI Foundry Bing Search tool
37
+ ├── prompts/
38
+ │ └── promptLoader.ts # Cached prompt template composition
39
+ ├── logging/
40
+ │ └── logger.ts # Pino logger with PII redaction
41
+ ├── shared/
42
+ │ ├── schemas/
43
+ │ │ └── session.ts # Zod schemas for all session entities
44
+ │ ├── copilotClient.ts # Copilot SDK abstraction + test fakes
45
+ │ ├── errorClassifier.ts # Error categorization (9 types)
46
+ │ ├── events.ts # Activity/telemetry event model
47
+ │ ├── markdownRenderer.ts # marked + marked-terminal rendering
48
+ │ ├── tableRenderer.ts # cli-table3 wrapper
49
+ │ └── data/
50
+ │ ├── cards.json # AI Envisioning Cards dataset
51
+ │ └── cardsLoader.ts # Cards dataset loader
52
+ └── vendor/
53
+ └── zod.ts # Re-export of zod/v4
54
+ ```
55
+
56
+ ## Data Flow
57
+
58
+ ```
59
+ User Input
60
+
61
+
62
+ ┌─────────────────┐ ┌──────────────────┐
63
+ │ CLI Commands │────▶│ workshopCommand │
64
+ │ (index.ts) │ │ statusCommand │
65
+ │ │ │ exportCommand │
66
+ │ │ │ directCommands │
67
+ └─────────────────┘ └────────┬─────────┘
68
+
69
+ ┌────────────▼───────────┐
70
+ │ ConversationLoop │
71
+ │ (multi-turn chat) │
72
+ └────────────┬───────────┘
73
+
74
+ ┌──────────────────┼──────────────────┐
75
+ ▼ ▼ ▼
76
+ ┌────────────────┐ ┌──────────────┐ ┌──────────────────┐
77
+ │ PhaseHandlers │ │ CopilotClient│ │ SessionStore │
78
+ │ (per-phase │ │ (SDK or fake)│ │ (JSON persist) │
79
+ │ logic) │ └──────────────┘ └──────────────────┘
80
+ └────────┬───────┘
81
+
82
+ ┌──────┴──────┐
83
+ ▼ ▼
84
+ ┌──────────────┐ ┌─────────────────┐
85
+ │ promptLoader │ │ phaseExtractors │
86
+ │ (templates) │ │ (Zod parse) │
87
+ └──────────────┘ └─────────────────┘
88
+ ```
89
+
90
+ ## Key Design Patterns
91
+
92
+ ### PhaseHandler Interface
93
+
94
+ Each workshop phase implements the `PhaseHandler` interface:
95
+
96
+ ```typescript
97
+ interface PhaseHandler {
98
+ phase: PhaseValue;
99
+ buildSystemPrompt(session: WorkshopSession): string;
100
+ getReferences(session: WorkshopSession): Reference[];
101
+ extractResult(text: string): unknown;
102
+ isComplete(session: WorkshopSession): boolean;
103
+ }
104
+ ```
105
+
106
+ ### ConversationLoop
107
+
108
+ The `ConversationLoop` orchestrates multi-turn conversations between the user, the Copilot client, and the active `PhaseHandler`. It handles:
109
+
110
+ - Streaming responses with real-time rendering
111
+ - Activity/telemetry event emission
112
+ - Ctrl+C signal handling for graceful shutdown
113
+ - Session persistence after every turn
114
+
115
+ ### LoopIO Interface
116
+
117
+ I/O is abstracted behind `LoopIO` for testability:
118
+
119
+ - **TTY mode:** Interactive prompts via terminal
120
+ - **Non-TTY mode:** Reads from stdin, writes JSON to stdout
121
+ - **JSON mode:** Activity events go to stderr, structured data to stdout
122
+
123
+ ### Error Classification
124
+
125
+ Errors are classified into 9 categories with recovery hints:
126
+
127
+ | Category | Recoverable | Example |
128
+ | ------------ | ----------- | --------------------- |
129
+ | `connection` | Yes | Network unreachable |
130
+ | `dns` | Yes | DNS resolution failed |
131
+ | `timeout` | Yes | Request timed out |
132
+ | `auth` | No | Invalid credentials |
133
+ | `rate-limit` | Yes | Too many requests |
134
+ | `not-found` | No | Resource not found |
135
+ | `validation` | No | Invalid input |
136
+ | `mcp` | Yes | MCP server down |
137
+ | `internal` | No | Unexpected error |
138
+
139
+ ### Pre-flight Checks
140
+
141
+ Before starting a workshop, `runPreflightChecks()` runs environment validations in parallel:
142
+
143
+ - Copilot SDK connectivity
144
+ - MCP server readiness
145
+ - Web search tool availability
146
+
147
+ Each check reports pass/warn/fail with a message. Required checks block startup; optional checks emit warnings.
148
+
149
+ ## Testing Architecture
150
+
151
+ ```
152
+ tests/
153
+ ├── unit/ # Single-module tests with mocks
154
+ ├── integration/ # Multi-module flow tests
155
+ └── e2e/ # PTY-based interactive tests
156
+ ```
157
+
158
+ - **Test runner:** Vitest with v8 coverage
159
+ - **Mocking:** `vi.mock()` at module boundaries
160
+ - **Fakes:** `createFakeCopilotClient()` for deterministic chat responses
161
+ - **TDD workflow:** Red → Green → Review for all new behavior
162
+
163
+ ## Related
164
+
165
+ - Feature 001 spec: [specs/001-cli-workshop-rebuild/spec.md](../specs/001-cli-workshop-rebuild/spec.md)
166
+ - Feature 001 plan: [specs/001-cli-workshop-rebuild/plan.md](../specs/001-cli-workshop-rebuild/plan.md)
167
+ - Feature 002 spec: [specs/002-poc-generation/spec.md](../specs/002-poc-generation/spec.md)
168
+ - Feature 002 plan: [specs/002-poc-generation/plan.md](../specs/002-poc-generation/plan.md)
169
+ - Research notes: [specs/001-cli-workshop-rebuild/research.md](../specs/001-cli-workshop-rebuild/research.md)