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