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,223 @@
1
+ /**
2
+ * Discovery Phase Enrichment.
3
+ *
4
+ * After the user provides company information in Step 1, this module
5
+ * optionally enriches the session with web search results and WorkIQ insights.
6
+ *
7
+ * Contract: specs/003-mcp-transport-integration/contracts/discovery-enricher.md
8
+ */
9
+ import type { McpManager } from '../mcp/mcpManager.js';
10
+ import type { LoopIO } from '../loop/conversationLoop.js';
11
+ import type { ActivitySpinner } from '../shared/activitySpinner.js';
12
+ import type { DiscoveryEnrichment } from '../shared/schemas/session.js';
13
+ import type { WebSearchResult } from '../mcp/webSearch.js';
14
+
15
+ // ── WebSearchClient interface ────────────────────────────────────────────────
16
+
17
+ export interface WebSearchClient {
18
+ search(query: string): Promise<WebSearchResult>;
19
+ }
20
+
21
+ // ── Options ──────────────────────────────────────────────────────────────────
22
+
23
+ export interface DiscoveryEnricherOptions {
24
+ /** Company and team summary from Step 1 */
25
+ companySummary: string;
26
+ /** MCP manager for WorkIQ tool calls */
27
+ mcpManager: McpManager;
28
+ /** IO for permission prompts and progress messages */
29
+ io: LoopIO;
30
+ /** Activity spinner for visual feedback */
31
+ spinner?: ActivitySpinner;
32
+ /** Web search client (defaults to production webSearch module) */
33
+ webSearchClient?: WebSearchClient;
34
+ }
35
+
36
+ // ── Helpers ──────────────────────────────────────────────────────────────────
37
+
38
+ const MAX_ITEMS = 10;
39
+
40
+ /**
41
+ * Extract a likely company name from the summary.
42
+ * Uses the first capitalized multi-word sequence or first noun phrase.
43
+ */
44
+ function extractCompanyName(summary: string): string {
45
+ // Try quoted string first
46
+ const quoted = summary.match(/"([^"]+)"/);
47
+ if (quoted) return quoted[1];
48
+ // Try first capitalized multi-word sequence
49
+ const capitalized = summary.match(/\b([A-Z][a-zA-Z]*(?:\s+[A-Z][a-zA-Z]*)*)\b/);
50
+ if (capitalized) return capitalized[1];
51
+ // Fallback: first 3 words
52
+ return summary.split(/\s+/).slice(0, 3).join(' ');
53
+ }
54
+
55
+ /**
56
+ * Map search results to "Title: Snippet" strings, capped at MAX_ITEMS.
57
+ */
58
+ function mapResults(results: Array<{ title: string; snippet: string }>): string[] {
59
+ return results.slice(0, MAX_ITEMS).map((r) => `${r.title}: ${r.snippet}`);
60
+ }
61
+
62
+ // ── DiscoveryEnricher ────────────────────────────────────────────────────────
63
+
64
+ export class DiscoveryEnricher {
65
+ /**
66
+ * Run the full enrichment flow: web search + optional WorkIQ.
67
+ */
68
+ async enrich(options: DiscoveryEnricherOptions): Promise<DiscoveryEnrichment> {
69
+ const { companySummary, mcpManager, io, webSearchClient } = options;
70
+
71
+ let webResult: Partial<DiscoveryEnrichment> = {};
72
+ let workiqResult: Partial<DiscoveryEnrichment> = {};
73
+
74
+ // Run web search if client provided
75
+ if (webSearchClient) {
76
+ io.writeActivity('Searching for recent company and industry context...');
77
+ webResult = await this.enrichFromWebSearch(companySummary, webSearchClient);
78
+ }
79
+
80
+ // Run WorkIQ if available
81
+ if (mcpManager.isAvailable('workiq')) {
82
+ workiqResult = await this.enrichFromWorkIQ(companySummary, mcpManager, io);
83
+ }
84
+
85
+ // Merge results
86
+ const sourcesUsed = [...(webResult.sourcesUsed ?? []), ...(workiqResult.sourcesUsed ?? [])];
87
+
88
+ const enrichment: DiscoveryEnrichment = {
89
+ ...webResult,
90
+ ...workiqResult,
91
+ sourcesUsed: sourcesUsed.length > 0 ? sourcesUsed : undefined,
92
+ enrichedAt: new Date().toISOString(),
93
+ };
94
+
95
+ return enrichment;
96
+ }
97
+
98
+ /**
99
+ * Run only the web search enrichment step.
100
+ */
101
+ async enrichFromWebSearch(
102
+ companySummary: string,
103
+ webSearchClient: WebSearchClient,
104
+ ): Promise<Partial<DiscoveryEnrichment>> {
105
+ const companyName = extractCompanyName(companySummary);
106
+
107
+ // GET CURRENT YEAR for dynamic query generation
108
+ const currentYear = new Date().getFullYear();
109
+
110
+ // Construct multiple queries to cover different angles
111
+
112
+ const queries = [
113
+ `${companyName} recent news ${currentYear - 1} ${currentYear}`,
114
+ `${companyName} competitors market ${currentYear - 1}`,
115
+ `${companyName} industry AI trends ${currentYear}`,
116
+ ];
117
+
118
+ const allSnippets: string[] = [];
119
+ let companyNews: string[] = [];
120
+ let competitorInfo: string[] = [];
121
+ let industryTrends: string[] = [];
122
+
123
+ for (let i = 0; i < queries.length; i++) {
124
+ try {
125
+ const result: WebSearchResult = await webSearchClient.search(queries[i]);
126
+ if (result.degraded) continue;
127
+
128
+ const mapped = mapResults(result.results);
129
+ if (mapped.length === 0) {
130
+ continue;
131
+ }
132
+
133
+ allSnippets.push(...result.results.map((r) => r.snippet));
134
+
135
+ if (i === 0) companyNews = mapped;
136
+ else if (i === 1) competitorInfo = mapped;
137
+ else if (i === 2) industryTrends = mapped;
138
+
139
+ // Stop after first successful query to avoid exhausting provider quotas
140
+ // across repeated enrichment calls in a single workshop run.
141
+ break;
142
+ } catch {
143
+ // Individual query failure — continue with remaining queries
144
+ continue;
145
+ }
146
+ }
147
+
148
+ // If no results at all, return minimal object
149
+ if (allSnippets.length === 0) {
150
+ return {};
151
+ }
152
+
153
+ return {
154
+ companyNews,
155
+ competitorInfo,
156
+ industryTrends,
157
+ webSearchResults: allSnippets.join('\n'),
158
+ sourcesUsed: ['websearch'],
159
+ enrichedAt: new Date().toISOString(),
160
+ };
161
+ }
162
+
163
+ /**
164
+ * Run only the WorkIQ enrichment step.
165
+ * Prompts the user for consent before making any WorkIQ calls.
166
+ */
167
+ async enrichFromWorkIQ(
168
+ companySummary: string,
169
+ mcpManager: McpManager,
170
+ io: LoopIO,
171
+ ): Promise<Partial<DiscoveryEnrichment>> {
172
+ // Prompt for consent (default No)
173
+ const answer = await io.readInput('May sofIA access WorkIQ for team insights? (y/N) ');
174
+ if (!answer || answer.trim().toLowerCase() !== 'y') {
175
+ return {};
176
+ }
177
+
178
+ try {
179
+ const response = (await mcpManager.callTool(
180
+ 'workiq',
181
+ 'analyze_team',
182
+ {
183
+ summary: companySummary,
184
+ focus: ['expertise', 'collaboration', 'documentation'],
185
+ },
186
+ { timeoutMs: 30_000 },
187
+ )) as Record<string, unknown>;
188
+
189
+ // Extract structured fields or fallback to insights string
190
+ let teamExpertise: string[] | undefined;
191
+ let collaborationPatterns: string[] | undefined;
192
+ let documentationGaps: string[] | undefined;
193
+
194
+ if (Array.isArray(response.teamExpertise)) {
195
+ teamExpertise = response.teamExpertise as string[];
196
+ collaborationPatterns = (response.collaborationPatterns ?? []) as string[];
197
+ documentationGaps = (response.documentationGaps ?? []) as string[];
198
+ } else if (typeof response.insights === 'string') {
199
+ // Fallback: split by newline
200
+ const lines = (response.insights as string).split('\n').filter(Boolean);
201
+ teamExpertise = lines.length > 0 ? [lines[0]] : [];
202
+ collaborationPatterns = lines.length > 1 ? [lines[1]] : [];
203
+ documentationGaps = lines.length > 2 ? [lines[2]] : [];
204
+ }
205
+
206
+ if (!teamExpertise) {
207
+ return {};
208
+ }
209
+
210
+ return {
211
+ workiqInsights: {
212
+ teamExpertise,
213
+ collaborationPatterns,
214
+ documentationGaps,
215
+ },
216
+ sourcesUsed: ['workiq'],
217
+ };
218
+ } catch {
219
+ // Graceful degradation — return empty on any error
220
+ return {};
221
+ }
222
+ }
223
+ }
@@ -0,0 +1,247 @@
1
+ /**
2
+ * Phase extraction utilities.
3
+ *
4
+ * Parsers that extract structured data from LLM responses.
5
+ * Each extractor tries to find a JSON block in the response
6
+ * and validates it against the expected schema.
7
+ */
8
+ import { z } from '../vendor/zod.js';
9
+ import {
10
+ businessContextSchema,
11
+ workflowMapSchema,
12
+ ideaCardSchema,
13
+ ideaEvaluationSchema,
14
+ selectedIdeaSchema,
15
+ implementationPlanSchema,
16
+ pocDevelopmentStateSchema,
17
+ type BusinessContext,
18
+ type WorkflowMap,
19
+ type IdeaCard,
20
+ type IdeaEvaluation,
21
+ type SelectedIdea,
22
+ type ImplementationPlan,
23
+ type PocDevelopmentState,
24
+ } from '../shared/schemas/session.js';
25
+
26
+ // ---------------------------------------------------------------------------
27
+ // JSON block extraction
28
+ // ---------------------------------------------------------------------------
29
+
30
+ /**
31
+ * Extract the first JSON object or array from a response string.
32
+ * Tries:
33
+ * 1. Markdown fenced code block (```json ... ```)
34
+ * 2. First `{...}` or `[...]` in plain text
35
+ *
36
+ * Returns the parsed value, or null if nothing valid is found.
37
+ */
38
+ export function extractJsonBlock(response: string): unknown {
39
+ // 1. Try fenced code block
40
+ const fenceMatch = response.match(/```(?:json)?\s*\n([\s\S]*?)\n```/);
41
+ if (fenceMatch) {
42
+ try {
43
+ return JSON.parse(fenceMatch[1].trim());
44
+ } catch {
45
+ // fall through
46
+ }
47
+ }
48
+
49
+ // 2. Try raw JSON — find first { or [
50
+ const objectMatch = response.match(/(\{[\s\S]*\})/);
51
+ if (objectMatch) {
52
+ try {
53
+ return JSON.parse(objectMatch[1]);
54
+ } catch {
55
+ // fall through
56
+ }
57
+ }
58
+
59
+ const arrayMatch = response.match(/(\[[\s\S]*\])/);
60
+ if (arrayMatch) {
61
+ try {
62
+ return JSON.parse(arrayMatch[1]);
63
+ } catch {
64
+ // fall through
65
+ }
66
+ }
67
+
68
+ return null;
69
+ }
70
+
71
+ // ---------------------------------------------------------------------------
72
+ // Multi-block JSON extraction (FR-007)
73
+ // ---------------------------------------------------------------------------
74
+
75
+ /**
76
+ * Extract ALL JSON objects/arrays from a response string.
77
+ * Uses /g flag for fenced blocks and bracket-depth counting for raw JSON.
78
+ * Returns an array of parsed values.
79
+ */
80
+ export function extractAllJsonBlocks(response: string): unknown[] {
81
+ const results: unknown[] = [];
82
+ const seen = new Set<string>();
83
+
84
+ // 1. Try all fenced code blocks
85
+ const fenceRegex = /```(?:json)?\s*\n([\s\S]*?)\n```/g;
86
+ let fenceMatch;
87
+ while ((fenceMatch = fenceRegex.exec(response)) !== null) {
88
+ const raw = fenceMatch[1].trim();
89
+ if (seen.has(raw)) continue;
90
+ try {
91
+ const parsed = JSON.parse(raw);
92
+ results.push(parsed);
93
+ seen.add(raw);
94
+ } catch {
95
+ // skip invalid JSON
96
+ }
97
+ }
98
+
99
+ // 2. Try bracket-depth counter for raw JSON (only if no fenced blocks found)
100
+ if (results.length === 0) {
101
+ for (const opener of ['{', '['] as const) {
102
+ const closer = opener === '{' ? '}' : ']';
103
+ let depth = 0;
104
+ let start = -1;
105
+
106
+ for (let i = 0; i < response.length; i++) {
107
+ const ch = response[i];
108
+ if (ch === opener) {
109
+ if (depth === 0) start = i;
110
+ depth++;
111
+ } else if (ch === closer) {
112
+ depth--;
113
+ if (depth === 0 && start >= 0) {
114
+ const raw = response.slice(start, i + 1);
115
+ if (!seen.has(raw)) {
116
+ try {
117
+ const parsed = JSON.parse(raw);
118
+ results.push(parsed);
119
+ seen.add(raw);
120
+ } catch {
121
+ // skip invalid
122
+ }
123
+ }
124
+ start = -1;
125
+ }
126
+ }
127
+ }
128
+ }
129
+ }
130
+
131
+ return results;
132
+ }
133
+
134
+ /**
135
+ * Extract the first JSON block from a response that validates against a Zod schema.
136
+ * Tries each extracted block with safeParse, returns the first valid match.
137
+ */
138
+ export function extractJsonBlockForSchema<T>(
139
+ response: string,
140
+ schema: z.ZodType<T>,
141
+ ): T | null {
142
+ const blocks = extractAllJsonBlocks(response);
143
+ for (const block of blocks) {
144
+ const result = schema.safeParse(block);
145
+ if (result.success) return result.data;
146
+ }
147
+ return null;
148
+ }
149
+
150
+ // ---------------------------------------------------------------------------
151
+ // Typed extractors
152
+ // ---------------------------------------------------------------------------
153
+
154
+ function safeParse<T>(schema: z.ZodType<T>, data: unknown): T | null {
155
+ const result = schema.safeParse(data);
156
+ return result.success ? result.data : null;
157
+ }
158
+
159
+ /**
160
+ * Extract BusinessContext from an LLM response containing a JSON block.
161
+ */
162
+ export function extractBusinessContext(response: string): BusinessContext | null {
163
+ const json = extractJsonBlock(response);
164
+ if (!json || typeof json !== 'object' || Array.isArray(json)) return null;
165
+ return safeParse(businessContextSchema, json);
166
+ }
167
+
168
+ /**
169
+ * Extract WorkflowMap from an LLM response containing a JSON block.
170
+ */
171
+ export function extractWorkflow(response: string): WorkflowMap | null {
172
+ const json = extractJsonBlock(response);
173
+ if (!json || typeof json !== 'object' || Array.isArray(json)) return null;
174
+ return safeParse(workflowMapSchema, json);
175
+ }
176
+
177
+ /**
178
+ * Extract IdeaCard[] from an LLM response.
179
+ * Supports both a raw array and an `{ ideas: [...] }` wrapper.
180
+ */
181
+ export function extractIdeas(response: string): IdeaCard[] | null {
182
+ const json = extractJsonBlock(response);
183
+ if (!json) return null;
184
+
185
+ // Raw array
186
+ if (Array.isArray(json)) {
187
+ const parsed = z.array(ideaCardSchema).safeParse(json);
188
+ return parsed.success ? parsed.data : null;
189
+ }
190
+
191
+ // Wrapper object with `ideas` key
192
+ if (typeof json === 'object' && 'ideas' in (json as Record<string, unknown>)) {
193
+ const parsed = z.array(ideaCardSchema).safeParse((json as Record<string, unknown>).ideas);
194
+ return parsed.success ? parsed.data : null;
195
+ }
196
+
197
+ return null;
198
+ }
199
+
200
+ /**
201
+ * Extract IdeaEvaluation from an LLM response.
202
+ */
203
+ export function extractEvaluation(response: string): IdeaEvaluation | null {
204
+ const json = extractJsonBlock(response);
205
+ if (!json || typeof json !== 'object' || Array.isArray(json)) return null;
206
+ return safeParse(ideaEvaluationSchema, json);
207
+ }
208
+
209
+ /**
210
+ * Extract SelectedIdea from an LLM response.
211
+ */
212
+ export function extractSelection(response: string): SelectedIdea | null {
213
+ const json = extractJsonBlock(response);
214
+ if (!json || typeof json !== 'object' || Array.isArray(json)) return null;
215
+ return safeParse(selectedIdeaSchema, json);
216
+ }
217
+
218
+ /**
219
+ * Extract ImplementationPlan from an LLM response.
220
+ */
221
+ export function extractPlan(response: string): ImplementationPlan | null {
222
+ const json = extractJsonBlock(response);
223
+ if (!json || typeof json !== 'object' || Array.isArray(json)) return null;
224
+ return safeParse(implementationPlanSchema, json);
225
+ }
226
+
227
+ /**
228
+ * Extract a sessionName string from an LLM response JSON block.
229
+ * Returns the trimmed name, or null if not present/empty.
230
+ */
231
+ export function extractSessionName(response: string): string | null {
232
+ const json = extractJsonBlock(response);
233
+ if (!json || typeof json !== 'object' || Array.isArray(json)) return null;
234
+ const obj = json as Record<string, unknown>;
235
+ if (typeof obj.sessionName !== 'string') return null;
236
+ const trimmed = obj.sessionName.trim();
237
+ return trimmed.length > 0 ? trimmed : null;
238
+ }
239
+
240
+ /**
241
+ * Extract PocDevelopmentState from an LLM response.
242
+ */
243
+ export function extractPocState(response: string): PocDevelopmentState | null {
244
+ const json = extractJsonBlock(response);
245
+ if (!json || typeof json !== 'object' || Array.isArray(json)) return null;
246
+ return safeParse(pocDevelopmentStateSchema, json);
247
+ }