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.
- package/.github/agents/copilot-instructions.md +39 -0
- package/.github/agents/speckit.analyze.agent.md +184 -0
- package/.github/agents/speckit.checklist.agent.md +294 -0
- package/.github/agents/speckit.clarify.agent.md +181 -0
- package/.github/agents/speckit.constitution.agent.md +84 -0
- package/.github/agents/speckit.implement.agent.md +135 -0
- package/.github/agents/speckit.plan.agent.md +90 -0
- package/.github/agents/speckit.specify.agent.md +258 -0
- package/.github/agents/speckit.tasks.agent.md +137 -0
- package/.github/agents/speckit.taskstoissues.agent.md +30 -0
- package/.github/copilot-instructions.md +257 -0
- package/.github/prompts/speckit.analyze.prompt.md +3 -0
- package/.github/prompts/speckit.checklist.prompt.md +3 -0
- package/.github/prompts/speckit.clarify.prompt.md +3 -0
- package/.github/prompts/speckit.constitution.prompt.md +3 -0
- package/.github/prompts/speckit.implement.prompt.md +3 -0
- package/.github/prompts/speckit.plan.prompt.md +3 -0
- package/.github/prompts/speckit.specify.prompt.md +3 -0
- package/.github/prompts/speckit.tasks.prompt.md +3 -0
- package/.github/prompts/speckit.taskstoissues.prompt.md +3 -0
- package/.github/workflows/ci.yml +38 -0
- package/.prettierrc +6 -0
- package/.specify/memory/constitution.md +181 -0
- package/.specify/scripts/bash/check-prerequisites.sh +166 -0
- package/.specify/scripts/bash/common.sh +156 -0
- package/.specify/scripts/bash/create-new-feature.sh +297 -0
- package/.specify/scripts/bash/setup-plan.sh +61 -0
- package/.specify/scripts/bash/update-agent-context.sh +810 -0
- package/.specify/templates/agent-file-template.md +28 -0
- package/.specify/templates/checklist-template.md +40 -0
- package/.specify/templates/constitution-template.md +50 -0
- package/.specify/templates/plan-template.md +113 -0
- package/.specify/templates/spec-template.md +115 -0
- package/.specify/templates/tasks-template.md +251 -0
- package/.vscode/mcp.json +42 -0
- package/.vscode/settings.json +19 -0
- package/CODE_OF_CONDUCT.md +128 -0
- package/LICENSE +21 -0
- package/README.md +213 -0
- package/dist/src/cli/developCommand.js +240 -0
- package/dist/src/cli/directCommands.js +143 -0
- package/dist/src/cli/envLoader.js +16 -0
- package/dist/src/cli/exportCommand.js +53 -0
- package/dist/src/cli/index.js +203 -0
- package/dist/src/cli/ioContext.js +109 -0
- package/dist/src/cli/preflight.js +57 -0
- package/dist/src/cli/statusCommand.js +110 -0
- package/dist/src/cli/workshopCommand.js +400 -0
- package/dist/src/develop/checkpointState.js +86 -0
- package/dist/src/develop/codeGenerator.js +319 -0
- package/dist/src/develop/dynamicScaffolder.js +226 -0
- package/dist/src/develop/githubMcpAdapter.js +122 -0
- package/dist/src/develop/index.js +15 -0
- package/dist/src/develop/mcpContextEnricher.js +195 -0
- package/dist/src/develop/pocScaffolder.js +542 -0
- package/dist/src/develop/ralphLoop.js +659 -0
- package/dist/src/develop/templateRegistry.js +364 -0
- package/dist/src/develop/testRunner.js +202 -0
- package/dist/src/logging/logger.js +58 -0
- package/dist/src/loop/conversationLoop.js +227 -0
- package/dist/src/loop/phaseSummarizer.js +87 -0
- package/dist/src/mcp/mcpManager.js +267 -0
- package/dist/src/mcp/mcpTransport.js +391 -0
- package/dist/src/mcp/retryPolicy.js +47 -0
- package/dist/src/mcp/webSearch.js +254 -0
- package/dist/src/phases/contextSummarizer.js +101 -0
- package/dist/src/phases/discoveryEnricher.js +156 -0
- package/dist/src/phases/phaseExtractors.js +222 -0
- package/dist/src/phases/phaseHandlers.js +328 -0
- package/dist/src/prompts/design.md +51 -0
- package/dist/src/prompts/develop-boundary.md +51 -0
- package/dist/src/prompts/develop.md +111 -0
- package/dist/src/prompts/discover.md +58 -0
- package/dist/src/prompts/ideate.md +56 -0
- package/dist/src/prompts/plan.md +51 -0
- package/dist/src/prompts/promptLoader.js +167 -0
- package/dist/src/prompts/promptLoader.ts +198 -0
- package/dist/src/prompts/select.md +47 -0
- package/dist/src/prompts/summarize/README.md +8 -0
- package/dist/src/prompts/summarize/design-summary.md +37 -0
- package/dist/src/prompts/summarize/develop-summary.md +25 -0
- package/dist/src/prompts/summarize/ideate-summary.md +27 -0
- package/dist/src/prompts/summarize/plan-summary.md +27 -0
- package/dist/src/prompts/summarize/select-summary.md +21 -0
- package/dist/src/prompts/system.md +28 -0
- package/dist/src/sessions/exportPaths.js +22 -0
- package/dist/src/sessions/exportWriter.js +406 -0
- package/dist/src/sessions/sessionManager.js +81 -0
- package/dist/src/sessions/sessionStore.js +65 -0
- package/dist/src/shared/activitySpinner.js +91 -0
- package/dist/src/shared/copilotClient.js +129 -0
- package/dist/src/shared/data/cards.json +1249 -0
- package/dist/src/shared/data/cardsLoader.js +51 -0
- package/dist/src/shared/errorClassifier.js +120 -0
- package/dist/src/shared/events.js +28 -0
- package/dist/src/shared/markdownRenderer.js +34 -0
- package/dist/src/shared/schemas/session.js +265 -0
- package/dist/src/shared/tableRenderer.js +20 -0
- package/dist/src/vendor/chalk.js +2 -0
- package/dist/src/vendor/cli-table3.js +3 -0
- package/dist/src/vendor/commander.js +2 -0
- package/dist/src/vendor/marked-terminal.js +3 -0
- package/dist/src/vendor/marked.js +2 -0
- package/dist/src/vendor/ora.js +2 -0
- package/dist/src/vendor/pino.js +2 -0
- package/dist/src/vendor/zod.js +2 -0
- package/dist/tests/e2e/developE2e.spec.js +126 -0
- package/dist/tests/e2e/developFailureE2e.spec.js +247 -0
- package/dist/tests/e2e/developPty.spec.js +75 -0
- package/dist/tests/e2e/discoveryWebSearchRelevance.spec.js +84 -0
- package/dist/tests/e2e/harness.spec.js +83 -0
- package/dist/tests/e2e/mcpLive.spec.js +120 -0
- package/dist/tests/e2e/newSession.e2e.spec.js +177 -0
- package/dist/tests/e2e/ralphLoopEnrichmentComparison.spec.js +62 -0
- package/dist/tests/e2e/workiqEnrichment.spec.js +56 -0
- package/dist/tests/e2e/zavaSimulation.spec.js +452 -0
- package/dist/tests/fixtures/test-fixture-project/src/add.js +3 -0
- package/dist/tests/fixtures/test-fixture-project/tests/failing.test.js +6 -0
- package/dist/tests/fixtures/test-fixture-project/tests/hanging.test.js +8 -0
- package/dist/tests/fixtures/test-fixture-project/tests/passing.test.js +10 -0
- package/dist/tests/fixtures/test-fixture-project/vitest.config.js +6 -0
- package/dist/tests/integration/autoStartConversation.spec.js +138 -0
- package/dist/tests/integration/defaultCommand.spec.js +147 -0
- package/dist/tests/integration/directCommandNonTty.spec.js +224 -0
- package/dist/tests/integration/directCommandTty.spec.js +151 -0
- package/dist/tests/integration/discoveryEnrichmentFlow.spec.js +175 -0
- package/dist/tests/integration/exportArtifacts.spec.js +202 -0
- package/dist/tests/integration/exportFallbackFlow.spec.js +99 -0
- package/dist/tests/integration/mcpDegradationFlow.spec.js +190 -0
- package/dist/tests/integration/mcpTransportFlow.spec.js +139 -0
- package/dist/tests/integration/newSessionFlow.spec.js +343 -0
- package/dist/tests/integration/pocGithubMcp.spec.js +186 -0
- package/dist/tests/integration/pocLocalFallback.spec.js +171 -0
- package/dist/tests/integration/pocScaffold.spec.js +163 -0
- package/dist/tests/integration/ralphLoopFlow.spec.js +359 -0
- package/dist/tests/integration/ralphLoopPartial.spec.js +368 -0
- package/dist/tests/integration/resumeAndBacktrack.spec.js +247 -0
- package/dist/tests/integration/spinnerLifecycle.spec.js +220 -0
- package/dist/tests/integration/summarizationFlow.spec.js +115 -0
- package/dist/tests/integration/testRunnerReal.spec.js +52 -0
- package/dist/tests/integration/webSearchAgent.spec.js +128 -0
- package/dist/tests/live/copilotSdkLive.spec.js +107 -0
- package/dist/tests/live/zavaFullWorkshop.spec.js +392 -0
- package/dist/tests/setup/loadEnv.js +3 -0
- package/dist/tests/unit/cli/developCommand.spec.js +567 -0
- package/dist/tests/unit/cli/directCommands.spec.js +279 -0
- package/dist/tests/unit/cli/envLoader.spec.js +58 -0
- package/dist/tests/unit/cli/ioContext.spec.js +119 -0
- package/dist/tests/unit/cli/preflight.spec.js +108 -0
- package/dist/tests/unit/cli/statusCommand.spec.js +111 -0
- package/dist/tests/unit/cli/workshopClientFallback.spec.js +80 -0
- package/dist/tests/unit/cli/workshopCommand.spec.js +329 -0
- package/dist/tests/unit/config/vitestEnvSetup.spec.js +13 -0
- package/dist/tests/unit/develop/checkpointState.spec.js +315 -0
- package/dist/tests/unit/develop/codeGenerator.spec.js +355 -0
- package/dist/tests/unit/develop/githubMcpAdapter.spec.js +231 -0
- package/dist/tests/unit/develop/mcpContextEnricher.spec.js +433 -0
- package/dist/tests/unit/develop/outputValidator.spec.js +119 -0
- package/dist/tests/unit/develop/pocScaffolder.spec.js +353 -0
- package/dist/tests/unit/develop/ralphLoop.spec.js +1248 -0
- package/dist/tests/unit/develop/templateRegistry.spec.js +85 -0
- package/dist/tests/unit/develop/testRunner.spec.js +249 -0
- package/dist/tests/unit/infraBicep.spec.js +92 -0
- package/dist/tests/unit/infraDeploy.spec.js +82 -0
- package/dist/tests/unit/infraTeardown.spec.js +63 -0
- package/dist/tests/unit/logging/logger.spec.js +43 -0
- package/dist/tests/unit/loop/conversationLoop.spec.js +592 -0
- package/dist/tests/unit/loop/phaseSummarizer.spec.js +141 -0
- package/dist/tests/unit/loop/streamingMarkdown.spec.js +147 -0
- package/dist/tests/unit/mcp/mcpManager.spec.js +279 -0
- package/dist/tests/unit/mcp/mcpTransport.spec.js +529 -0
- package/dist/tests/unit/mcp/retryPolicy.spec.js +218 -0
- package/dist/tests/unit/mcp/timeoutValidation.spec.js +46 -0
- package/dist/tests/unit/mcp/webSearch.spec.js +567 -0
- package/dist/tests/unit/phases/contextSummarizer.spec.js +140 -0
- package/dist/tests/unit/phases/discoveryEnricher.repeatCalls.spec.js +93 -0
- package/dist/tests/unit/phases/discoveryEnricher.spec.js +411 -0
- package/dist/tests/unit/phases/phaseExtractors.spec.js +352 -0
- package/dist/tests/unit/phases/phaseHandlers.spec.js +425 -0
- package/dist/tests/unit/prompts/promptLoader.spec.js +118 -0
- package/dist/tests/unit/schemas/pocSchemas.spec.js +412 -0
- package/dist/tests/unit/schemas/session.spec.js +257 -0
- package/dist/tests/unit/sessions/exportPaths.spec.js +31 -0
- package/dist/tests/unit/sessions/exportWriter.spec.js +655 -0
- package/dist/tests/unit/sessions/sessionManager.spec.js +151 -0
- package/dist/tests/unit/sessions/sessionStore.spec.js +116 -0
- package/dist/tests/unit/shared/activitySpinner.spec.js +175 -0
- package/dist/tests/unit/shared/cardsLoader.spec.js +76 -0
- package/dist/tests/unit/shared/copilotClient.spec.js +155 -0
- package/dist/tests/unit/shared/errorClassifier.spec.js +131 -0
- package/dist/tests/unit/shared/events.spec.js +55 -0
- package/dist/tests/unit/shared/markdownRenderer.spec.js +35 -0
- package/dist/tests/unit/shared/markdownRendererChunks.spec.js +70 -0
- package/dist/tests/unit/shared/tableRenderer.spec.js +34 -0
- package/dist/vitest.config.js +14 -0
- package/dist/vitest.live.config.js +18 -0
- package/docs/README.md +35 -0
- package/docs/architecture.md +169 -0
- package/docs/cli-usage.md +207 -0
- package/docs/environment.md +66 -0
- package/docs/export-format.md +146 -0
- package/docs/session-model.md +113 -0
- package/eslint.config.js +35 -0
- package/infra/deploy.sh +193 -0
- package/infra/gather-env.sh +211 -0
- package/infra/main.bicep +90 -0
- package/infra/main.bicepparam +18 -0
- package/infra/resources.bicep +134 -0
- package/infra/teardown.sh +114 -0
- package/package.json +63 -0
- package/specs/001-cli-workshop-rebuild/checklists/requirements.md +35 -0
- package/specs/001-cli-workshop-rebuild/contracts/cli.md +59 -0
- package/specs/001-cli-workshop-rebuild/contracts/export-summary-json.md +23 -0
- package/specs/001-cli-workshop-rebuild/contracts/session-json.md +30 -0
- package/specs/001-cli-workshop-rebuild/data-model.md +210 -0
- package/specs/001-cli-workshop-rebuild/plan.md +361 -0
- package/specs/001-cli-workshop-rebuild/quickstart.md +83 -0
- package/specs/001-cli-workshop-rebuild/research.md +116 -0
- package/specs/001-cli-workshop-rebuild/spec.md +240 -0
- package/specs/001-cli-workshop-rebuild/tasks.md +476 -0
- package/specs/002-poc-generation/contracts/poc-output.md +172 -0
- package/specs/002-poc-generation/contracts/ralph-loop.md +113 -0
- package/specs/002-poc-generation/data-model.md +172 -0
- package/specs/002-poc-generation/plan.md +109 -0
- package/specs/002-poc-generation/quickstart.md +97 -0
- package/specs/002-poc-generation/research.md +786 -0
- package/specs/002-poc-generation/spec.md +81 -0
- package/specs/002-poc-generation/tasks-fix.md +198 -0
- package/specs/002-poc-generation/tasks.md +252 -0
- package/specs/003-mcp-transport-integration/checklists/requirements.md +37 -0
- package/specs/003-mcp-transport-integration/contracts/context-enricher.md +220 -0
- package/specs/003-mcp-transport-integration/contracts/discovery-enricher.md +267 -0
- package/specs/003-mcp-transport-integration/contracts/github-adapter.md +149 -0
- package/specs/003-mcp-transport-integration/contracts/mcp-transport.md +288 -0
- package/specs/003-mcp-transport-integration/data-model.md +326 -0
- package/specs/003-mcp-transport-integration/plan.md +114 -0
- package/specs/003-mcp-transport-integration/quickstart.md +311 -0
- package/specs/003-mcp-transport-integration/research.md +395 -0
- package/specs/003-mcp-transport-integration/spec.md +234 -0
- package/specs/003-mcp-transport-integration/tasks.md +324 -0
- package/specs/003-next-spec-gaps.md +150 -0
- package/specs/004-dev-resume-hardening/checklists/requirements.md +37 -0
- package/specs/004-dev-resume-hardening/contracts/cli.md +160 -0
- package/specs/004-dev-resume-hardening/data-model.md +321 -0
- package/specs/004-dev-resume-hardening/plan.md +107 -0
- package/specs/004-dev-resume-hardening/quickstart.md +115 -0
- package/specs/004-dev-resume-hardening/research.md +142 -0
- package/specs/004-dev-resume-hardening/spec.md +221 -0
- package/specs/004-dev-resume-hardening/tasks.md +333 -0
- package/specs/005-ai-search-deploy/checklists/requirements.md +39 -0
- package/specs/005-ai-search-deploy/contracts/web-search-tool.md +241 -0
- package/specs/005-ai-search-deploy/data-model.md +130 -0
- package/specs/005-ai-search-deploy/plan.md +93 -0
- package/specs/005-ai-search-deploy/quickstart.md +96 -0
- package/specs/005-ai-search-deploy/research.md +187 -0
- package/specs/005-ai-search-deploy/spec.md +143 -0
- package/specs/005-ai-search-deploy/tasks.md +284 -0
- package/specs/006-workshop-extraction-fixes/checklists/requirements.md +61 -0
- package/specs/006-workshop-extraction-fixes/contracts/summarization-and-export.md +131 -0
- package/specs/006-workshop-extraction-fixes/data-model.md +149 -0
- package/specs/006-workshop-extraction-fixes/plan.md +123 -0
- package/specs/006-workshop-extraction-fixes/quickstart.md +101 -0
- package/specs/006-workshop-extraction-fixes/research.md +143 -0
- package/specs/006-workshop-extraction-fixes/spec.md +210 -0
- package/specs/006-workshop-extraction-fixes/tasks.md +316 -0
- package/src/cli/developCommand.ts +308 -0
- package/src/cli/directCommands.ts +195 -0
- package/src/cli/envLoader.ts +17 -0
- package/src/cli/exportCommand.ts +65 -0
- package/src/cli/index.ts +249 -0
- package/src/cli/ioContext.ts +139 -0
- package/src/cli/preflight.ts +86 -0
- package/src/cli/statusCommand.ts +118 -0
- package/src/cli/workshopCommand.ts +496 -0
- package/src/develop/checkpointState.ts +121 -0
- package/src/develop/codeGenerator.ts +402 -0
- package/src/develop/dynamicScaffolder.ts +284 -0
- package/src/develop/githubMcpAdapter.ts +199 -0
- package/src/develop/index.ts +34 -0
- package/src/develop/mcpContextEnricher.ts +279 -0
- package/src/develop/pocScaffolder.ts +646 -0
- package/src/develop/ralphLoop.ts +1044 -0
- package/src/develop/templateRegistry.ts +427 -0
- package/src/develop/testRunner.ts +276 -0
- package/src/logging/logger.ts +73 -0
- package/src/loop/conversationLoop.ts +355 -0
- package/src/loop/phaseSummarizer.ts +114 -0
- package/src/mcp/mcpManager.ts +365 -0
- package/src/mcp/mcpTransport.ts +562 -0
- package/src/mcp/retryPolicy.ts +87 -0
- package/src/mcp/webSearch.ts +388 -0
- package/src/originalPrompts/design_thinking.md +178 -0
- package/src/originalPrompts/design_thinking_persona.md +76 -0
- package/src/originalPrompts/document_generator_example.md +77 -0
- package/src/originalPrompts/document_generator_persona.md +47 -0
- package/src/originalPrompts/facilitator_persona.md +125 -0
- package/src/originalPrompts/guardrails.md +47 -0
- package/src/phases/contextSummarizer.ts +154 -0
- package/src/phases/discoveryEnricher.ts +223 -0
- package/src/phases/phaseExtractors.ts +247 -0
- package/src/phases/phaseHandlers.ts +450 -0
- package/src/prompts/design.md +51 -0
- package/src/prompts/develop-boundary.md +51 -0
- package/src/prompts/develop.md +111 -0
- package/src/prompts/discover.md +58 -0
- package/src/prompts/ideate.md +56 -0
- package/src/prompts/plan.md +51 -0
- package/src/prompts/promptLoader.ts +198 -0
- package/src/prompts/select.md +47 -0
- package/src/prompts/summarize/README.md +8 -0
- package/src/prompts/summarize/design-summary.md +37 -0
- package/src/prompts/summarize/develop-summary.md +25 -0
- package/src/prompts/summarize/ideate-summary.md +27 -0
- package/src/prompts/summarize/plan-summary.md +27 -0
- package/src/prompts/summarize/select-summary.md +21 -0
- package/src/prompts/system.md +28 -0
- package/src/sessions/exportPaths.ts +28 -0
- package/src/sessions/exportWriter.ts +490 -0
- package/src/sessions/sessionManager.ts +119 -0
- package/src/sessions/sessionStore.ts +69 -0
- package/src/shared/activitySpinner.ts +108 -0
- package/src/shared/copilotClient.ts +291 -0
- package/src/shared/data/cards.json +1249 -0
- package/src/shared/data/cardsLoader.ts +70 -0
- package/src/shared/errorClassifier.ts +160 -0
- package/src/shared/events.ts +103 -0
- package/src/shared/markdownRenderer.ts +44 -0
- package/src/shared/schemas/session.ts +346 -0
- package/src/shared/tableRenderer.ts +28 -0
- package/src/types/marked-terminal.d.ts +5 -0
- package/src/vendor/chalk.ts +2 -0
- package/src/vendor/cli-table3.ts +3 -0
- package/src/vendor/commander.ts +2 -0
- package/src/vendor/marked-terminal.ts +3 -0
- package/src/vendor/marked.ts +2 -0
- package/src/vendor/ora.ts +2 -0
- package/src/vendor/pino.ts +3 -0
- package/src/vendor/zod.ts +3 -0
- package/tests/e2e/developE2e.spec.ts +152 -0
- package/tests/e2e/developFailureE2e.spec.ts +289 -0
- package/tests/e2e/developPty.spec.ts +86 -0
- package/tests/e2e/discoveryWebSearchRelevance.spec.ts +103 -0
- package/tests/e2e/harness.spec.ts +104 -0
- package/tests/e2e/mcpLive.spec.ts +149 -0
- package/tests/e2e/newSession.e2e.spec.ts +245 -0
- package/tests/e2e/ralphLoopEnrichmentComparison.spec.ts +70 -0
- package/tests/e2e/workiqEnrichment.spec.ts +72 -0
- package/tests/e2e/zava-assessment/agent-interaction-script.md +258 -0
- package/tests/e2e/zava-assessment/company-profile.md +98 -0
- package/tests/e2e/zava-assessment/expected-results-checklist.md +454 -0
- package/tests/e2e/zavaSimulation.spec.ts +511 -0
- package/tests/fixtures/completedSession.json +141 -0
- package/tests/fixtures/test-fixture-project/package-lock.json +1585 -0
- package/tests/fixtures/test-fixture-project/package.json +12 -0
- package/tests/fixtures/test-fixture-project/src/add.ts +3 -0
- package/tests/fixtures/test-fixture-project/tests/failing.test.ts +7 -0
- package/tests/fixtures/test-fixture-project/tests/hanging.test.ts +9 -0
- package/tests/fixtures/test-fixture-project/tests/passing.test.ts +13 -0
- package/tests/fixtures/test-fixture-project/vitest.config.ts +7 -0
- package/tests/integration/autoStartConversation.spec.ts +168 -0
- package/tests/integration/defaultCommand.spec.ts +179 -0
- package/tests/integration/directCommandNonTty.spec.ts +260 -0
- package/tests/integration/directCommandTty.spec.ts +185 -0
- package/tests/integration/discoveryEnrichmentFlow.spec.ts +209 -0
- package/tests/integration/exportArtifacts.spec.ts +232 -0
- package/tests/integration/exportFallbackFlow.spec.ts +115 -0
- package/tests/integration/mcpDegradationFlow.spec.ts +231 -0
- package/tests/integration/mcpTransportFlow.spec.ts +178 -0
- package/tests/integration/newSessionFlow.spec.ts +406 -0
- package/tests/integration/pocGithubMcp.spec.ts +224 -0
- package/tests/integration/pocLocalFallback.spec.ts +205 -0
- package/tests/integration/pocScaffold.spec.ts +220 -0
- package/tests/integration/ralphLoopFlow.spec.ts +430 -0
- package/tests/integration/ralphLoopPartial.spec.ts +416 -0
- package/tests/integration/resumeAndBacktrack.spec.ts +278 -0
- package/tests/integration/spinnerLifecycle.spec.ts +270 -0
- package/tests/integration/summarizationFlow.spec.ts +135 -0
- package/tests/integration/testRunnerReal.spec.ts +63 -0
- package/tests/integration/webSearchAgent.spec.ts +155 -0
- package/tests/live/copilotSdkLive.spec.ts +149 -0
- package/tests/live/zavaFullWorkshop.spec.ts +515 -0
- package/tests/setup/loadEnv.ts +5 -0
- package/tests/unit/cli/developCommand.spec.ts +679 -0
- package/tests/unit/cli/directCommands.spec.ts +325 -0
- package/tests/unit/cli/envLoader.spec.ts +73 -0
- package/tests/unit/cli/ioContext.spec.ts +148 -0
- package/tests/unit/cli/preflight.spec.ts +125 -0
- package/tests/unit/cli/statusCommand.spec.ts +134 -0
- package/tests/unit/cli/workshopClientFallback.spec.ts +100 -0
- package/tests/unit/cli/workshopCommand.spec.ts +378 -0
- package/tests/unit/config/vitestEnvSetup.spec.ts +24 -0
- package/tests/unit/develop/checkpointState.spec.ts +378 -0
- package/tests/unit/develop/codeGenerator.spec.ts +447 -0
- package/tests/unit/develop/githubMcpAdapter.spec.ts +283 -0
- package/tests/unit/develop/mcpContextEnricher.spec.ts +564 -0
- package/tests/unit/develop/outputValidator.spec.ts +134 -0
- package/tests/unit/develop/pocScaffolder.spec.ts +451 -0
- package/tests/unit/develop/ralphLoop.spec.ts +1439 -0
- package/tests/unit/develop/templateRegistry.spec.ts +106 -0
- package/tests/unit/develop/testRunner.spec.ts +294 -0
- package/tests/unit/infraBicep.spec.ts +116 -0
- package/tests/unit/infraDeploy.spec.ts +102 -0
- package/tests/unit/infraTeardown.spec.ts +77 -0
- package/tests/unit/logging/logger.spec.ts +50 -0
- package/tests/unit/loop/conversationLoop.spec.ts +719 -0
- package/tests/unit/loop/phaseSummarizer.spec.ts +169 -0
- package/tests/unit/loop/streamingMarkdown.spec.ts +180 -0
- package/tests/unit/mcp/mcpManager.spec.ts +336 -0
- package/tests/unit/mcp/mcpTransport.spec.ts +689 -0
- package/tests/unit/mcp/retryPolicy.spec.ts +278 -0
- package/tests/unit/mcp/timeoutValidation.spec.ts +55 -0
- package/tests/unit/mcp/webSearch.spec.ts +718 -0
- package/tests/unit/phases/contextSummarizer.spec.ts +158 -0
- package/tests/unit/phases/discoveryEnricher.repeatCalls.spec.ts +125 -0
- package/tests/unit/phases/discoveryEnricher.spec.ts +512 -0
- package/tests/unit/phases/phaseExtractors.spec.ts +406 -0
- package/tests/unit/phases/phaseHandlers.spec.ts +483 -0
- package/tests/unit/prompts/promptLoader.spec.ts +144 -0
- package/tests/unit/schemas/pocSchemas.spec.ts +457 -0
- package/tests/unit/schemas/session.spec.ts +328 -0
- package/tests/unit/sessions/exportPaths.spec.ts +38 -0
- package/tests/unit/sessions/exportWriter.spec.ts +737 -0
- package/tests/unit/sessions/sessionManager.spec.ts +174 -0
- package/tests/unit/sessions/sessionStore.spec.ts +136 -0
- package/tests/unit/shared/activitySpinner.spec.ts +211 -0
- package/tests/unit/shared/cardsLoader.spec.ts +89 -0
- package/tests/unit/shared/copilotClient.spec.ts +185 -0
- package/tests/unit/shared/errorClassifier.spec.ts +152 -0
- package/tests/unit/shared/events.spec.ts +71 -0
- package/tests/unit/shared/markdownRenderer.spec.ts +42 -0
- package/tests/unit/shared/markdownRendererChunks.spec.ts +83 -0
- package/tests/unit/shared/tableRenderer.spec.ts +38 -0
- package/tsconfig.json +20 -0
- package/vitest.config.ts +15 -0
- package/vitest.live.config.ts +19 -0
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Discovery Phase Enrichment.
|
|
3
|
+
*
|
|
4
|
+
* After the user provides company information in Step 1, this module
|
|
5
|
+
* optionally enriches the session with web search results and WorkIQ insights.
|
|
6
|
+
*
|
|
7
|
+
* Contract: specs/003-mcp-transport-integration/contracts/discovery-enricher.md
|
|
8
|
+
*/
|
|
9
|
+
import type { McpManager } from '../mcp/mcpManager.js';
|
|
10
|
+
import type { LoopIO } from '../loop/conversationLoop.js';
|
|
11
|
+
import type { ActivitySpinner } from '../shared/activitySpinner.js';
|
|
12
|
+
import type { DiscoveryEnrichment } from '../shared/schemas/session.js';
|
|
13
|
+
import type { WebSearchResult } from '../mcp/webSearch.js';
|
|
14
|
+
|
|
15
|
+
// ── WebSearchClient interface ────────────────────────────────────────────────
|
|
16
|
+
|
|
17
|
+
export interface WebSearchClient {
|
|
18
|
+
search(query: string): Promise<WebSearchResult>;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// ── Options ──────────────────────────────────────────────────────────────────
|
|
22
|
+
|
|
23
|
+
export interface DiscoveryEnricherOptions {
|
|
24
|
+
/** Company and team summary from Step 1 */
|
|
25
|
+
companySummary: string;
|
|
26
|
+
/** MCP manager for WorkIQ tool calls */
|
|
27
|
+
mcpManager: McpManager;
|
|
28
|
+
/** IO for permission prompts and progress messages */
|
|
29
|
+
io: LoopIO;
|
|
30
|
+
/** Activity spinner for visual feedback */
|
|
31
|
+
spinner?: ActivitySpinner;
|
|
32
|
+
/** Web search client (defaults to production webSearch module) */
|
|
33
|
+
webSearchClient?: WebSearchClient;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// ── Helpers ──────────────────────────────────────────────────────────────────
|
|
37
|
+
|
|
38
|
+
const MAX_ITEMS = 10;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Extract a likely company name from the summary.
|
|
42
|
+
* Uses the first capitalized multi-word sequence or first noun phrase.
|
|
43
|
+
*/
|
|
44
|
+
function extractCompanyName(summary: string): string {
|
|
45
|
+
// Try quoted string first
|
|
46
|
+
const quoted = summary.match(/"([^"]+)"/);
|
|
47
|
+
if (quoted) return quoted[1];
|
|
48
|
+
// Try first capitalized multi-word sequence
|
|
49
|
+
const capitalized = summary.match(/\b([A-Z][a-zA-Z]*(?:\s+[A-Z][a-zA-Z]*)*)\b/);
|
|
50
|
+
if (capitalized) return capitalized[1];
|
|
51
|
+
// Fallback: first 3 words
|
|
52
|
+
return summary.split(/\s+/).slice(0, 3).join(' ');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Map search results to "Title: Snippet" strings, capped at MAX_ITEMS.
|
|
57
|
+
*/
|
|
58
|
+
function mapResults(results: Array<{ title: string; snippet: string }>): string[] {
|
|
59
|
+
return results.slice(0, MAX_ITEMS).map((r) => `${r.title}: ${r.snippet}`);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// ── DiscoveryEnricher ────────────────────────────────────────────────────────
|
|
63
|
+
|
|
64
|
+
export class DiscoveryEnricher {
|
|
65
|
+
/**
|
|
66
|
+
* Run the full enrichment flow: web search + optional WorkIQ.
|
|
67
|
+
*/
|
|
68
|
+
async enrich(options: DiscoveryEnricherOptions): Promise<DiscoveryEnrichment> {
|
|
69
|
+
const { companySummary, mcpManager, io, webSearchClient } = options;
|
|
70
|
+
|
|
71
|
+
let webResult: Partial<DiscoveryEnrichment> = {};
|
|
72
|
+
let workiqResult: Partial<DiscoveryEnrichment> = {};
|
|
73
|
+
|
|
74
|
+
// Run web search if client provided
|
|
75
|
+
if (webSearchClient) {
|
|
76
|
+
io.writeActivity('Searching for recent company and industry context...');
|
|
77
|
+
webResult = await this.enrichFromWebSearch(companySummary, webSearchClient);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Run WorkIQ if available
|
|
81
|
+
if (mcpManager.isAvailable('workiq')) {
|
|
82
|
+
workiqResult = await this.enrichFromWorkIQ(companySummary, mcpManager, io);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Merge results
|
|
86
|
+
const sourcesUsed = [...(webResult.sourcesUsed ?? []), ...(workiqResult.sourcesUsed ?? [])];
|
|
87
|
+
|
|
88
|
+
const enrichment: DiscoveryEnrichment = {
|
|
89
|
+
...webResult,
|
|
90
|
+
...workiqResult,
|
|
91
|
+
sourcesUsed: sourcesUsed.length > 0 ? sourcesUsed : undefined,
|
|
92
|
+
enrichedAt: new Date().toISOString(),
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
return enrichment;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Run only the web search enrichment step.
|
|
100
|
+
*/
|
|
101
|
+
async enrichFromWebSearch(
|
|
102
|
+
companySummary: string,
|
|
103
|
+
webSearchClient: WebSearchClient,
|
|
104
|
+
): Promise<Partial<DiscoveryEnrichment>> {
|
|
105
|
+
const companyName = extractCompanyName(companySummary);
|
|
106
|
+
|
|
107
|
+
// GET CURRENT YEAR for dynamic query generation
|
|
108
|
+
const currentYear = new Date().getFullYear();
|
|
109
|
+
|
|
110
|
+
// Construct multiple queries to cover different angles
|
|
111
|
+
|
|
112
|
+
const queries = [
|
|
113
|
+
`${companyName} recent news ${currentYear - 1} ${currentYear}`,
|
|
114
|
+
`${companyName} competitors market ${currentYear - 1}`,
|
|
115
|
+
`${companyName} industry AI trends ${currentYear}`,
|
|
116
|
+
];
|
|
117
|
+
|
|
118
|
+
const allSnippets: string[] = [];
|
|
119
|
+
let companyNews: string[] = [];
|
|
120
|
+
let competitorInfo: string[] = [];
|
|
121
|
+
let industryTrends: string[] = [];
|
|
122
|
+
|
|
123
|
+
for (let i = 0; i < queries.length; i++) {
|
|
124
|
+
try {
|
|
125
|
+
const result: WebSearchResult = await webSearchClient.search(queries[i]);
|
|
126
|
+
if (result.degraded) continue;
|
|
127
|
+
|
|
128
|
+
const mapped = mapResults(result.results);
|
|
129
|
+
if (mapped.length === 0) {
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
allSnippets.push(...result.results.map((r) => r.snippet));
|
|
134
|
+
|
|
135
|
+
if (i === 0) companyNews = mapped;
|
|
136
|
+
else if (i === 1) competitorInfo = mapped;
|
|
137
|
+
else if (i === 2) industryTrends = mapped;
|
|
138
|
+
|
|
139
|
+
// Stop after first successful query to avoid exhausting provider quotas
|
|
140
|
+
// across repeated enrichment calls in a single workshop run.
|
|
141
|
+
break;
|
|
142
|
+
} catch {
|
|
143
|
+
// Individual query failure — continue with remaining queries
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// If no results at all, return minimal object
|
|
149
|
+
if (allSnippets.length === 0) {
|
|
150
|
+
return {};
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return {
|
|
154
|
+
companyNews,
|
|
155
|
+
competitorInfo,
|
|
156
|
+
industryTrends,
|
|
157
|
+
webSearchResults: allSnippets.join('\n'),
|
|
158
|
+
sourcesUsed: ['websearch'],
|
|
159
|
+
enrichedAt: new Date().toISOString(),
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Run only the WorkIQ enrichment step.
|
|
165
|
+
* Prompts the user for consent before making any WorkIQ calls.
|
|
166
|
+
*/
|
|
167
|
+
async enrichFromWorkIQ(
|
|
168
|
+
companySummary: string,
|
|
169
|
+
mcpManager: McpManager,
|
|
170
|
+
io: LoopIO,
|
|
171
|
+
): Promise<Partial<DiscoveryEnrichment>> {
|
|
172
|
+
// Prompt for consent (default No)
|
|
173
|
+
const answer = await io.readInput('May sofIA access WorkIQ for team insights? (y/N) ');
|
|
174
|
+
if (!answer || answer.trim().toLowerCase() !== 'y') {
|
|
175
|
+
return {};
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
try {
|
|
179
|
+
const response = (await mcpManager.callTool(
|
|
180
|
+
'workiq',
|
|
181
|
+
'analyze_team',
|
|
182
|
+
{
|
|
183
|
+
summary: companySummary,
|
|
184
|
+
focus: ['expertise', 'collaboration', 'documentation'],
|
|
185
|
+
},
|
|
186
|
+
{ timeoutMs: 30_000 },
|
|
187
|
+
)) as Record<string, unknown>;
|
|
188
|
+
|
|
189
|
+
// Extract structured fields or fallback to insights string
|
|
190
|
+
let teamExpertise: string[] | undefined;
|
|
191
|
+
let collaborationPatterns: string[] | undefined;
|
|
192
|
+
let documentationGaps: string[] | undefined;
|
|
193
|
+
|
|
194
|
+
if (Array.isArray(response.teamExpertise)) {
|
|
195
|
+
teamExpertise = response.teamExpertise as string[];
|
|
196
|
+
collaborationPatterns = (response.collaborationPatterns ?? []) as string[];
|
|
197
|
+
documentationGaps = (response.documentationGaps ?? []) as string[];
|
|
198
|
+
} else if (typeof response.insights === 'string') {
|
|
199
|
+
// Fallback: split by newline
|
|
200
|
+
const lines = (response.insights as string).split('\n').filter(Boolean);
|
|
201
|
+
teamExpertise = lines.length > 0 ? [lines[0]] : [];
|
|
202
|
+
collaborationPatterns = lines.length > 1 ? [lines[1]] : [];
|
|
203
|
+
documentationGaps = lines.length > 2 ? [lines[2]] : [];
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
if (!teamExpertise) {
|
|
207
|
+
return {};
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
return {
|
|
211
|
+
workiqInsights: {
|
|
212
|
+
teamExpertise,
|
|
213
|
+
collaborationPatterns,
|
|
214
|
+
documentationGaps,
|
|
215
|
+
},
|
|
216
|
+
sourcesUsed: ['workiq'],
|
|
217
|
+
};
|
|
218
|
+
} catch {
|
|
219
|
+
// Graceful degradation — return empty on any error
|
|
220
|
+
return {};
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Phase extraction utilities.
|
|
3
|
+
*
|
|
4
|
+
* Parsers that extract structured data from LLM responses.
|
|
5
|
+
* Each extractor tries to find a JSON block in the response
|
|
6
|
+
* and validates it against the expected schema.
|
|
7
|
+
*/
|
|
8
|
+
import { z } from '../vendor/zod.js';
|
|
9
|
+
import {
|
|
10
|
+
businessContextSchema,
|
|
11
|
+
workflowMapSchema,
|
|
12
|
+
ideaCardSchema,
|
|
13
|
+
ideaEvaluationSchema,
|
|
14
|
+
selectedIdeaSchema,
|
|
15
|
+
implementationPlanSchema,
|
|
16
|
+
pocDevelopmentStateSchema,
|
|
17
|
+
type BusinessContext,
|
|
18
|
+
type WorkflowMap,
|
|
19
|
+
type IdeaCard,
|
|
20
|
+
type IdeaEvaluation,
|
|
21
|
+
type SelectedIdea,
|
|
22
|
+
type ImplementationPlan,
|
|
23
|
+
type PocDevelopmentState,
|
|
24
|
+
} from '../shared/schemas/session.js';
|
|
25
|
+
|
|
26
|
+
// ---------------------------------------------------------------------------
|
|
27
|
+
// JSON block extraction
|
|
28
|
+
// ---------------------------------------------------------------------------
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Extract the first JSON object or array from a response string.
|
|
32
|
+
* Tries:
|
|
33
|
+
* 1. Markdown fenced code block (```json ... ```)
|
|
34
|
+
* 2. First `{...}` or `[...]` in plain text
|
|
35
|
+
*
|
|
36
|
+
* Returns the parsed value, or null if nothing valid is found.
|
|
37
|
+
*/
|
|
38
|
+
export function extractJsonBlock(response: string): unknown {
|
|
39
|
+
// 1. Try fenced code block
|
|
40
|
+
const fenceMatch = response.match(/```(?:json)?\s*\n([\s\S]*?)\n```/);
|
|
41
|
+
if (fenceMatch) {
|
|
42
|
+
try {
|
|
43
|
+
return JSON.parse(fenceMatch[1].trim());
|
|
44
|
+
} catch {
|
|
45
|
+
// fall through
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// 2. Try raw JSON — find first { or [
|
|
50
|
+
const objectMatch = response.match(/(\{[\s\S]*\})/);
|
|
51
|
+
if (objectMatch) {
|
|
52
|
+
try {
|
|
53
|
+
return JSON.parse(objectMatch[1]);
|
|
54
|
+
} catch {
|
|
55
|
+
// fall through
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const arrayMatch = response.match(/(\[[\s\S]*\])/);
|
|
60
|
+
if (arrayMatch) {
|
|
61
|
+
try {
|
|
62
|
+
return JSON.parse(arrayMatch[1]);
|
|
63
|
+
} catch {
|
|
64
|
+
// fall through
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// ---------------------------------------------------------------------------
|
|
72
|
+
// Multi-block JSON extraction (FR-007)
|
|
73
|
+
// ---------------------------------------------------------------------------
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Extract ALL JSON objects/arrays from a response string.
|
|
77
|
+
* Uses /g flag for fenced blocks and bracket-depth counting for raw JSON.
|
|
78
|
+
* Returns an array of parsed values.
|
|
79
|
+
*/
|
|
80
|
+
export function extractAllJsonBlocks(response: string): unknown[] {
|
|
81
|
+
const results: unknown[] = [];
|
|
82
|
+
const seen = new Set<string>();
|
|
83
|
+
|
|
84
|
+
// 1. Try all fenced code blocks
|
|
85
|
+
const fenceRegex = /```(?:json)?\s*\n([\s\S]*?)\n```/g;
|
|
86
|
+
let fenceMatch;
|
|
87
|
+
while ((fenceMatch = fenceRegex.exec(response)) !== null) {
|
|
88
|
+
const raw = fenceMatch[1].trim();
|
|
89
|
+
if (seen.has(raw)) continue;
|
|
90
|
+
try {
|
|
91
|
+
const parsed = JSON.parse(raw);
|
|
92
|
+
results.push(parsed);
|
|
93
|
+
seen.add(raw);
|
|
94
|
+
} catch {
|
|
95
|
+
// skip invalid JSON
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// 2. Try bracket-depth counter for raw JSON (only if no fenced blocks found)
|
|
100
|
+
if (results.length === 0) {
|
|
101
|
+
for (const opener of ['{', '['] as const) {
|
|
102
|
+
const closer = opener === '{' ? '}' : ']';
|
|
103
|
+
let depth = 0;
|
|
104
|
+
let start = -1;
|
|
105
|
+
|
|
106
|
+
for (let i = 0; i < response.length; i++) {
|
|
107
|
+
const ch = response[i];
|
|
108
|
+
if (ch === opener) {
|
|
109
|
+
if (depth === 0) start = i;
|
|
110
|
+
depth++;
|
|
111
|
+
} else if (ch === closer) {
|
|
112
|
+
depth--;
|
|
113
|
+
if (depth === 0 && start >= 0) {
|
|
114
|
+
const raw = response.slice(start, i + 1);
|
|
115
|
+
if (!seen.has(raw)) {
|
|
116
|
+
try {
|
|
117
|
+
const parsed = JSON.parse(raw);
|
|
118
|
+
results.push(parsed);
|
|
119
|
+
seen.add(raw);
|
|
120
|
+
} catch {
|
|
121
|
+
// skip invalid
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
start = -1;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return results;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Extract the first JSON block from a response that validates against a Zod schema.
|
|
136
|
+
* Tries each extracted block with safeParse, returns the first valid match.
|
|
137
|
+
*/
|
|
138
|
+
export function extractJsonBlockForSchema<T>(
|
|
139
|
+
response: string,
|
|
140
|
+
schema: z.ZodType<T>,
|
|
141
|
+
): T | null {
|
|
142
|
+
const blocks = extractAllJsonBlocks(response);
|
|
143
|
+
for (const block of blocks) {
|
|
144
|
+
const result = schema.safeParse(block);
|
|
145
|
+
if (result.success) return result.data;
|
|
146
|
+
}
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// ---------------------------------------------------------------------------
|
|
151
|
+
// Typed extractors
|
|
152
|
+
// ---------------------------------------------------------------------------
|
|
153
|
+
|
|
154
|
+
function safeParse<T>(schema: z.ZodType<T>, data: unknown): T | null {
|
|
155
|
+
const result = schema.safeParse(data);
|
|
156
|
+
return result.success ? result.data : null;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Extract BusinessContext from an LLM response containing a JSON block.
|
|
161
|
+
*/
|
|
162
|
+
export function extractBusinessContext(response: string): BusinessContext | null {
|
|
163
|
+
const json = extractJsonBlock(response);
|
|
164
|
+
if (!json || typeof json !== 'object' || Array.isArray(json)) return null;
|
|
165
|
+
return safeParse(businessContextSchema, json);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Extract WorkflowMap from an LLM response containing a JSON block.
|
|
170
|
+
*/
|
|
171
|
+
export function extractWorkflow(response: string): WorkflowMap | null {
|
|
172
|
+
const json = extractJsonBlock(response);
|
|
173
|
+
if (!json || typeof json !== 'object' || Array.isArray(json)) return null;
|
|
174
|
+
return safeParse(workflowMapSchema, json);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Extract IdeaCard[] from an LLM response.
|
|
179
|
+
* Supports both a raw array and an `{ ideas: [...] }` wrapper.
|
|
180
|
+
*/
|
|
181
|
+
export function extractIdeas(response: string): IdeaCard[] | null {
|
|
182
|
+
const json = extractJsonBlock(response);
|
|
183
|
+
if (!json) return null;
|
|
184
|
+
|
|
185
|
+
// Raw array
|
|
186
|
+
if (Array.isArray(json)) {
|
|
187
|
+
const parsed = z.array(ideaCardSchema).safeParse(json);
|
|
188
|
+
return parsed.success ? parsed.data : null;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Wrapper object with `ideas` key
|
|
192
|
+
if (typeof json === 'object' && 'ideas' in (json as Record<string, unknown>)) {
|
|
193
|
+
const parsed = z.array(ideaCardSchema).safeParse((json as Record<string, unknown>).ideas);
|
|
194
|
+
return parsed.success ? parsed.data : null;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
return null;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Extract IdeaEvaluation from an LLM response.
|
|
202
|
+
*/
|
|
203
|
+
export function extractEvaluation(response: string): IdeaEvaluation | null {
|
|
204
|
+
const json = extractJsonBlock(response);
|
|
205
|
+
if (!json || typeof json !== 'object' || Array.isArray(json)) return null;
|
|
206
|
+
return safeParse(ideaEvaluationSchema, json);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Extract SelectedIdea from an LLM response.
|
|
211
|
+
*/
|
|
212
|
+
export function extractSelection(response: string): SelectedIdea | null {
|
|
213
|
+
const json = extractJsonBlock(response);
|
|
214
|
+
if (!json || typeof json !== 'object' || Array.isArray(json)) return null;
|
|
215
|
+
return safeParse(selectedIdeaSchema, json);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Extract ImplementationPlan from an LLM response.
|
|
220
|
+
*/
|
|
221
|
+
export function extractPlan(response: string): ImplementationPlan | null {
|
|
222
|
+
const json = extractJsonBlock(response);
|
|
223
|
+
if (!json || typeof json !== 'object' || Array.isArray(json)) return null;
|
|
224
|
+
return safeParse(implementationPlanSchema, json);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Extract a sessionName string from an LLM response JSON block.
|
|
229
|
+
* Returns the trimmed name, or null if not present/empty.
|
|
230
|
+
*/
|
|
231
|
+
export function extractSessionName(response: string): string | null {
|
|
232
|
+
const json = extractJsonBlock(response);
|
|
233
|
+
if (!json || typeof json !== 'object' || Array.isArray(json)) return null;
|
|
234
|
+
const obj = json as Record<string, unknown>;
|
|
235
|
+
if (typeof obj.sessionName !== 'string') return null;
|
|
236
|
+
const trimmed = obj.sessionName.trim();
|
|
237
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Extract PocDevelopmentState from an LLM response.
|
|
242
|
+
*/
|
|
243
|
+
export function extractPocState(response: string): PocDevelopmentState | null {
|
|
244
|
+
const json = extractJsonBlock(response);
|
|
245
|
+
if (!json || typeof json !== 'object' || Array.isArray(json)) return null;
|
|
246
|
+
return safeParse(pocDevelopmentStateSchema, json);
|
|
247
|
+
}
|