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,101 @@
1
+ // ── Builder ──────────────────────────────────────────────────────────────────
2
+ /**
3
+ * Build a summarized context object from all structured session fields.
4
+ * Missing fields are omitted (undefined) for graceful degradation.
5
+ */
6
+ export function buildSummarizedContext(session) {
7
+ const ctx = {};
8
+ // Discover
9
+ if (session.businessContext) {
10
+ ctx.businessSummary = session.businessContext.businessDescription;
11
+ ctx.challenges = session.businessContext.challenges;
12
+ }
13
+ if (session.topic) {
14
+ ctx.topicArea = session.topic.topicArea;
15
+ }
16
+ if (session.workflow?.activities?.length) {
17
+ ctx.workflowSteps = session.workflow.activities.map((a) => a.name);
18
+ }
19
+ // Discovery enrichment
20
+ if (session.discovery?.enrichment) {
21
+ const enrichment = session.discovery.enrichment;
22
+ const highlights = [];
23
+ if (enrichment.industryTrends?.length) {
24
+ highlights.push(...enrichment.industryTrends.slice(0, 3));
25
+ }
26
+ if (enrichment.companyNews?.length) {
27
+ highlights.push(...enrichment.companyNews.slice(0, 3));
28
+ }
29
+ if (enrichment.workiqInsights?.teamExpertise?.length) {
30
+ highlights.push(`Team expertise: ${enrichment.workiqInsights.teamExpertise.join(', ')}`);
31
+ }
32
+ if (highlights.length > 0) {
33
+ ctx.enrichmentHighlights = highlights;
34
+ }
35
+ }
36
+ // Ideate
37
+ if (session.ideas?.length) {
38
+ ctx.ideaSummaries = session.ideas.map((idea) => ({
39
+ id: idea.id,
40
+ title: idea.title,
41
+ description: idea.description,
42
+ }));
43
+ }
44
+ // Design
45
+ if (session.evaluation) {
46
+ ctx.evaluationSummary = `Method: ${session.evaluation.method}, ${session.evaluation.ideas.length} ideas evaluated`;
47
+ }
48
+ // Select
49
+ if (session.selection) {
50
+ ctx.selectionSummary = `Selected: ${session.selection.ideaId} — ${session.selection.selectionRationale}`;
51
+ }
52
+ // Plan
53
+ if (session.plan?.milestones?.length) {
54
+ ctx.planMilestones = session.plan.milestones.map((m) => m.title);
55
+ }
56
+ if (session.plan?.architectureNotes) {
57
+ ctx.architectureNotes = session.plan.architectureNotes;
58
+ }
59
+ return ctx;
60
+ }
61
+ // ── Renderer ─────────────────────────────────────────────────────────────────
62
+ /**
63
+ * Render a summarized context into a compact markdown section
64
+ * for injection into phase system prompts.
65
+ */
66
+ export function renderSummarizedContext(ctx) {
67
+ const sections = [];
68
+ if (ctx.businessSummary) {
69
+ sections.push(`### Business Context\n- **Business**: ${ctx.businessSummary}`);
70
+ if (ctx.challenges?.length) {
71
+ sections.push(`- **Challenges**: ${ctx.challenges.join(', ')}`);
72
+ }
73
+ }
74
+ if (ctx.topicArea) {
75
+ sections.push(`- **Focus Area**: ${ctx.topicArea}`);
76
+ }
77
+ if (ctx.workflowSteps?.length) {
78
+ sections.push(`### Workflow\n${ctx.workflowSteps.map((s) => `- ${s}`).join('\n')}`);
79
+ }
80
+ if (ctx.enrichmentHighlights?.length) {
81
+ sections.push(`### Discovery Enrichment\n${ctx.enrichmentHighlights.map((h) => `- ${h}`).join('\n')}`);
82
+ }
83
+ if (ctx.ideaSummaries?.length) {
84
+ sections.push(`### Ideas\n${ctx.ideaSummaries.map((i) => `- **${i.title}**: ${i.description}`).join('\n')}`);
85
+ }
86
+ if (ctx.evaluationSummary) {
87
+ sections.push(`### Evaluation\n- ${ctx.evaluationSummary}`);
88
+ }
89
+ if (ctx.selectionSummary) {
90
+ sections.push(`### Selection\n- ${ctx.selectionSummary}`);
91
+ }
92
+ if (ctx.planMilestones?.length) {
93
+ sections.push(`### Plan\n${ctx.planMilestones.map((m) => `- ${m}`).join('\n')}`);
94
+ if (ctx.architectureNotes) {
95
+ sections.push(`- **Architecture**: ${ctx.architectureNotes}`);
96
+ }
97
+ }
98
+ if (sections.length === 0)
99
+ return '';
100
+ return `\n\n## Prior Phase Context\n\n${sections.join('\n\n')}`;
101
+ }
@@ -0,0 +1,156 @@
1
+ // ── Helpers ──────────────────────────────────────────────────────────────────
2
+ const MAX_ITEMS = 10;
3
+ /**
4
+ * Extract a likely company name from the summary.
5
+ * Uses the first capitalized multi-word sequence or first noun phrase.
6
+ */
7
+ function extractCompanyName(summary) {
8
+ // Try quoted string first
9
+ const quoted = summary.match(/"([^"]+)"/);
10
+ if (quoted)
11
+ return quoted[1];
12
+ // Try first capitalized multi-word sequence
13
+ const capitalized = summary.match(/\b([A-Z][a-zA-Z]*(?:\s+[A-Z][a-zA-Z]*)*)\b/);
14
+ if (capitalized)
15
+ return capitalized[1];
16
+ // Fallback: first 3 words
17
+ return summary.split(/\s+/).slice(0, 3).join(' ');
18
+ }
19
+ /**
20
+ * Map search results to "Title: Snippet" strings, capped at MAX_ITEMS.
21
+ */
22
+ function mapResults(results) {
23
+ return results.slice(0, MAX_ITEMS).map((r) => `${r.title}: ${r.snippet}`);
24
+ }
25
+ // ── DiscoveryEnricher ────────────────────────────────────────────────────────
26
+ export class DiscoveryEnricher {
27
+ /**
28
+ * Run the full enrichment flow: web search + optional WorkIQ.
29
+ */
30
+ async enrich(options) {
31
+ const { companySummary, mcpManager, io, webSearchClient } = options;
32
+ let webResult = {};
33
+ let workiqResult = {};
34
+ // Run web search if client provided
35
+ if (webSearchClient) {
36
+ io.writeActivity('Searching for recent company and industry context...');
37
+ webResult = await this.enrichFromWebSearch(companySummary, webSearchClient);
38
+ }
39
+ // Run WorkIQ if available
40
+ if (mcpManager.isAvailable('workiq')) {
41
+ workiqResult = await this.enrichFromWorkIQ(companySummary, mcpManager, io);
42
+ }
43
+ // Merge results
44
+ const sourcesUsed = [...(webResult.sourcesUsed ?? []), ...(workiqResult.sourcesUsed ?? [])];
45
+ const enrichment = {
46
+ ...webResult,
47
+ ...workiqResult,
48
+ sourcesUsed: sourcesUsed.length > 0 ? sourcesUsed : undefined,
49
+ enrichedAt: new Date().toISOString(),
50
+ };
51
+ return enrichment;
52
+ }
53
+ /**
54
+ * Run only the web search enrichment step.
55
+ */
56
+ async enrichFromWebSearch(companySummary, webSearchClient) {
57
+ const companyName = extractCompanyName(companySummary);
58
+ // GET CURRENT YEAR for dynamic query generation
59
+ const currentYear = new Date().getFullYear();
60
+ // Construct multiple queries to cover different angles
61
+ const queries = [
62
+ `${companyName} recent news ${currentYear - 1} ${currentYear}`,
63
+ `${companyName} competitors market ${currentYear - 1}`,
64
+ `${companyName} industry AI trends ${currentYear}`,
65
+ ];
66
+ const allSnippets = [];
67
+ let companyNews = [];
68
+ let competitorInfo = [];
69
+ let industryTrends = [];
70
+ for (let i = 0; i < queries.length; i++) {
71
+ try {
72
+ const result = await webSearchClient.search(queries[i]);
73
+ if (result.degraded)
74
+ continue;
75
+ const mapped = mapResults(result.results);
76
+ if (mapped.length === 0) {
77
+ continue;
78
+ }
79
+ allSnippets.push(...result.results.map((r) => r.snippet));
80
+ if (i === 0)
81
+ companyNews = mapped;
82
+ else if (i === 1)
83
+ competitorInfo = mapped;
84
+ else if (i === 2)
85
+ industryTrends = mapped;
86
+ // Stop after first successful query to avoid exhausting provider quotas
87
+ // across repeated enrichment calls in a single workshop run.
88
+ break;
89
+ }
90
+ catch {
91
+ // Individual query failure — continue with remaining queries
92
+ continue;
93
+ }
94
+ }
95
+ // If no results at all, return minimal object
96
+ if (allSnippets.length === 0) {
97
+ return {};
98
+ }
99
+ return {
100
+ companyNews,
101
+ competitorInfo,
102
+ industryTrends,
103
+ webSearchResults: allSnippets.join('\n'),
104
+ sourcesUsed: ['websearch'],
105
+ enrichedAt: new Date().toISOString(),
106
+ };
107
+ }
108
+ /**
109
+ * Run only the WorkIQ enrichment step.
110
+ * Prompts the user for consent before making any WorkIQ calls.
111
+ */
112
+ async enrichFromWorkIQ(companySummary, mcpManager, io) {
113
+ // Prompt for consent (default No)
114
+ const answer = await io.readInput('May sofIA access WorkIQ for team insights? (y/N) ');
115
+ if (!answer || answer.trim().toLowerCase() !== 'y') {
116
+ return {};
117
+ }
118
+ try {
119
+ const response = (await mcpManager.callTool('workiq', 'analyze_team', {
120
+ summary: companySummary,
121
+ focus: ['expertise', 'collaboration', 'documentation'],
122
+ }, { timeoutMs: 30_000 }));
123
+ // Extract structured fields or fallback to insights string
124
+ let teamExpertise;
125
+ let collaborationPatterns;
126
+ let documentationGaps;
127
+ if (Array.isArray(response.teamExpertise)) {
128
+ teamExpertise = response.teamExpertise;
129
+ collaborationPatterns = (response.collaborationPatterns ?? []);
130
+ documentationGaps = (response.documentationGaps ?? []);
131
+ }
132
+ else if (typeof response.insights === 'string') {
133
+ // Fallback: split by newline
134
+ const lines = response.insights.split('\n').filter(Boolean);
135
+ teamExpertise = lines.length > 0 ? [lines[0]] : [];
136
+ collaborationPatterns = lines.length > 1 ? [lines[1]] : [];
137
+ documentationGaps = lines.length > 2 ? [lines[2]] : [];
138
+ }
139
+ if (!teamExpertise) {
140
+ return {};
141
+ }
142
+ return {
143
+ workiqInsights: {
144
+ teamExpertise,
145
+ collaborationPatterns,
146
+ documentationGaps,
147
+ },
148
+ sourcesUsed: ['workiq'],
149
+ };
150
+ }
151
+ catch {
152
+ // Graceful degradation — return empty on any error
153
+ return {};
154
+ }
155
+ }
156
+ }
@@ -0,0 +1,222 @@
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 { businessContextSchema, workflowMapSchema, ideaCardSchema, ideaEvaluationSchema, selectedIdeaSchema, implementationPlanSchema, pocDevelopmentStateSchema, } from '../shared/schemas/session.js';
10
+ // ---------------------------------------------------------------------------
11
+ // JSON block extraction
12
+ // ---------------------------------------------------------------------------
13
+ /**
14
+ * Extract the first JSON object or array from a response string.
15
+ * Tries:
16
+ * 1. Markdown fenced code block (```json ... ```)
17
+ * 2. First `{...}` or `[...]` in plain text
18
+ *
19
+ * Returns the parsed value, or null if nothing valid is found.
20
+ */
21
+ export function extractJsonBlock(response) {
22
+ // 1. Try fenced code block
23
+ const fenceMatch = response.match(/```(?:json)?\s*\n([\s\S]*?)\n```/);
24
+ if (fenceMatch) {
25
+ try {
26
+ return JSON.parse(fenceMatch[1].trim());
27
+ }
28
+ catch {
29
+ // fall through
30
+ }
31
+ }
32
+ // 2. Try raw JSON — find first { or [
33
+ const objectMatch = response.match(/(\{[\s\S]*\})/);
34
+ if (objectMatch) {
35
+ try {
36
+ return JSON.parse(objectMatch[1]);
37
+ }
38
+ catch {
39
+ // fall through
40
+ }
41
+ }
42
+ const arrayMatch = response.match(/(\[[\s\S]*\])/);
43
+ if (arrayMatch) {
44
+ try {
45
+ return JSON.parse(arrayMatch[1]);
46
+ }
47
+ catch {
48
+ // fall through
49
+ }
50
+ }
51
+ return null;
52
+ }
53
+ // ---------------------------------------------------------------------------
54
+ // Multi-block JSON extraction (FR-007)
55
+ // ---------------------------------------------------------------------------
56
+ /**
57
+ * Extract ALL JSON objects/arrays from a response string.
58
+ * Uses /g flag for fenced blocks and bracket-depth counting for raw JSON.
59
+ * Returns an array of parsed values.
60
+ */
61
+ export function extractAllJsonBlocks(response) {
62
+ const results = [];
63
+ const seen = new Set();
64
+ // 1. Try all fenced code blocks
65
+ const fenceRegex = /```(?:json)?\s*\n([\s\S]*?)\n```/g;
66
+ let fenceMatch;
67
+ while ((fenceMatch = fenceRegex.exec(response)) !== null) {
68
+ const raw = fenceMatch[1].trim();
69
+ if (seen.has(raw))
70
+ continue;
71
+ try {
72
+ const parsed = JSON.parse(raw);
73
+ results.push(parsed);
74
+ seen.add(raw);
75
+ }
76
+ catch {
77
+ // skip invalid JSON
78
+ }
79
+ }
80
+ // 2. Try bracket-depth counter for raw JSON (only if no fenced blocks found)
81
+ if (results.length === 0) {
82
+ for (const opener of ['{', '[']) {
83
+ const closer = opener === '{' ? '}' : ']';
84
+ let depth = 0;
85
+ let start = -1;
86
+ for (let i = 0; i < response.length; i++) {
87
+ const ch = response[i];
88
+ if (ch === opener) {
89
+ if (depth === 0)
90
+ start = i;
91
+ depth++;
92
+ }
93
+ else if (ch === closer) {
94
+ depth--;
95
+ if (depth === 0 && start >= 0) {
96
+ const raw = response.slice(start, i + 1);
97
+ if (!seen.has(raw)) {
98
+ try {
99
+ const parsed = JSON.parse(raw);
100
+ results.push(parsed);
101
+ seen.add(raw);
102
+ }
103
+ catch {
104
+ // skip invalid
105
+ }
106
+ }
107
+ start = -1;
108
+ }
109
+ }
110
+ }
111
+ }
112
+ }
113
+ return results;
114
+ }
115
+ /**
116
+ * Extract the first JSON block from a response that validates against a Zod schema.
117
+ * Tries each extracted block with safeParse, returns the first valid match.
118
+ */
119
+ export function extractJsonBlockForSchema(response, schema) {
120
+ const blocks = extractAllJsonBlocks(response);
121
+ for (const block of blocks) {
122
+ const result = schema.safeParse(block);
123
+ if (result.success)
124
+ return result.data;
125
+ }
126
+ return null;
127
+ }
128
+ // ---------------------------------------------------------------------------
129
+ // Typed extractors
130
+ // ---------------------------------------------------------------------------
131
+ function safeParse(schema, data) {
132
+ const result = schema.safeParse(data);
133
+ return result.success ? result.data : null;
134
+ }
135
+ /**
136
+ * Extract BusinessContext from an LLM response containing a JSON block.
137
+ */
138
+ export function extractBusinessContext(response) {
139
+ const json = extractJsonBlock(response);
140
+ if (!json || typeof json !== 'object' || Array.isArray(json))
141
+ return null;
142
+ return safeParse(businessContextSchema, json);
143
+ }
144
+ /**
145
+ * Extract WorkflowMap from an LLM response containing a JSON block.
146
+ */
147
+ export function extractWorkflow(response) {
148
+ const json = extractJsonBlock(response);
149
+ if (!json || typeof json !== 'object' || Array.isArray(json))
150
+ return null;
151
+ return safeParse(workflowMapSchema, json);
152
+ }
153
+ /**
154
+ * Extract IdeaCard[] from an LLM response.
155
+ * Supports both a raw array and an `{ ideas: [...] }` wrapper.
156
+ */
157
+ export function extractIdeas(response) {
158
+ const json = extractJsonBlock(response);
159
+ if (!json)
160
+ return null;
161
+ // Raw array
162
+ if (Array.isArray(json)) {
163
+ const parsed = z.array(ideaCardSchema).safeParse(json);
164
+ return parsed.success ? parsed.data : null;
165
+ }
166
+ // Wrapper object with `ideas` key
167
+ if (typeof json === 'object' && 'ideas' in json) {
168
+ const parsed = z.array(ideaCardSchema).safeParse(json.ideas);
169
+ return parsed.success ? parsed.data : null;
170
+ }
171
+ return null;
172
+ }
173
+ /**
174
+ * Extract IdeaEvaluation from an LLM response.
175
+ */
176
+ export function extractEvaluation(response) {
177
+ const json = extractJsonBlock(response);
178
+ if (!json || typeof json !== 'object' || Array.isArray(json))
179
+ return null;
180
+ return safeParse(ideaEvaluationSchema, json);
181
+ }
182
+ /**
183
+ * Extract SelectedIdea from an LLM response.
184
+ */
185
+ export function extractSelection(response) {
186
+ const json = extractJsonBlock(response);
187
+ if (!json || typeof json !== 'object' || Array.isArray(json))
188
+ return null;
189
+ return safeParse(selectedIdeaSchema, json);
190
+ }
191
+ /**
192
+ * Extract ImplementationPlan from an LLM response.
193
+ */
194
+ export function extractPlan(response) {
195
+ const json = extractJsonBlock(response);
196
+ if (!json || typeof json !== 'object' || Array.isArray(json))
197
+ return null;
198
+ return safeParse(implementationPlanSchema, json);
199
+ }
200
+ /**
201
+ * Extract a sessionName string from an LLM response JSON block.
202
+ * Returns the trimmed name, or null if not present/empty.
203
+ */
204
+ export function extractSessionName(response) {
205
+ const json = extractJsonBlock(response);
206
+ if (!json || typeof json !== 'object' || Array.isArray(json))
207
+ return null;
208
+ const obj = json;
209
+ if (typeof obj.sessionName !== 'string')
210
+ return null;
211
+ const trimmed = obj.sessionName.trim();
212
+ return trimmed.length > 0 ? trimmed : null;
213
+ }
214
+ /**
215
+ * Extract PocDevelopmentState from an LLM response.
216
+ */
217
+ export function extractPocState(response) {
218
+ const json = extractJsonBlock(response);
219
+ if (!json || typeof json !== 'object' || Array.isArray(json))
220
+ return null;
221
+ return safeParse(pocDevelopmentStateSchema, json);
222
+ }