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,130 @@
1
+ # Data Model: AI Foundry Search Service Deployment
2
+
3
+ **Feature**: 005-ai-search-deploy
4
+ **Date**: 2026-03-01
5
+
6
+ ## Entities
7
+
8
+ ### 1. FoundryDeploymentConfig
9
+
10
+ Configuration for the Bicep deployment. Captured as Bicep parameters and passed via the deployment script.
11
+
12
+ | Field | Type | Required | Default | Constraints | Notes |
13
+ |-------|------|----------|---------|-------------|-------|
14
+ | `subscriptionId` | string | yes | — | Valid Azure subscription GUID | From `az account show` or user input |
15
+ | `resourceGroupName` | string | yes | — | 1-90 chars, alphanumeric + `-_.()` | Auto-created if missing (FR-002) |
16
+ | `location` | string | no | `swedencentral` | Valid Azure region with Agent Service | FR-004 |
17
+ | `accountName` | string | no | `sofia-foundry` | 2-64 chars, `^[a-zA-Z0-9][a-zA-Z0-9_.-]*$` | Used to derive `customSubDomainName` |
18
+ | `projectName` | string | no | `sofia-project` | 2-64 chars | Child of account |
19
+ | `modelDeploymentName` | string | no | `gpt-4.1-mini` | Valid model deployment name | FR-012 |
20
+ | `modelName` | string | no | `gpt-4.1-mini` | Must support `web_search_preview` | See research.md R3 |
21
+ | `modelVersion` | string | no | `2025-04-14` | Valid model version | Pinned for reproducibility |
22
+ | `modelSkuName` | string | no | `GlobalStandard` | `GlobalStandard` or `Standard` | GlobalStandard for broadest availability |
23
+ | `modelSkuCapacity` | int | no | `1` | ≥1 (TPM in thousands) | Sufficient for workshop usage |
24
+
25
+ ### 2. FoundryDeploymentOutput
26
+
27
+ Output produced by the deployment script. Used to configure the sofIA CLI.
28
+
29
+ | Field | Type | Description |
30
+ |-------|------|-------------|
31
+ | `projectEndpoint` | string | Foundry project endpoint URL (e.g., `https://<name>.services.ai.azure.com/api/projects/<project>`) |
32
+ | `modelDeploymentName` | string | Model deployment name (e.g., `gpt-4.1-mini`) |
33
+ | `resourceGroupName` | string | Resource group containing the deployment (for teardown) |
34
+ | `accountName` | string | Foundry account name |
35
+
36
+ ### 3. WebSearchConfig (updated)
37
+
38
+ Runtime configuration for the `web.search` Copilot SDK tool. Replaces the current `WebSearchConfig` interface in `src/mcp/webSearch.ts`.
39
+
40
+ | Field | Type | Required | Source | Notes |
41
+ |-------|------|----------|--------|-------|
42
+ | `projectEndpoint` | string | yes | `FOUNDRY_PROJECT_ENDPOINT` env var | Replaces `endpoint` |
43
+ | `modelDeploymentName` | string | yes | `FOUNDRY_MODEL_DEPLOYMENT_NAME` env var | New field |
44
+
45
+ **Removed fields** (from current `WebSearchConfig`):
46
+ - `endpoint` → replaced by `projectEndpoint`
47
+ - `apiKey` → eliminated (using `DefaultAzureCredential`)
48
+ - `fetchFn` → eliminated (using SDK, not raw fetch)
49
+
50
+ ### 4. AgentSession
51
+
52
+ Internal state for the ephemeral web search agent, managed within `webSearch.ts`. Not persisted — exists only in memory during a CLI session.
53
+
54
+ | Field | Type | Required | Notes |
55
+ |-------|------|----------|-------|
56
+ | `client` | `AIProjectClient` | yes | Created once per session |
57
+ | `openAIClient` | OpenAI client ref | yes | From `client.getOpenAIClient()` |
58
+ | `agentName` | string | yes | Agent name (e.g., `sofia-web-search`) |
59
+ | `agentVersion` | string | yes | Version returned by `createVersion()` |
60
+ | `conversationId` | string | yes | Thread/conversation for message exchange |
61
+ | `initialized` | boolean | yes | Tracks lazy initialization state |
62
+
63
+ **State transitions**:
64
+ ```
65
+ [Uninitialized] → (first web.search call) → [Initialized] → (session end / error) → [Cleaned Up]
66
+ ```
67
+
68
+ - **Uninitialized → Initialized**: On first `web.search` call, creates `AIProjectClient`, agent, and conversation.
69
+ - **Initialized → Cleaned Up**: On `destroyWebSearchSession()` call or `process.beforeExit`, deletes conversation and agent version.
70
+ - If cleanup fails, log warning but do not throw — stale agents will be cleaned up manually or by TTL.
71
+
72
+ ### 5. WebSearchResult (unchanged)
73
+
74
+ The existing `WebSearchResult` interface remains structurally identical but gains citation data from `url_citation` annotations.
75
+
76
+ | Field | Type | Required | Notes |
77
+ |-------|------|----------|-------|
78
+ | `results` | `WebSearchResultItem[]` | yes | Structured search results |
79
+ | `sources` | `string[]` | no | Deduplicated citation URLs (FR-014) |
80
+ | `degraded` | boolean | no | `true` if Foundry unavailable/error |
81
+ | `error` | string | no | Error message when degraded |
82
+
83
+ ### 6. WebSearchResultItem (updated)
84
+
85
+ | Field | Type | Required | Notes |
86
+ |-------|------|----------|-------|
87
+ | `title` | string | yes | Page title (extracted from citation or response) |
88
+ | `url` | string | yes | Source URL from `url_citation` annotation |
89
+ | `snippet` | string | yes | Relevant text excerpt |
90
+
91
+ ### 7. LegacyEnvVarError
92
+
93
+ Not a data model entity but a specific error condition (FR-016).
94
+
95
+ | Condition | Action |
96
+ |-----------|--------|
97
+ | `SOFIA_FOUNDRY_AGENT_ENDPOINT` is set | Emit error: "Legacy env var detected. Migrate to FOUNDRY_PROJECT_ENDPOINT. See docs/environment.md" |
98
+ | `SOFIA_FOUNDRY_AGENT_KEY` is set | Emit error: "Legacy env var detected. API key auth is no longer used. See docs/environment.md" |
99
+
100
+ Checked during preflight (`preflight.ts`). Fails the preflight check with `required: true`.
101
+
102
+ ## Relationships
103
+
104
+ ```
105
+ FoundryDeploymentConfig ──(deploys to)──> Azure Resources
106
+
107
+ ├── Foundry Account
108
+ │ ├── Model Deployment
109
+ │ └── Account Capability Host
110
+ └── Foundry Project
111
+ └── Project Capability Host
112
+
113
+ FoundryDeploymentOutput ──(configures)──> WebSearchConfig (runtime)
114
+
115
+ └── AgentSession (lazy, in-memory)
116
+
117
+ ├── AIProjectClient
118
+ ├── Agent (ephemeral)
119
+ └── Conversation
120
+
121
+ └── WebSearchResult + citations
122
+ ```
123
+
124
+ ## Validation Rules
125
+
126
+ 1. **`projectEndpoint`** must match pattern: `https://*.services.ai.azure.com/api/projects/*`
127
+ 2. **`modelDeploymentName`** must be non-empty string, no whitespace
128
+ 3. **Legacy env vars**: Presence of `SOFIA_FOUNDRY_AGENT_ENDPOINT` or `SOFIA_FOUNDRY_AGENT_KEY` is a hard error (FR-016)
129
+ 4. **Bicep parameters**: `accountName` must be unique within the resource group; `customSubDomainName` must be globally unique
130
+ 5. **Agent cleanup**: Must attempt cleanup even on error; log warnings but do not throw on cleanup failure
@@ -0,0 +1,93 @@
1
+ # Implementation Plan: AI Foundry Search Service Deployment
2
+
3
+ **Branch**: `005-ai-search-deploy` | **Date**: 2026-03-01 | **Spec**: [spec.md](spec.md)
4
+ **Input**: Feature specification from `/specs/005-ai-search-deploy/spec.md`
5
+
6
+ ## Summary
7
+
8
+ Provide one-command deployment of Azure AI Foundry infrastructure (account, project, model deployment) via Bicep + shell script, and migrate the sofIA CLI's `web.search` tool from raw HTTP + API key (`SOFIA_FOUNDRY_AGENT_ENDPOINT`/`SOFIA_FOUNDRY_AGENT_KEY`) to the `@azure/ai-projects` SDK with `DefaultAzureCredential` auth and ephemeral `web_search_preview` agents. Includes teardown, prerequisite validation, and clean-break migration from legacy env vars.
9
+
10
+ ## Technical Context
11
+
12
+ **Language/Version**: Node.js 20 LTS + TypeScript 5.3, Bash (deployment scripts), Bicep (IaC)
13
+ **Primary Dependencies**: `@github/copilot-sdk ^0.1.28`, `@azure/ai-projects` (new), `@azure/identity` (new), `dotenv` (new), `zod ^4.3.6`
14
+ **Storage**: N/A (stateless infrastructure provisioning; session state handled by existing `SessionStore`)
15
+ **Testing**: Vitest 4.x (unit + integration), TDD Red→Green→Review per constitution
16
+ **Target Platform**: CLI — Linux, macOS, Windows (WSL/Git Bash); Azure for infrastructure deployment
17
+ **Project Type**: CLI tool + Infrastructure-as-Code
18
+ **Performance Goals**: Web search query returns grounded results with citations within 10 seconds (SC-003)
19
+ **Constraints**: Deploy completes in <15 minutes (SC-001); teardown in <10 minutes (SC-004); agent lifecycle is ephemeral (created/deleted per CLI session)
20
+ **Scale/Scope**: Workshop/PoC usage — small number of queries per session; single resource group deployment
21
+
22
+ ## Constitution Check
23
+
24
+ _GATE: Must pass before Phase 0 research. Re-check after Phase 1 design._
25
+
26
+ Default gates for this repository (sofIA Copilot CLI) — derived from `.specify/memory/constitution.md`:
27
+
28
+ - **Outcome-first discovery**: ✅ PASS — Deploys the web search backend that enables real-time company/industry research during the Discover phase (Step 1). Directly ties to the workshop's core value: grounding ideation in real-world context.
29
+ - **Secure-by-default**: ✅ PASS — Migrates from API key auth (`SOFIA_FOUNDRY_AGENT_KEY`) to `DefaultAzureCredential` (least privilege, no secrets in env vars). Legacy key vars trigger an error, not silent fallback. Logger redaction remains.
30
+ - **Node.js + TypeScript**: ✅ PASS — CLI integration uses `@azure/ai-projects` + `@azure/identity` TypeScript SDKs. Bicep + Bash for infrastructure only (not runtime code).
31
+ - **MCP-first**: ⚠️ EXCEPTION — The Foundry Agent Service does not expose an MCP server; the `@azure/ai-projects` SDK is the only supported integration surface. The tool is still registered as a Copilot SDK tool (`web.search`) and used by MCP-aware phases. Documented in Complexity Tracking.
32
+ - **Test-first (NON-NEGOTIABLE)**: ✅ PASS — All SDK integration code must follow Red→Green→Review. Unit tests for config validation, credential detection, and migration error. Integration tests with fakes for agent create/query/delete lifecycle. Bash deployment script validated via dry-run tests.
33
+ - **CLI transparency**: ✅ PASS — Deployment script streams progress (`az deployment` output, prerequisite check results, resource provisioning status). CLI surfaces web search availability/degradation to user. Teardown confirms resource deletion.
34
+
35
+ ## Project Structure
36
+
37
+ ### Documentation (this feature)
38
+
39
+ ```text
40
+ specs/005-ai-search-deploy/
41
+ ├── plan.md # This file
42
+ ├── research.md # Phase 0 output
43
+ ├── data-model.md # Phase 1 output
44
+ ├── quickstart.md # Phase 1 output
45
+ ├── contracts/ # Phase 1 output
46
+ │ └── web-search-tool.md
47
+ └── tasks.md # Phase 2 output (created by /speckit.tasks)
48
+ ```
49
+
50
+ ### Source Code (repository root)
51
+
52
+ ```text
53
+ infra/ # NEW — Infrastructure-as-Code
54
+ ├── main.bicep # Subscription-scoped entry point (resource group + module)
55
+ ├── resources.bicep # Resource-group-scoped module (account, model, project, capability hosts)
56
+ ├── main.bicepparam # Default parameters (swedencentral, gpt-4.1-mini)
57
+ ├── deploy.sh # One-command deployment script (FR-002), writes .env (FR-018)
58
+ └── teardown.sh # Resource group deletion (FR-007)
59
+
60
+ src/
61
+ ├── mcp/
62
+ │ └── webSearch.ts # MODIFIED — Migrate from raw HTTP + API key
63
+ │ # to @azure/ai-projects SDK + DefaultAzureCredential
64
+ │ # + ephemeral agent lifecycle (create/query/delete)
65
+ ├── cli/
66
+ │ ├── envLoader.ts # NEW — Loads .env file at startup via dotenv (FR-017)
67
+ │ ├── index.ts # MODIFIED — Calls loadEnvFile() at startup
68
+ │ └── preflight.ts # MODIFIED — Add legacy env var detection check (FR-016)
69
+ ├── shared/
70
+ │ └── copilotClient.ts # UNCHANGED — ToolDefinition interface still used
71
+ └── develop/
72
+ └── mcpContextEnricher.ts # MODIFIED — Update isWebSearchConfigured() import
73
+
74
+ docs/
75
+ └── environment.md # MODIFIED — Update env var documentation
76
+
77
+ tests/
78
+ ├── unit/
79
+ │ ├── webSearch.spec.ts # NEW — Config validation, credential auth, migration error
80
+ │ └── infraDeploy.spec.ts # NEW — Deploy script parameter validation (dry-run)
81
+ └── integration/
82
+ └── webSearchAgent.spec.ts # NEW — Ephemeral agent lifecycle with fakes
83
+ ```
84
+
85
+ **Structure Decision**: Single project layout (Option 1) with a new `infra/` directory at the repository root for Bicep templates and deployment scripts. This follows Azure conventions and keeps infrastructure separate from application code. The `src/mcp/webSearch.ts` module is modified in-place (not moved) since it already has the correct responsibility boundary.
86
+
87
+ ## Complexity Tracking
88
+
89
+ > **Fill ONLY if Constitution Check has violations that must be justified**
90
+
91
+ | Violation | Why Needed | Simpler Alternative Rejected Because |
92
+ | ------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------ |
93
+ | MCP-first exception: direct SDK call to Foundry Agent Service | Azure AI Foundry Agent Service has no MCP server; `@azure/ai-projects` is the only supported client SDK. The tool is still exposed as a Copilot SDK tool and consumed by MCP-aware phases. | No MCP adapter exists for this service. Writing a custom MCP proxy would add complexity with no ecosystem benefit. |
@@ -0,0 +1,96 @@
1
+ # Quickstart: AI Foundry Search Service Deployment
2
+
3
+ **Feature**: 005-ai-search-deploy
4
+ **Date**: 2026-03-01
5
+
6
+ ## Prerequisites
7
+
8
+ - **Azure CLI** installed and logged in (`az login`)
9
+ - **Azure subscription** with Owner or Contributor permissions
10
+ - **Node.js 20+** for running the sofIA CLI
11
+ - **Bash shell** (Linux, macOS, or Windows WSL/Git Bash)
12
+
13
+ ## 1. Deploy the Infrastructure
14
+
15
+ ```bash
16
+ # From the repository root (uses your current az CLI subscription)
17
+ ./infra/deploy.sh --resource-group sofia-workshop-rg
18
+ ```
19
+
20
+ This provisions:
21
+
22
+ - Azure AI Foundry account with SystemAssigned managed identity
23
+ - Model deployment (`gpt-4.1-mini` by default)
24
+ - Foundry project with Agent Service capability enabled
25
+
26
+ **Customize** (optional):
27
+
28
+ ```bash
29
+ ./infra/deploy.sh \
30
+ --resource-group sofia-workshop-rg \
31
+ --subscription <id> \
32
+ --location eastus \
33
+ --account-name my-foundry \
34
+ --model gpt-4o-mini
35
+ ```
36
+
37
+ ## 2. Configure sofIA
38
+
39
+ After deployment, the script automatically writes the required environment variables to a `.env` file in the workspace root:
40
+
41
+ ```bash
42
+ FOUNDRY_PROJECT_ENDPOINT="https://sofia-foundry-abc123.services.ai.azure.com/api/projects/sofia-project"
43
+ FOUNDRY_MODEL_DEPLOYMENT_NAME="gpt-4.1-mini"
44
+ ```
45
+
46
+ The sofIA CLI loads this `.env` file automatically at startup — no manual configuration needed.
47
+
48
+ > **Note**: No API key needed. sofIA authenticates using your Azure login credentials (`az login`).
49
+
50
+ ## 3. Verify Web Search
51
+
52
+ Start a sofIA workshop session:
53
+
54
+ ```bash
55
+ sofia workshop --new-session
56
+ ```
57
+
58
+ During the **Discover** phase, describe a real company. sofIA will automatically invoke the `web.search` tool to research the company, its competitors, and industry trends. Search results include clickable source URLs.
59
+
60
+ ## 4. Teardown (When Done)
61
+
62
+ ```bash
63
+ ./infra/teardown.sh --resource-group sofia-workshop-rg
64
+ ```
65
+
66
+ This deletes the resource group and all contained Azure resources to stop billing.
67
+
68
+ ## Migrating from Legacy Configuration
69
+
70
+ If you previously used `SOFIA_FOUNDRY_AGENT_ENDPOINT` / `SOFIA_FOUNDRY_AGENT_KEY`:
71
+
72
+ 1. **Remove** the old variables from your environment
73
+ 2. **Set** the new variables (`FOUNDRY_PROJECT_ENDPOINT`, `FOUNDRY_MODEL_DEPLOYMENT_NAME`)
74
+ 3. **Ensure** you are logged in via `az login`
75
+
76
+ The CLI will display an error if it detects the old variables, guiding you through the migration.
77
+
78
+ ## Troubleshooting
79
+
80
+ | Symptom | Cause | Fix |
81
+ | ---------------------------------------- | ------------------------------------ | --------------------------------------------------------------------------------------------------------- |
82
+ | "Web search not configured" | Env vars not set | Set `FOUNDRY_PROJECT_ENDPOINT` and `FOUNDRY_MODEL_DEPLOYMENT_NAME` |
83
+ | "Azure authentication failed" | Not logged in or token expired | Run `az login` |
84
+ | "Legacy web search env vars detected" | Old `SOFIA_FOUNDRY_*` vars still set | Remove them, set new vars |
85
+ | Deploy fails: "subscription not found" | Wrong subscription selected | Run `az account set --subscription <id>` |
86
+ | Deploy fails: "insufficient permissions" | Not Owner/Contributor | Ask an admin to grant access |
87
+ | Web search returns no results | Model didn't use web search | This is normal — the model decides when to search |
88
+ | "Web search disabled at subscription" | Admin blocked the tool | Run `az feature unregister --name OpenAI.BlockedTools.web_search --namespace Microsoft.CognitiveServices` |
89
+
90
+ ## Cost Expectations
91
+
92
+ - **Foundry account**: Free (billing is per-usage)
93
+ - **Model deployment**: Pay-per-token for `gpt-4.1-mini` queries
94
+ - **Grounding with Bing Search**: Usage-based ([pricing](https://www.microsoft.com/bing/apis/grounding-pricing))
95
+ - **Typical workshop**: A few dozen web search queries — minimal cost
96
+ - **Teardown immediately after workshop** to avoid idle resource charges
@@ -0,0 +1,187 @@
1
+ # Research: AI Foundry Search Service Deployment
2
+
3
+ **Feature**: 005-ai-search-deploy
4
+ **Date**: 2026-03-01
5
+ **Status**: Complete — all NEEDS CLARIFICATION items resolved
6
+
7
+ ## R1: Azure AI Foundry Bicep Resource Types
8
+
9
+ **Decision**: Use `Microsoft.CognitiveServices` resource provider (API version `2025-06-01`) with 5 resources for the basic agent setup.
10
+
11
+ **Rationale**: The basic (Microsoft-managed) setup minimizes complexity — no BYO Storage, Key Vault, Cosmos DB, or AI Search needed. Microsoft manages these behind the scenes. This aligns with FR-008 (basic agent setup) and the workshop/PoC use case.
12
+
13
+ **Required Resources**:
14
+
15
+ | # | Bicep Resource Type | Purpose |
16
+ |---|---------------------|---------|
17
+ | 1 | `Microsoft.CognitiveServices/accounts` (kind: `AIServices`) | Foundry account with `allowProjectManagement: true` and `customSubDomainName` |
18
+ | 2 | `Microsoft.CognitiveServices/accounts/deployments` | Model deployment (default: `gpt-4.1-mini`, version `2025-04-14`, SKU `GlobalStandard`) |
19
+ | 3 | `Microsoft.CognitiveServices/accounts/projects` | Foundry project — provides the endpoint URL |
20
+ | 4 | `Microsoft.CognitiveServices/accounts/capabilityHosts` | Account-level capability host (`capabilityHostKind: 'Agents'`) |
21
+ | 5 | `Microsoft.CognitiveServices/accounts/projects/capabilityHosts` | Project-level capability host (basic setup = empty connections) |
22
+
23
+ **Alternatives considered**:
24
+ - **Azure Verified Module (`br/public:avm/ptn/ai-ml/ai-foundry`)**: Less transparent, harder to document each resource per FR-011. Rejected for PoC simplicity.
25
+ - **Standard agent setup (BYO resources)**: Requires Cosmos DB, Storage, Key Vault, AI Search, multiple role assignments. Over-engineered for workshop scenario.
26
+
27
+ **Gotchas**:
28
+ - `customSubDomainName` is mandatory and must be globally unique — generate with a suffix (e.g., `sofia-<uniqueString>`)
29
+ - `allowProjectManagement: true` is required for child projects
30
+ - Capability hosts cannot be updated after creation; must delete and recreate
31
+ - Account capability host must be created before project capability host (`dependsOn`)
32
+ - Model deployment must exist before the account capability host references it
33
+
34
+ ## R2: Model Deployment Configuration
35
+
36
+ **Decision**: Default to `gpt-4.1-mini` with `GlobalStandard` SKU, version `2025-04-14`.
37
+
38
+ **Rationale**: `gpt-4.1-mini` supports `web_search_preview` and is cost-effective for workshop scenarios. `GlobalStandard` SKU routes to the nearest available region, providing the broadest availability. The spec (FR-012) explicitly requires `gpt-4.1-mini` as default.
39
+
40
+ **Alternatives considered**:
41
+ - **`gpt-4.1`**: More capable but higher cost. Unnecessary for web search query routing.
42
+ - **`gpt-4o-mini`**: Also supported but `gpt-4.1-mini` is newer and matches the spec decision.
43
+ - **`Standard` SKU**: Regional-only deployment; model must be available in the exact account region. More restrictive than `GlobalStandard`.
44
+
45
+ ## R3: `web_search_preview` Region and Model Support
46
+
47
+ **Decision**: No region restrictions — `web_search_preview` is available in all 23 Agent Service regions, including `swedencentral`.
48
+
49
+ **Rationale**: Research confirms web search is universally available across all Agent Service regions. No deployment script region validation needed beyond basic AI Services availability.
50
+
51
+ **Supported model families**: gpt-4.1, gpt-4.1-mini, gpt-4.1-nano, gpt-4o, gpt-4o-mini, o3, o4-mini, o3-mini, o1, gpt-5. Notably NOT supported: DeepSeek, Llama, Grok.
52
+
53
+ ## R4: @azure/ai-projects SDK Integration Pattern
54
+
55
+ **Decision**: Use `@azure/ai-projects@beta` (v2.x preview) with `AIProjectClient`, `agents.createVersion()`, and OpenAI-style `responses.create()` pattern.
56
+
57
+ **Rationale**: This is the current official SDK documented at learn.microsoft.com for the Foundry Agent Service. It replaces the older `@azure/ai-agents` package and provides a unified API for agent lifecycle management.
58
+
59
+ **Key API Pattern**:
60
+
61
+ ```typescript
62
+ import { DefaultAzureCredential } from "@azure/identity";
63
+ import { AIProjectClient } from "@azure/ai-projects";
64
+
65
+ // 1. Create client
66
+ const project = new AIProjectClient(endpoint, new DefaultAzureCredential());
67
+ const openAIClient = await project.getOpenAIClient();
68
+
69
+ // 2. Create ephemeral agent with web search
70
+ const agent = await project.agents.createVersion("sofia-web-search", {
71
+ kind: "prompt",
72
+ model: deploymentName,
73
+ instructions: "You are a web search assistant...",
74
+ tools: [{ type: "web_search_preview" }],
75
+ });
76
+
77
+ // 3. Create conversation, send message, get response
78
+ const conversation = await openAIClient.conversations.create();
79
+ const response = await openAIClient.responses.create(
80
+ { conversation: conversation.id, input: query },
81
+ { body: { agent: { name: agent.name, type: "agent_reference" } } },
82
+ );
83
+
84
+ // 4. Extract citations
85
+ for (const item of response.output) {
86
+ if (item.type === "message") {
87
+ for (const content of item.content) {
88
+ if (content.type === "output_text" && content.annotations) {
89
+ for (const annotation of content.annotations) {
90
+ if (annotation.type === "url_citation") {
91
+ // { url, start_index, end_index }
92
+ }
93
+ }
94
+ }
95
+ }
96
+ }
97
+ }
98
+
99
+ // 5. Cleanup
100
+ await openAIClient.conversations.delete(conversation.id);
101
+ await project.agents.deleteVersion(agent.name, agent.version);
102
+ ```
103
+
104
+ **Alternatives considered**:
105
+ - **`@azure/ai-agents` (classic API)**: Older `AgentsClient` with threads/runs pattern. Still works but being superseded by `AIProjectClient`.
106
+ - **Raw HTTP POST (current pattern)**: Requires manual token management, no built-in credential chain. Rejected for security and maintainability.
107
+
108
+ ## R5: Authentication Migration
109
+
110
+ **Decision**: Replace API key auth (`SOFIA_FOUNDRY_AGENT_KEY`) with `DefaultAzureCredential` from `@azure/identity`.
111
+
112
+ **Rationale**: `DefaultAzureCredential` provides a credential chain that automatically discovers the best available credential (Azure CLI → Managed Identity → Environment). Eliminates secrets from environment variables. Aligns with FR-013 and the secure-by-default constitution principle.
113
+
114
+ **Credential chain order** (what `DefaultAzureCredential` tries):
115
+ 1. `EnvironmentCredential` (`AZURE_CLIENT_ID` + `AZURE_TENANT_ID` + `AZURE_CLIENT_SECRET`)
116
+ 2. `WorkloadIdentityCredential` (Kubernetes)
117
+ 3. `ManagedIdentityCredential` (Azure-hosted)
118
+ 4. `AzureDeveloperCliCredential` (`azd auth login`)
119
+ 5. `AzureCliCredential` (`az login`)
120
+ 6. `AzurePowerShellCredential` (`Connect-AzAccount`)
121
+
122
+ **Required RBAC role**: `Azure AI User` at the Foundry project scope.
123
+
124
+ **Environment variables (new)**:
125
+ - `FOUNDRY_PROJECT_ENDPOINT` — e.g. `https://<name>.services.ai.azure.com/api/projects/<project>`
126
+ - `FOUNDRY_MODEL_DEPLOYMENT_NAME` — e.g. `gpt-4.1-mini`
127
+
128
+ **Migration behavior** (FR-016): If legacy `SOFIA_FOUNDRY_AGENT_ENDPOINT` or `SOFIA_FOUNDRY_AGENT_KEY` are detected, CLI emits an error message with migration instructions. Old vars are never used.
129
+
130
+ ## R6: Deployment Script Design
131
+
132
+ **Decision**: Bash script (`deploy.sh`) wrapping `az deployment sub create` for subscription-level Bicep deployment, with prerequisite validation.
133
+
134
+ **Rationale**: Bash is portable across Linux, macOS, and WSL/Git Bash (FR-010). Subscription-level deployment is needed because the script auto-creates the resource group (FR-002). `az deployment sub create` handles this natively.
135
+
136
+ **Script flow**:
137
+ 1. Validate prerequisites: `az` CLI installed, user logged in, subscription accessible
138
+ 2. Accept parameters: subscription ID, resource group name, region (default: `swedencentral`), account name, model (default: `gpt-4.1-mini`)
139
+ 3. Generate unique subdomain name from account name
140
+ 4. Run `az deployment sub create` with Bicep template
141
+ 5. Query outputs: project endpoint URL, model deployment name
142
+ 6. Print configuration instructions for `FOUNDRY_PROJECT_ENDPOINT` and `FOUNDRY_MODEL_DEPLOYMENT_NAME`
143
+
144
+ **Teardown script** (`teardown.sh`):
145
+ 1. Accept resource group name
146
+ 2. Validate resource group exists (informational exit if not)
147
+ 3. Run `az group delete --yes --no-wait` for non-blocking deletion
148
+
149
+ ## R7: Copilot SDK Tool Registration
150
+
151
+ **Decision**: Keep the existing `web.search` tool name and `ToolDefinition` interface. The handler function internally calls the Foundry Agent Service SDK instead of raw HTTP.
152
+
153
+ **Rationale**: The Copilot SDK tool contract (tool name, parameters, handler signature) is unchanged — only the implementation behind `createWebSearchTool()` changes. This maintains backward compatibility with prompt references (`discover.md`, `develop.md`) and the `mcpContextEnricher.ts` integration.
154
+
155
+ **Integration pattern**: The `createWebSearchTool()` factory creates the `AIProjectClient` and an ephemeral agent on first call. The agent and conversation are reused for the session lifetime. On session end (or error), the agent and conversation are cleaned up.
156
+
157
+ **Alternatives considered**:
158
+ - **Create agent per query**: Too expensive — agent creation has latency. Rejected.
159
+ - **Persistent agent (not deleted)**: Would accumulate agents in the Foundry project. Rejected per FR-015 (ephemeral lifecycle).
160
+ - **Lazy initialization**: Agent created on first `web.search` call, not on session start. This avoids agent creation overhead when web search is never invoked. **This is the chosen pattern** — create lazily, delete on session end.
161
+
162
+ ## R8: Ephemeral Agent Lifecycle
163
+
164
+ **Decision**: Lazy creation on first web search call, automatic deletion on process exit or session end.
165
+
166
+ **Rationale**: Creating the agent at session start adds unnecessary latency if web search is never used. Creating on first call amortizes the cost and ensures cleanup happens reliably.
167
+
168
+ **Implementation**:
169
+ - `webSearch.ts` maintains a module-level `AgentSession` (agent ID, conversation ID, client references)
170
+ - First call to `web.search` handler triggers `AgentSession.initialize()` — creates agent + conversation
171
+ - Subsequent calls reuse the same agent and conversation
172
+ - `AgentSession.cleanup()` deletes the conversation and agent version
173
+ - Register cleanup via `process.on('beforeExit', ...)` and expose a `destroyWebSearchSession()` for explicit cleanup from the workshop command
174
+
175
+ ## R9: New Dependencies Impact
176
+
177
+ **Decision**: Add `@azure/ai-projects@beta` and `@azure/identity` as production dependencies.
178
+
179
+ **Impact assessment**:
180
+ - `@azure/identity` is well-maintained (v4.13.0+), widely used, no known security issues
181
+ - `@azure/ai-projects@beta` is in preview — API may change. Pin to a specific beta version for stability
182
+ - Both are tree-shakeable ESM packages
183
+ - No conflicting peer dependencies with existing packages (`commander`, `zod`, `pino`, etc.)
184
+ - TypeScript types are included in both packages
185
+
186
+ **Alternatives considered**:
187
+ - **Optional dependencies**: Would complicate the build. Since web search is a core workshop tool, these should be required dependencies.