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,249 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * sofIA CLI entrypoint.
4
+ *
5
+ * Provides the main `sofia` command. Running `sofia` with no subcommand
6
+ * starts the workshop flow (default). Explicit subcommands:
7
+ * - workshop: alias for the default workshop flow
8
+ * - status: display session status
9
+ * - export: export session artifacts
10
+ */
11
+ import path from 'node:path';
12
+ import { fileURLToPath } from 'node:url';
13
+ import { Command } from 'commander';
14
+
15
+ import { loadEnvFile } from './envLoader.js';
16
+ import type { PhaseValue } from '../shared/schemas/session.js';
17
+
18
+ // ── Load .env from workspace root ──────────────────────────────────────────
19
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
20
+ loadEnvFile(path.resolve(__dirname, '../../.env'));
21
+
22
+ // ── Handler types ──────────────────────────────────────────────────────────
23
+
24
+ export interface CliHandlers {
25
+ workshopHandler: (opts: Record<string, unknown>) => Promise<void>;
26
+ statusHandler: (opts: Record<string, unknown>) => Promise<void>;
27
+ exportHandler: (opts: Record<string, unknown>) => Promise<void>;
28
+ }
29
+
30
+ // ── Build CLI ──────────────────────────────────────────────────────────────
31
+
32
+ /**
33
+ * Build the Commander program. Accepts optional handler overrides for testing.
34
+ * When handlers are not provided, they dynamically import the real modules.
35
+ */
36
+ export function buildCli(handlers?: Partial<CliHandlers>): Command {
37
+ const program = new Command();
38
+
39
+ program.name('sofia').description('sofIA — AI Discovery Workshop CLI').version('0.1.0');
40
+
41
+ // ── Global options ──────────────────────────────────────────────────────
42
+
43
+ program
44
+ .option('--session <id>', 'Target an existing session')
45
+ .option('--json', 'Emit machine-readable JSON only on stdout')
46
+ .option('--debug', 'Enable debug telemetry')
47
+ .option('--log-file <path>', 'Write structured logs to file')
48
+ .option(
49
+ '--non-interactive',
50
+ 'Disallow prompts; fail with actionable error if input is missing',
51
+ );
52
+
53
+ // ── Workshop options promoted to top level (FR-004) ──────────────────────
54
+
55
+ program
56
+ .option('--new-session', 'Start a new session')
57
+ .option('--phase <phase>', 'Jump to a specific phase')
58
+ .option('--retry <count>', 'Retry transient failures N times', parseInt);
59
+
60
+ // ── Workshop handler logic ──────────────────────────────────────────────
61
+
62
+ async function invokeWorkshopHandler(
63
+ programOpts: Record<string, unknown>,
64
+ cmdOpts?: Record<string, unknown>,
65
+ ): Promise<void> {
66
+ const merged = { ...programOpts, ...cmdOpts };
67
+
68
+ if (handlers?.workshopHandler) {
69
+ await handlers.workshopHandler(merged);
70
+ return;
71
+ }
72
+
73
+ // Direct command mode: if --session and --phase are both specified
74
+ if (merged.session && merged.phase) {
75
+ const { runDirectCommand } = await import('./directCommands.js');
76
+ const { createLoopIO } = await import('./ioContext.js');
77
+ const { createDefaultStore } = await import('../sessions/sessionStore.js');
78
+ const { createCopilotClient } = await import('../shared/copilotClient.js');
79
+ const { getLogger } = await import('../logging/logger.js');
80
+
81
+ const store = createDefaultStore();
82
+ const io = createLoopIO({
83
+ json: merged.json as boolean,
84
+ nonInteractive: merged.nonInteractive as boolean,
85
+ });
86
+
87
+ let client;
88
+ try {
89
+ client = await createCopilotClient();
90
+ } catch (err: unknown) {
91
+ const logger = getLogger();
92
+ logger.error({ err }, 'Failed to create Copilot client — cannot run direct command');
93
+ const msg = err instanceof Error ? err.message : 'Unknown error creating Copilot client';
94
+ if (merged.json) {
95
+ process.stdout.write(JSON.stringify({ error: msg }) + '\n');
96
+ } else {
97
+ console.error(`Error: ${msg}`);
98
+ }
99
+ process.exitCode = 1;
100
+ return;
101
+ }
102
+
103
+ const result = await runDirectCommand({
104
+ sessionId: merged.session as string,
105
+ phase: merged.phase as PhaseValue,
106
+ store,
107
+ client,
108
+ io,
109
+ nonInteractive: merged.nonInteractive as boolean,
110
+ json: merged.json as boolean,
111
+ debug: merged.debug as boolean,
112
+ retry: merged.retry as number,
113
+ });
114
+
115
+ process.exitCode = result.exitCode;
116
+ return;
117
+ }
118
+
119
+ const { workshopCommand } = await import('./workshopCommand.js');
120
+ await workshopCommand(merged);
121
+ }
122
+
123
+ // ── Workshop command (default + alias) ─────────────────────────────────
124
+
125
+ program
126
+ .command('workshop', { isDefault: true })
127
+ .description('Start or resume a governed AI Discovery Workshop session')
128
+ .action(async () => {
129
+ const opts = program.opts();
130
+ await invokeWorkshopHandler(opts);
131
+ });
132
+
133
+ // ── Status command ────────────────────────────────────────────────────
134
+
135
+ program
136
+ .command('status')
137
+ .description('Display session status and next expected action')
138
+ .action(async () => {
139
+ if (handlers?.statusHandler) {
140
+ await handlers.statusHandler(program.opts());
141
+ return;
142
+ }
143
+ const { statusCommand } = await import('./statusCommand.js');
144
+ const globalOpts = program.opts();
145
+ await statusCommand(globalOpts);
146
+ });
147
+
148
+ // ── Export command ────────────────────────────────────────────────────
149
+
150
+ program
151
+ .command('export')
152
+ .description('Export workshop artifacts for a session')
153
+ .option('--output <dir>', 'Output directory (default: ./exports/<sessionId>/)')
154
+ .action(async (opts) => {
155
+ if (handlers?.exportHandler) {
156
+ await handlers.exportHandler({ ...program.opts(), ...opts });
157
+ return;
158
+ }
159
+ const { exportCommand } = await import('./exportCommand.js');
160
+ const globalOpts = program.opts();
161
+ await exportCommand({ ...globalOpts, ...opts });
162
+ });
163
+
164
+ // ── Dev command ───────────────────────────────────────────────────────
165
+
166
+ program
167
+ .command('dev')
168
+ .description('Generate a proof-of-concept repository for a completed workshop session')
169
+ .option('--max-iterations <n>', 'Maximum Ralph loop iterations (default: 20)', parseInt)
170
+ .option('--output <dir>', 'Output directory for the PoC (default: ./poc/<sessionId>/)')
171
+ .option('--force', 'Overwrite existing output directory and start fresh')
172
+ .action(async (opts) => {
173
+ const { developCommand } = await import('./developCommand.js');
174
+ const { createDefaultStore } = await import('../sessions/sessionStore.js');
175
+ const { createLoopIO } = await import('./ioContext.js');
176
+ const { createCopilotClient } = await import('../shared/copilotClient.js');
177
+ const { getLogger } = await import('../logging/logger.js');
178
+ const { loadMcpConfig, McpManager } = await import('../mcp/mcpManager.js');
179
+ const { join: pathJoin } = await import('node:path');
180
+
181
+ const globalOpts = program.opts();
182
+ const merged = { ...globalOpts, ...opts };
183
+
184
+ const store = createDefaultStore();
185
+ const io = createLoopIO({
186
+ json: merged.json as boolean,
187
+ nonInteractive: merged.nonInteractive as boolean,
188
+ });
189
+
190
+ let client;
191
+ try {
192
+ client = await createCopilotClient();
193
+ } catch (err: unknown) {
194
+ const logger = getLogger();
195
+ logger.error({ err }, 'Failed to create Copilot client');
196
+ const msg = err instanceof Error ? err.message : 'Unknown error creating Copilot client';
197
+ if (merged.json) {
198
+ process.stdout.write(JSON.stringify({ error: msg }) + '\n');
199
+ } else {
200
+ process.stderr.write(`Error: ${msg}\n`);
201
+ }
202
+ process.exitCode = 1;
203
+ return;
204
+ }
205
+
206
+ // Load MCP config and wire adapters when MCP servers are configured
207
+ const mcpConfigPath = pathJoin(process.cwd(), '.vscode', 'mcp.json');
208
+ let mcpManager: import('../mcp/mcpManager.js').McpManager | undefined;
209
+ try {
210
+ const mcpConfig = await loadMcpConfig(mcpConfigPath);
211
+ if (Object.keys(mcpConfig.servers).length > 0) {
212
+ mcpManager = new McpManager(mcpConfig);
213
+ // Mark all configured servers as connected (optimistic: actual MCP failures
214
+ // degrade gracefully inside GitHubMcpAdapter / McpContextEnricher)
215
+ for (const name of mcpManager.listServers()) {
216
+ mcpManager.markConnected(name);
217
+ }
218
+ }
219
+ } catch {
220
+ // MCP config is optional — proceed without it
221
+ }
222
+
223
+ await developCommand(merged as Parameters<typeof developCommand>[0], {
224
+ store,
225
+ io,
226
+ client,
227
+ mcpManager,
228
+ });
229
+ });
230
+
231
+ return program;
232
+ }
233
+
234
+ // ── Auto-parse when run as CLI entrypoint ─────────────────────────────────
235
+
236
+ // Only auto-parse when running as the main CLI entrypoint, not when imported for testing
237
+ const isMainModule =
238
+ process.argv[1] &&
239
+ (process.argv[1].endsWith('/cli/index.js') ||
240
+ process.argv[1].endsWith('/cli/index.ts') ||
241
+ process.argv[1].endsWith('sofia'));
242
+
243
+ if (isMainModule) {
244
+ const program = buildCli();
245
+ program.parseAsync(process.argv).catch((err) => {
246
+ console.error(err instanceof Error ? err.message : 'Unknown error');
247
+ process.exit(1);
248
+ });
249
+ }
@@ -0,0 +1,139 @@
1
+ /**
2
+ * IO Context.
3
+ *
4
+ * Detects TTY vs non-TTY, JSON mode, and provides the LoopIO
5
+ * implementation for the ConversationLoop based on CLI options.
6
+ */
7
+ import * as readline from 'node:readline';
8
+
9
+ import type { LoopIO, DecisionGateResult, DecisionGateChoice } from '../loop/conversationLoop.js';
10
+ import type { PhaseValue } from '../shared/schemas/session.js';
11
+ import { renderMarkdown } from '../shared/markdownRenderer.js';
12
+
13
+ export interface IoContextOptions {
14
+ json?: boolean;
15
+ nonInteractive?: boolean;
16
+ debug?: boolean;
17
+ input?: NodeJS.ReadableStream;
18
+ output?: NodeJS.WritableStream;
19
+ errorOutput?: NodeJS.WritableStream;
20
+ }
21
+
22
+ /**
23
+ * Create a LoopIO implementation based on CLI context.
24
+ */
25
+ export function createLoopIO(options: IoContextOptions = {}): LoopIO {
26
+ const input = options.input ?? process.stdin;
27
+ const output = options.output ?? process.stdout;
28
+ const errorOutput = options.errorOutput ?? process.stderr;
29
+ const isTTY = !options.nonInteractive && Boolean((input as NodeJS.ReadStream).isTTY);
30
+ const isJsonMode = options.json ?? false;
31
+ const isDebug = options.debug ?? false;
32
+
33
+ let rl: readline.Interface | null = null;
34
+ let rlClosed = false;
35
+
36
+ function getReadline(): readline.Interface {
37
+ if (!rl || rlClosed) {
38
+ rlClosed = false;
39
+ rl = readline.createInterface({
40
+ input: input as NodeJS.ReadableStream,
41
+ output: isTTY ? (output as NodeJS.WritableStream) : undefined,
42
+ terminal: isTTY,
43
+ });
44
+ rl.on('close', () => { rlClosed = true; });
45
+ }
46
+ return rl;
47
+ }
48
+
49
+ return {
50
+ write(text: string): void {
51
+ (output as NodeJS.WritableStream).write(text);
52
+ },
53
+
54
+ writeActivity(text: string): void {
55
+ if (!isJsonMode) {
56
+ (errorOutput as NodeJS.WritableStream).write(`[activity] ${text}\n`);
57
+ }
58
+ },
59
+
60
+ writeToolSummary(toolName: string, summary: string, details?: { args?: Record<string, unknown>; result?: unknown }): void {
61
+ if (isJsonMode || options.nonInteractive) return;
62
+
63
+ (errorOutput as NodeJS.WritableStream).write(`✓ ${toolName}: ${summary}\n`);
64
+
65
+ if (isDebug && details) {
66
+ if (details.args) {
67
+ (errorOutput as NodeJS.WritableStream).write(` args: ${JSON.stringify(details.args, null, 2)}\n`);
68
+ }
69
+ if (details.result !== undefined) {
70
+ (errorOutput as NodeJS.WritableStream).write(` result: ${JSON.stringify(details.result, null, 2)}\n`);
71
+ }
72
+ }
73
+ },
74
+
75
+ async readInput(prompt?: string): Promise<string | null> {
76
+ if (options.nonInteractive) {
77
+ return null; // Non-interactive mode: no input
78
+ }
79
+
80
+ return new Promise((resolve) => {
81
+ const r = getReadline();
82
+ r.question(prompt ?? '> ', (answer) => {
83
+ resolve(answer);
84
+ });
85
+ r.once('close', () => resolve(null));
86
+ });
87
+ },
88
+
89
+ async showDecisionGate(phase: PhaseValue): Promise<DecisionGateResult> {
90
+ if (isJsonMode || options.nonInteractive) {
91
+ return { choice: 'continue' };
92
+ }
93
+
94
+ const phaseOrder: PhaseValue[] = [
95
+ 'Discover', 'Ideate', 'Design', 'Select', 'Plan', 'Develop', 'Complete',
96
+ ];
97
+ const currentIdx = phaseOrder.indexOf(phase);
98
+ const nextPhase = currentIdx < phaseOrder.length - 1 ? phaseOrder[currentIdx + 1] : null;
99
+
100
+ const rendered = renderMarkdown(
101
+ `\n---\n\n**Phase "${phase}" complete.**\n\n` +
102
+ `Options:\n` +
103
+ ` 1. Continue to ${nextPhase ?? 'Complete'}\n` +
104
+ ` 2. Refine current phase\n` +
105
+ ` 3. Return to main menu\n` +
106
+ ` 4. Exit\n`,
107
+ { isTTY },
108
+ );
109
+ (output as NodeJS.WritableStream).write(rendered);
110
+
111
+ return new Promise((resolve) => {
112
+ const r = getReadline();
113
+ r.question('Choose [1-4]: ', (answer) => {
114
+ const choiceMap: Record<string, DecisionGateChoice> = {
115
+ '1': 'continue',
116
+ '2': 'refine',
117
+ '3': 'menu',
118
+ '4': 'exit',
119
+ };
120
+ const choice = choiceMap[answer.trim()] ?? 'continue';
121
+ resolve({
122
+ choice,
123
+ targetPhase: choice === 'continue' ? (nextPhase ?? undefined) : undefined,
124
+ });
125
+ });
126
+ });
127
+ },
128
+
129
+ isJsonMode,
130
+ isTTY,
131
+ };
132
+ }
133
+
134
+ /**
135
+ * Close any open readline interfaces.
136
+ */
137
+ export function closeIO(_io: LoopIO): void {
138
+ // The IO might hold a readline interface — no-op if not applicable
139
+ }
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Preflight checks — validates environment readiness before starting a workshop.
3
+ *
4
+ * Each check returns a PreflightCheck result. runPreflightChecks() collects all
5
+ * results, never short-circuits, and returns an aggregate PreflightResult.
6
+ */
7
+
8
+ /** Result of a single check. */
9
+ export interface PreflightCheck {
10
+ name: string;
11
+ status: 'pass' | 'warn' | 'fail';
12
+ message: string;
13
+ /** If true (default), a 'fail' status causes overall failure. */
14
+ required?: boolean;
15
+ }
16
+
17
+ /** Aggregate result of all checks. */
18
+ export interface PreflightResult {
19
+ passed: boolean;
20
+ checks: PreflightCheck[];
21
+ }
22
+
23
+ /** A map of named async check functions. */
24
+ export type CheckMap = Record<string, () => Promise<PreflightCheck>>;
25
+
26
+ /**
27
+ * Run all preflight checks in parallel and aggregate results.
28
+ *
29
+ * - Checks that throw are caught and reported as fail with `required: true`.
30
+ * - Overall pass requires that no check with `required !== false` has status 'fail'.
31
+ */
32
+ export async function runPreflightChecks(checks: CheckMap): Promise<PreflightResult> {
33
+ const entries = Object.entries(checks);
34
+
35
+ const results = await Promise.all(
36
+ entries.map(async ([key, fn]) => {
37
+ try {
38
+ return await fn();
39
+ } catch (err: unknown) {
40
+ const message = err instanceof Error ? err.message : String(err);
41
+ return {
42
+ name: key.replace(/^check/, '').replace(/([A-Z])/g, '-$1').toLowerCase().replace(/^-/, ''),
43
+ status: 'fail' as const,
44
+ message,
45
+ required: true,
46
+ };
47
+ }
48
+ }),
49
+ );
50
+
51
+ const passed = results.every(
52
+ (c) => c.status !== 'fail' || c.required === false,
53
+ );
54
+
55
+ return { passed, checks: results };
56
+ }
57
+
58
+ /**
59
+ * Check for legacy web search env vars (FR-016).
60
+ *
61
+ * If `SOFIA_FOUNDRY_AGENT_ENDPOINT` or `SOFIA_FOUNDRY_AGENT_KEY` are set,
62
+ * returns a fail result with migration instructions.
63
+ */
64
+ export async function checkLegacyWebSearchEnvVars(): Promise<PreflightCheck> {
65
+ const legacyEndpoint = process.env.SOFIA_FOUNDRY_AGENT_ENDPOINT;
66
+ const legacyKey = process.env.SOFIA_FOUNDRY_AGENT_KEY;
67
+
68
+ if (legacyEndpoint || legacyKey) {
69
+ return {
70
+ name: 'legacy-web-search-env',
71
+ status: 'fail',
72
+ message:
73
+ 'Legacy web search env vars detected. ' +
74
+ 'Migrate: replace SOFIA_FOUNDRY_AGENT_ENDPOINT with FOUNDRY_PROJECT_ENDPOINT ' +
75
+ 'and remove SOFIA_FOUNDRY_AGENT_KEY (API key auth is no longer used). ' +
76
+ 'See docs/environment.md',
77
+ required: true,
78
+ };
79
+ }
80
+
81
+ return {
82
+ name: 'legacy-web-search-env',
83
+ status: 'pass',
84
+ message: 'No legacy web search env vars detected',
85
+ };
86
+ }
@@ -0,0 +1,118 @@
1
+ /**
2
+ * Status command handler.
3
+ *
4
+ * Implements `sofia status` — displays session status and next expected action.
5
+ * Supports both TTY (human-readable) and JSON output modes.
6
+ */
7
+ import { createDefaultStore } from '../sessions/sessionStore.js';
8
+ import { renderTable } from '../shared/tableRenderer.js';
9
+ import { getNextPhase } from '../phases/phaseHandlers.js';
10
+
11
+ export interface StatusCommandOptions {
12
+ session?: string;
13
+ json?: boolean;
14
+ debug?: boolean;
15
+ logFile?: string;
16
+ nonInteractive?: boolean;
17
+ }
18
+
19
+ export async function statusCommand(opts: StatusCommandOptions): Promise<void> {
20
+ if (!opts.session) {
21
+ // Try to list all sessions
22
+ const store = createDefaultStore();
23
+ const sessions = await store.list();
24
+
25
+ if (sessions.length === 0) {
26
+ if (opts.json) {
27
+ process.stdout.write(JSON.stringify({ error: 'No sessions found. Start one with: sofia workshop --new-session' }) + '\n');
28
+ } else {
29
+ console.error('No sessions found. Start one with: sofia workshop --new-session');
30
+ }
31
+ process.exitCode = 1;
32
+ return;
33
+ }
34
+
35
+ // Show all sessions
36
+ if (opts.json) {
37
+ const statuses = [];
38
+ for (const id of sessions) {
39
+ try {
40
+ const s = await store.load(id);
41
+ statuses.push({
42
+ sessionId: s.sessionId,
43
+ name: s.name,
44
+ phase: s.phase,
45
+ status: s.status,
46
+ updatedAt: s.updatedAt,
47
+ });
48
+ } catch {
49
+ statuses.push({ sessionId: id, error: 'Failed to load' });
50
+ }
51
+ }
52
+ process.stdout.write(JSON.stringify({ sessions: statuses }) + '\n');
53
+ } else {
54
+ const rows: string[][] = [];
55
+ for (const id of sessions) {
56
+ try {
57
+ const s = await store.load(id);
58
+ rows.push([s.sessionId.slice(0, 8), s.name ?? '', s.phase, s.status, s.updatedAt]);
59
+ } catch {
60
+ rows.push([id.slice(0, 8), '', '?', 'Error', '?']);
61
+ }
62
+ }
63
+ console.log(renderTable({
64
+ head: ['Session', 'Name', 'Phase', 'Status', 'Updated'],
65
+ rows,
66
+ }));
67
+ }
68
+ return;
69
+ }
70
+
71
+ const store = createDefaultStore();
72
+
73
+ if (!(await store.exists(opts.session))) {
74
+ if (opts.json) {
75
+ process.stdout.write(JSON.stringify({ error: `Session "${opts.session}" not found.` }) + '\n');
76
+ } else {
77
+ console.error(`Error: Session "${opts.session}" not found.`);
78
+ }
79
+ process.exitCode = 1;
80
+ return;
81
+ }
82
+
83
+ const session = await store.load(opts.session);
84
+
85
+ if (opts.json) {
86
+ const status: Record<string, unknown> = {
87
+ sessionId: session.sessionId,
88
+ phase: session.phase,
89
+ status: session.status,
90
+ nextPhase: getNextPhase(session.phase),
91
+ turns: session.turns?.length ?? 0,
92
+ participants: session.participants.length,
93
+ createdAt: session.createdAt,
94
+ updatedAt: session.updatedAt,
95
+ hasBusinessContext: !!session.businessContext,
96
+ hasWorkflow: !!session.workflow,
97
+ ideaCount: session.ideas?.length ?? 0,
98
+ hasSelection: !!session.selection,
99
+ hasPlan: !!session.plan,
100
+ };
101
+ if (session.name) status.name = session.name;
102
+ process.stdout.write(JSON.stringify(status) + '\n');
103
+ } else {
104
+ const next = getNextPhase(session.phase);
105
+ console.log(`\nSession: ${session.sessionId}`);
106
+ if (session.name) {
107
+ console.log(`Name: ${session.name}`);
108
+ }
109
+ console.log(`Phase: ${session.phase}`);
110
+ console.log(`Status: ${session.status}`);
111
+ console.log(`Turns: ${session.turns?.length ?? 0}`);
112
+ console.log(`Updated: ${session.updatedAt}`);
113
+ if (next) {
114
+ console.log(`Next: ${next}`);
115
+ }
116
+ console.log('');
117
+ }
118
+ }