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,220 @@
|
|
|
1
|
+
# Contract: MCP Context Enricher (Real Integration)
|
|
2
|
+
|
|
3
|
+
**Feature**: 003-mcp-transport-integration
|
|
4
|
+
**Module**: `src/develop/mcpContextEnricher.ts`
|
|
5
|
+
**Status**: Authoritative design document (replaces stub behavior from Feature 002)
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Overview
|
|
10
|
+
|
|
11
|
+
`McpContextEnricher` conditionally queries three MCP servers to enrich LLM iteration prompts:
|
|
12
|
+
|
|
13
|
+
1. **Context7** — library documentation for PoC dependencies
|
|
14
|
+
2. **Azure MCP** — architecture guidance when plan references Azure services
|
|
15
|
+
3. **Web Search** — solutions to failing tests when stuck (2+ consecutive iterations)
|
|
16
|
+
|
|
17
|
+
All three methods use real MCP `callTool()` invocations (replacing hardcoded strings). All degrade gracefully when their respective servers are unavailable.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## queryContext7() Contract
|
|
22
|
+
|
|
23
|
+
### When Invoked
|
|
24
|
+
|
|
25
|
+
Only when:
|
|
26
|
+
- `mcpManager.isAvailable('context7')` is `true`
|
|
27
|
+
- `dependencies.length > 0`
|
|
28
|
+
|
|
29
|
+
### Tool Call Sequence (per dependency)
|
|
30
|
+
|
|
31
|
+
**Step 1: Resolve library ID**
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
mcpManager.callTool('context7', 'resolve-library-id', {
|
|
35
|
+
libraryName: dep, // e.g., 'express', 'zod'
|
|
36
|
+
}, { timeoutMs: 30_000 })
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Response field extraction for `libraryId`:
|
|
40
|
+
- `response.libraryId` (primary)
|
|
41
|
+
- `response.id` (fallback)
|
|
42
|
+
- If neither present: skip to fallback link (do not throw)
|
|
43
|
+
|
|
44
|
+
**Step 2: Query docs (only if libraryId resolved)**
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
mcpManager.callTool('context7', 'query-docs', {
|
|
48
|
+
libraryId, // e.g., '/expressjs/express'
|
|
49
|
+
topic: dep, // hint to focus the query
|
|
50
|
+
}, { timeoutMs: 30_000 })
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Response field extraction for documentation text:
|
|
54
|
+
- `response.content` (string, primary)
|
|
55
|
+
- `response.text` (string, fallback)
|
|
56
|
+
- If neither present: use fallback link
|
|
57
|
+
|
|
58
|
+
### Dependency Filter Rules
|
|
59
|
+
|
|
60
|
+
| Dependency | Skip? |
|
|
61
|
+
|------------|-------|
|
|
62
|
+
| Starts with `@types/` | ✅ Skip (type-only package) |
|
|
63
|
+
| `typescript` | ✅ Skip (well-known, no runtime docs needed) |
|
|
64
|
+
| `vitest` | ✅ Skip (test-only) |
|
|
65
|
+
| `node` | ✅ Skip |
|
|
66
|
+
| First 5 non-skipped deps only | Process (others skipped to limit tokens) |
|
|
67
|
+
|
|
68
|
+
### Fallback
|
|
69
|
+
|
|
70
|
+
When Context7 is unavailable OR a dependency resolution fails:
|
|
71
|
+
```
|
|
72
|
+
- **{dep}**: See https://www.npmjs.com/package/{dep} for API documentation
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Output Format
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
- **express**:
|
|
79
|
+
{documentation text from Context7}
|
|
80
|
+
|
|
81
|
+
- **zod**:
|
|
82
|
+
{documentation text from Context7}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## queryAzureMcp() Contract
|
|
88
|
+
|
|
89
|
+
### When Invoked
|
|
90
|
+
|
|
91
|
+
Only when:
|
|
92
|
+
- `mcpManager.isAvailable('azure')` is `true`
|
|
93
|
+
- `architectureNotes` contains at least one Azure keyword (existing detection logic)
|
|
94
|
+
|
|
95
|
+
### Tool Call
|
|
96
|
+
|
|
97
|
+
```typescript
|
|
98
|
+
mcpManager.callTool('azure', 'documentation', {
|
|
99
|
+
query: `Best practices for ${detectedKeywords.join(', ')} in Azure`,
|
|
100
|
+
}, { timeoutMs: 30_000 })
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Response field extraction:
|
|
104
|
+
- `response.content` (string, primary)
|
|
105
|
+
- `response.text` (string, fallback)
|
|
106
|
+
- If neither: fall through to static guidance
|
|
107
|
+
|
|
108
|
+
### Fallback (when Azure MCP unavailable or call fails)
|
|
109
|
+
|
|
110
|
+
Return static guidance string (existing behavior):
|
|
111
|
+
```
|
|
112
|
+
Detected Azure services: {detected.join(', ')}
|
|
113
|
+
Use the @azure/identity DefaultAzureCredential for authentication.
|
|
114
|
+
Prefer connection strings from environment variables (never hardcode).
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## queryWebSearch() Contract
|
|
120
|
+
|
|
121
|
+
### When Invoked
|
|
122
|
+
|
|
123
|
+
Only when:
|
|
124
|
+
- `isWebSearchConfigured()` returns `true` (env var `AZURE_AI_FOUNDRY_ENDPOINT` set)
|
|
125
|
+
- `stuckIterations >= 2`
|
|
126
|
+
- `failingTests.length > 0`
|
|
127
|
+
|
|
128
|
+
### Invocation Priority
|
|
129
|
+
|
|
130
|
+
1. **Prefer MCP-based search** (if `mcpManager.isAvailable('websearch')`):
|
|
131
|
+
```typescript
|
|
132
|
+
mcpManager.callTool('websearch', 'search', {
|
|
133
|
+
query: `how to fix: ${failingTests.slice(0, 3).join('; ')}`,
|
|
134
|
+
}, { timeoutMs: 30_000 })
|
|
135
|
+
```
|
|
136
|
+
Response: `response.content` or `response.text`
|
|
137
|
+
|
|
138
|
+
2. **Fall back to Azure AI Foundry bridge** (existing `webSearch.ts` implementation):
|
|
139
|
+
```typescript
|
|
140
|
+
// Already implemented in src/mcp/webSearch.ts
|
|
141
|
+
webSearchClient.search(query)
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Output Format
|
|
145
|
+
|
|
146
|
+
When results are returned:
|
|
147
|
+
```
|
|
148
|
+
Search results for: "{query}"
|
|
149
|
+
|
|
150
|
+
{formatted search results}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
When no results available:
|
|
154
|
+
```
|
|
155
|
+
Web search for: "{query}" — no results available in this environment.
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## enrich() Orchestration Contract
|
|
161
|
+
|
|
162
|
+
```typescript
|
|
163
|
+
async enrich(options: EnricherOptions): Promise<EnrichedContext>
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Execution Order
|
|
167
|
+
|
|
168
|
+
1. Context7 query (parallel-safe, independent)
|
|
169
|
+
2. Azure MCP query (parallel-safe, independent)
|
|
170
|
+
3. Web search (only if stuck — gated by `stuckIterations >= 2`)
|
|
171
|
+
|
|
172
|
+
**Parallelism**: Queries 1 and 2 MAY be run concurrently with `Promise.allSettled()` to reduce latency. Web search runs sequentially after both to avoid unnecessary API calls when Context7 already unblocks the LLM.
|
|
173
|
+
|
|
174
|
+
### EnrichedContext Assembly
|
|
175
|
+
|
|
176
|
+
```typescript
|
|
177
|
+
{
|
|
178
|
+
libraryDocs, // from Context7 (undefined if unavailable)
|
|
179
|
+
azureGuidance, // from Azure MCP (undefined if unavailable)
|
|
180
|
+
webSearchResults, // from web search (undefined if not stuck or unavailable)
|
|
181
|
+
combined: parts.join('\n\n'), // non-empty parts assembled as markdown sections
|
|
182
|
+
}
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
## Graceful Degradation Matrix
|
|
188
|
+
|
|
189
|
+
| Server | Unavailable Behavior |
|
|
190
|
+
|--------|---------------------|
|
|
191
|
+
| `context7` | Returns npm links instead of real docs. `combined` omits Context7 section. |
|
|
192
|
+
| `azure` | Returns static guidance string. `combined` uses static string. |
|
|
193
|
+
| `websearch` | Falls back to Azure AI Foundry bridge. If also unavailable, returns placeholder string. |
|
|
194
|
+
| All unavailable | `combined` is empty string. Ralph Loop continues with LLM's baseline knowledge. |
|
|
195
|
+
|
|
196
|
+
---
|
|
197
|
+
|
|
198
|
+
## Acceptance Tests
|
|
199
|
+
|
|
200
|
+
| Test | Type | Description |
|
|
201
|
+
|------|------|-------------|
|
|
202
|
+
| `queryContext7 calls resolve-library-id for each dependency` | unit | Verify tool calls dispatched |
|
|
203
|
+
| `queryContext7 uses libraryId from response.libraryId` | unit | Primary field extraction |
|
|
204
|
+
| `queryContext7 uses libraryId from response.id as fallback` | unit | Fallback field extraction |
|
|
205
|
+
| `queryContext7 skips @types/* dependencies` | unit | Filter rule |
|
|
206
|
+
| `queryContext7 skips typescript and vitest dependencies` | unit | Filter rule |
|
|
207
|
+
| `queryContext7 processes max 5 non-skipped deps` | unit | Limit rule |
|
|
208
|
+
| `queryContext7 returns npm link when resolve-library-id fails` | unit | Graceful degradation |
|
|
209
|
+
| `queryContext7 returns npm link when libraryId missing` | unit | No libraryId in response |
|
|
210
|
+
| `queryContext7 returns undefined when context7 unavailable` | unit | `isAvailable('context7')` false |
|
|
211
|
+
| `queryAzureMcp calls documentation tool with detected keywords` | unit | Tool dispatched with correct query |
|
|
212
|
+
| `queryAzureMcp extracts content from response.content` | unit | Primary field |
|
|
213
|
+
| `queryAzureMcp falls back to static guidance on callTool error` | unit | Graceful degradation |
|
|
214
|
+
| `queryAzureMcp returns undefined when azure unavailable` | unit | `isAvailable('azure')` false |
|
|
215
|
+
| `queryWebSearch calls websearch.search when server available` | unit | MCP tool dispatch |
|
|
216
|
+
| `queryWebSearch uses Azure AI Foundry bridge as fallback` | unit | Bridge used when MCP unavailable |
|
|
217
|
+
| `queryWebSearch returns undefined when not configured` | unit | `isWebSearchConfigured()` false |
|
|
218
|
+
| `enrich returns combined string with all available contexts` | unit | All three sections present |
|
|
219
|
+
| `enrich skips web search when stuckIterations < 2` | unit | Gate enforced |
|
|
220
|
+
| `enrich handles all servers unavailable gracefully` | unit | Empty combined, no throws |
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
# Contract: Discovery Phase Enrichment
|
|
2
|
+
|
|
3
|
+
**Feature**: 003-mcp-transport-integration
|
|
4
|
+
**Modules**: `src/phases/discoveryEnricher.ts`, `src/shared/schemas/session.ts`
|
|
5
|
+
**Status**: Authoritative design document
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Overview
|
|
10
|
+
|
|
11
|
+
After the user provides company and team information in Step 1 of the discovery workshop, the system optionally enriches the session with:
|
|
12
|
+
1. **Web search results** — recent company news, competitor activity, industry trends
|
|
13
|
+
2. **WorkIQ insights** — internal team collaboration patterns and expertise (requires explicit user consent and WorkIQ availability)
|
|
14
|
+
|
|
15
|
+
Enrichment is stored in `WorkshopSession.discovery.enrichment` and is referenced by subsequent phases (ideation, planning) to improve PoC relevance.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## DiscoveryEnricher Interface
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
// src/phases/discoveryEnricher.ts
|
|
23
|
+
|
|
24
|
+
export interface DiscoveryEnricherOptions {
|
|
25
|
+
/** Company and team summary from Step 1 (used to build search queries) */
|
|
26
|
+
companySummary: string;
|
|
27
|
+
/** MCP manager for WorkIQ tool calls */
|
|
28
|
+
mcpManager: McpManager;
|
|
29
|
+
/** IO for permission prompts and progress messages */
|
|
30
|
+
io: LoopIO;
|
|
31
|
+
/** Activity spinner for visual feedback */
|
|
32
|
+
spinner?: ActivitySpinner;
|
|
33
|
+
/** Web search client (defaults to production webSearch module) */
|
|
34
|
+
webSearchClient?: WebSearchClient;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export class DiscoveryEnricher {
|
|
38
|
+
/**
|
|
39
|
+
* Run the full enrichment flow: web search + optional WorkIQ.
|
|
40
|
+
* Returns a populated DiscoveryEnrichment object (may have empty fields
|
|
41
|
+
* if all enrichment sources are unavailable).
|
|
42
|
+
*/
|
|
43
|
+
async enrich(options: DiscoveryEnricherOptions): Promise<DiscoveryEnrichment>;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Run only the web search enrichment step.
|
|
47
|
+
* Does not prompt the user.
|
|
48
|
+
*/
|
|
49
|
+
async enrichFromWebSearch(
|
|
50
|
+
companySummary: string,
|
|
51
|
+
webSearchClient: WebSearchClient,
|
|
52
|
+
): Promise<Partial<DiscoveryEnrichment>>;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Run only the WorkIQ enrichment step.
|
|
56
|
+
* Prompts the user for consent before making any WorkIQ calls.
|
|
57
|
+
* Returns empty partial if user declines or WorkIQ unavailable.
|
|
58
|
+
*/
|
|
59
|
+
async enrichFromWorkIQ(
|
|
60
|
+
companySummary: string,
|
|
61
|
+
mcpManager: McpManager,
|
|
62
|
+
io: LoopIO,
|
|
63
|
+
): Promise<Partial<DiscoveryEnrichment>>;
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## enrich() Orchestration Flow
|
|
70
|
+
|
|
71
|
+
```
|
|
72
|
+
Step 1 input collected
|
|
73
|
+
│
|
|
74
|
+
▼
|
|
75
|
+
[Web Search Available?] ──no──► skip, continue
|
|
76
|
+
│ yes
|
|
77
|
+
▼
|
|
78
|
+
io.writeActivity('Searching for recent company and industry context...')
|
|
79
|
+
spinner.start('Enriching discovery context')
|
|
80
|
+
│
|
|
81
|
+
▼
|
|
82
|
+
enrichFromWebSearch(companySummary)
|
|
83
|
+
│
|
|
84
|
+
▼
|
|
85
|
+
[WorkIQ MCP Available?] ──no──► skip to session save
|
|
86
|
+
│ yes
|
|
87
|
+
▼
|
|
88
|
+
io.writeActivity('WorkIQ is available — it can analyze your team's internal context.')
|
|
89
|
+
io.prompt('May sofIA query WorkIQ for team insights? [y/N]')
|
|
90
|
+
│
|
|
91
|
+
├── no/timeout ──► skip WorkIQ
|
|
92
|
+
│
|
|
93
|
+
▼ yes
|
|
94
|
+
enrichFromWorkIQ(companySummary)
|
|
95
|
+
│
|
|
96
|
+
▼
|
|
97
|
+
Merge partial enrichments → DiscoveryEnrichment
|
|
98
|
+
Set enrichment.enrichedAt = new Date().toISOString()
|
|
99
|
+
Set enrichment.sourcesUsed = ['websearch'?, 'workiq'?]
|
|
100
|
+
session.discovery.enrichment = enrichment
|
|
101
|
+
onSessionUpdate(session)
|
|
102
|
+
spinner.stop()
|
|
103
|
+
io.writeActivity('Discovery context enriched ✓')
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## enrichFromWebSearch() Contract
|
|
109
|
+
|
|
110
|
+
### Web Search Query Strategy
|
|
111
|
+
|
|
112
|
+
Three sequential queries (or as many as return results before timeout):
|
|
113
|
+
|
|
114
|
+
| Query | Purpose |
|
|
115
|
+
|-------|---------|
|
|
116
|
+
| `"${company name} recent news 2024 2025"` | Company news |
|
|
117
|
+
| `"${company name} competitors market 2024"` | Competitor activity |
|
|
118
|
+
| `"${industry or domain} AI trends 2025"` | Industry trends |
|
|
119
|
+
|
|
120
|
+
The company name and industry are extracted from `companySummary` via simple keyword heuristic (first quoted proper noun, or first capitalized multi-word sequence).
|
|
121
|
+
|
|
122
|
+
### Response Mapping
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
// From WebSearchResult:
|
|
126
|
+
{
|
|
127
|
+
companyNews: results[0]?.results.map(r => `${r.title}: ${r.snippet}`),
|
|
128
|
+
competitorInfo: results[1]?.results.map(r => `${r.title}: ${r.snippet}`),
|
|
129
|
+
industryTrends: results[2]?.results.map(r => `${r.title}: ${r.snippet}`),
|
|
130
|
+
webSearchResults: [results].flatMap(r => r.results).map(r => r.snippet).join('\n'),
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Array fields are capped at 10 items each.
|
|
135
|
+
|
|
136
|
+
### Graceful Degradation
|
|
137
|
+
|
|
138
|
+
| Condition | Behavior |
|
|
139
|
+
|-----------|---------|
|
|
140
|
+
| Web search not configured (`isWebSearchConfigured()` false) | Return `{}` immediately, no prompt shown |
|
|
141
|
+
| `WebSearchResult.degraded` is `true` | Return `{}` with no error surfaced to user |
|
|
142
|
+
| Individual query throws | Log debug, continue with remaining queries |
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## enrichFromWorkIQ() Contract
|
|
147
|
+
|
|
148
|
+
### Permission Gate
|
|
149
|
+
|
|
150
|
+
**REQUIRED**: Show a consent prompt before any WorkIQ call:
|
|
151
|
+
|
|
152
|
+
```
|
|
153
|
+
sofIA can query WorkIQ to analyze your team's internal context
|
|
154
|
+
(meeting patterns, expertise areas, documentation gaps).
|
|
155
|
+
This requires access to your Microsoft 365 tenant.
|
|
156
|
+
|
|
157
|
+
May sofIA access WorkIQ for team insights? (y/N)
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
If the user responds `n` or `N` (or presses Enter for the default):
|
|
161
|
+
- Return `{}` immediately
|
|
162
|
+
- Do NOT call any WorkIQ tool
|
|
163
|
+
- Log at `info` level: `'User declined WorkIQ enrichment'`
|
|
164
|
+
|
|
165
|
+
### WorkIQ Tool Call
|
|
166
|
+
|
|
167
|
+
```typescript
|
|
168
|
+
mcpManager.callTool('workiq', 'analyze_team', {
|
|
169
|
+
summary: companySummary,
|
|
170
|
+
focus: ['expertise', 'collaboration', 'documentation'],
|
|
171
|
+
}, { timeoutMs: 30_000 })
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
Response field extraction:
|
|
175
|
+
- `response.teamExpertise` → `workiqInsights.teamExpertise`
|
|
176
|
+
- `response.collaborationPatterns` → `workiqInsights.collaborationPatterns`
|
|
177
|
+
- `response.documentationGaps` → `workiqInsights.documentationGaps`
|
|
178
|
+
- `response.insights` (fallback, split by newline) → all three fields
|
|
179
|
+
|
|
180
|
+
### Graceful Degradation
|
|
181
|
+
|
|
182
|
+
| Condition | Behavior |
|
|
183
|
+
|-----------|---------|
|
|
184
|
+
| `mcpManager.isAvailable('workiq')` false | Return `{}`, no prompt shown, log info `'WorkIQ not available'` |
|
|
185
|
+
| `callTool` throws `auth-failure` | Return `{}`, show message: `'WorkIQ authentication required — skipping team insights'` |
|
|
186
|
+
| `callTool` throws timeout/connection error | Return `{}`, log warn, show message: `'WorkIQ temporarily unavailable — skipping team insights'` |
|
|
187
|
+
| User declines consent | Return `{}`, no WorkIQ calls |
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
## Session Schema Extension
|
|
192
|
+
|
|
193
|
+
```typescript
|
|
194
|
+
// src/shared/schemas/session.ts
|
|
195
|
+
|
|
196
|
+
// DiscoveryEnrichmentSchema (new)
|
|
197
|
+
export const DiscoveryEnrichmentSchema = z.object({
|
|
198
|
+
webSearchResults: z.string().optional(),
|
|
199
|
+
companyNews: z.array(z.string()).max(10).optional(),
|
|
200
|
+
competitorInfo: z.array(z.string()).max(10).optional(),
|
|
201
|
+
industryTrends: z.array(z.string()).max(10).optional(),
|
|
202
|
+
workiqInsights: z.object({
|
|
203
|
+
teamExpertise: z.array(z.string()).max(10).optional(),
|
|
204
|
+
collaborationPatterns: z.array(z.string()).max(10).optional(),
|
|
205
|
+
documentationGaps: z.array(z.string()).max(10).optional(),
|
|
206
|
+
}).optional(),
|
|
207
|
+
enrichedAt: z.string().datetime().optional(),
|
|
208
|
+
sourcesUsed: z.array(z.string()).optional(),
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
// DiscoveryStateSchema (modified — add enrichment field)
|
|
212
|
+
export const DiscoveryStateSchema = z.object({
|
|
213
|
+
// ... existing fields ...
|
|
214
|
+
enrichment: DiscoveryEnrichmentSchema.optional(),
|
|
215
|
+
});
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
**Backward compatibility**: `enrichment` is optional. Sessions from Feature 001/002 parse without errors.
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
## Downstream Phase Usage
|
|
223
|
+
|
|
224
|
+
When `session.discovery.enrichment` is non-empty, the enrichment is injected into the ideation and planning phase prompts:
|
|
225
|
+
|
|
226
|
+
```markdown
|
|
227
|
+
## Discovery Context (from market research)
|
|
228
|
+
|
|
229
|
+
**Recent Company News**:
|
|
230
|
+
- {companyNews[0]}
|
|
231
|
+
- {companyNews[1]}
|
|
232
|
+
|
|
233
|
+
**Competitive Landscape**:
|
|
234
|
+
- {competitorInfo[0]}
|
|
235
|
+
|
|
236
|
+
**Industry Trends**:
|
|
237
|
+
- {industryTrends[0]}
|
|
238
|
+
|
|
239
|
+
**Internal Team Context** (from WorkIQ):
|
|
240
|
+
- Expertise: {workiqInsights.teamExpertise.join(', ')}
|
|
241
|
+
- Collaboration: {workiqInsights.collaborationPatterns.join(', ')}
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
This injection is the responsibility of the ideation/planning phase prompt builder, not `DiscoveryEnricher`.
|
|
245
|
+
|
|
246
|
+
---
|
|
247
|
+
|
|
248
|
+
## Acceptance Tests
|
|
249
|
+
|
|
250
|
+
| Test | Type | Description |
|
|
251
|
+
|------|------|-------------|
|
|
252
|
+
| `enrich runs web search when configured` | unit | webSearchClient called with company queries |
|
|
253
|
+
| `enrich skips web search when not configured` | unit | Returns without querying |
|
|
254
|
+
| `enrich shows WorkIQ prompt when available` | unit | io.prompt called before WorkIQ |
|
|
255
|
+
| `enrich calls WorkIQ when user consents` | unit | callTool('workiq', 'analyze_team', ...) dispatched |
|
|
256
|
+
| `enrich skips WorkIQ when user declines` | unit | No callTool for workiq |
|
|
257
|
+
| `enrich skips WorkIQ when not available` | unit | No prompt shown, no callTool |
|
|
258
|
+
| `enrich stores enrichedAt timestamp` | unit | ISO string set |
|
|
259
|
+
| `enrich stores sourcesUsed correctly` | unit | Reflects which sources ran |
|
|
260
|
+
| `enrichFromWebSearch builds three queries from companySummary` | unit | Query construction |
|
|
261
|
+
| `enrichFromWebSearch caps array fields at 10 items` | unit | Boundary check |
|
|
262
|
+
| `enrichFromWebSearch returns empty on degraded search` | unit | Graceful degradation |
|
|
263
|
+
| `enrichFromWorkIQ returns empty on auth-failure` | unit | Auth error handling |
|
|
264
|
+
| `enrichFromWorkIQ returns empty on timeout` | unit | Timeout handling |
|
|
265
|
+
| `enrichFromWorkIQ returns empty on user decline` | unit | No-consent path |
|
|
266
|
+
| `discoveryEnricher saves enrichment to session via onSessionUpdate` | integration | Session persistence |
|
|
267
|
+
| `phaseHandler injects enrichment into ideation prompt` | integration | Downstream usage |
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
# Contract: GitHub MCP Adapter (Real Integration)
|
|
2
|
+
|
|
3
|
+
**Feature**: 003-mcp-transport-integration
|
|
4
|
+
**Module**: `src/develop/githubMcpAdapter.ts`
|
|
5
|
+
**Status**: Authoritative design document (replaces stub behavior from Feature 002)
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Overview
|
|
10
|
+
|
|
11
|
+
`GitHubMcpAdapter` wraps two GitHub MCP tool calls — `create_repository` and `push_files` — and applies graceful degradation when the GitHub MCP server is unavailable. This contract defines the real behavior replacing the stubs introduced in Feature 002.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## createRepository()
|
|
16
|
+
|
|
17
|
+
### Call
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
mcpManager.callTool('github', 'create_repository', {
|
|
21
|
+
name: options.name, // repository name (slug)
|
|
22
|
+
description: options.description ?? '',
|
|
23
|
+
private: options.private ?? true,
|
|
24
|
+
}, { timeoutMs: 60_000 })
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### Response Mapping
|
|
28
|
+
|
|
29
|
+
The GitHub MCP `create_repository` tool returns a JSON object representing the created repository. Field extraction priority:
|
|
30
|
+
|
|
31
|
+
| Field to Extract | Try These Response Keys (in order) |
|
|
32
|
+
|------------------|------------------------------------|
|
|
33
|
+
| `repoUrl` | `response.html_url`, `response.url`, `response.clone_url` |
|
|
34
|
+
| `repoName` | `response.name`, `response.full_name`, or fallback to `options.name` |
|
|
35
|
+
|
|
36
|
+
### Success Return
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
{ available: true, repoUrl: 'https://github.com/org/repo', repoName: 'repo' }
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Failure Return
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
{ available: false, reason: '<error message>' }
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Conditions Returning `{ available: false }`
|
|
49
|
+
|
|
50
|
+
| Condition | Reason Logged |
|
|
51
|
+
|-----------|---------------|
|
|
52
|
+
| `isAvailable()` is `false` | `'GitHub MCP not available'` |
|
|
53
|
+
| `callTool` throws `McpTransportError` | Error message from transport |
|
|
54
|
+
| Response missing `html_url`, `url`, and `clone_url` | `'MCP response missing repository URL'` |
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## pushFiles()
|
|
59
|
+
|
|
60
|
+
### Pre-processing (ralphLoop.ts responsibility)
|
|
61
|
+
|
|
62
|
+
Before calling `pushFiles()`, the caller (Ralph Loop) MUST:
|
|
63
|
+
1. Read each file's content from disk using `readFile(resolve(outputDir, filePath), 'utf-8')`.
|
|
64
|
+
2. Skip files that fail to read — log a warning and omit them from the push.
|
|
65
|
+
3. Skip files outside the output directory (path traversal check using `isPathWithinDirectory`).
|
|
66
|
+
|
|
67
|
+
The `PushFilesOptions.files` array MUST contain actual file content — never empty strings.
|
|
68
|
+
|
|
69
|
+
### Call
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
mcpManager.callTool('github', 'push_files', {
|
|
73
|
+
owner: extractOwnerFromUrl(options.repoUrl), // extracted from repo URL
|
|
74
|
+
repo: extractRepoFromUrl(options.repoUrl), // extracted from repo URL
|
|
75
|
+
branch: options.branch ?? 'main',
|
|
76
|
+
message: options.commitMessage,
|
|
77
|
+
files: options.files.map(f => ({
|
|
78
|
+
path: f.path,
|
|
79
|
+
content: f.content, // actual file content (UTF-8 text)
|
|
80
|
+
})),
|
|
81
|
+
}, { timeoutMs: 60_000 })
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Response Mapping
|
|
85
|
+
|
|
86
|
+
| Field to Extract | Try These Response Keys |
|
|
87
|
+
|-----------------|------------------------|
|
|
88
|
+
| `commitSha` | `response.sha`, `response.commit.sha` |
|
|
89
|
+
|
|
90
|
+
### Success Return
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
{ available: true, commitSha: 'abc123def456' }
|
|
94
|
+
// commitSha is optional — may be undefined if the server doesn't return it
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Failure Return
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
{ available: false, reason: '<error message>' }
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## Post-Scaffold Push (RalphLoop Responsibility)
|
|
106
|
+
|
|
107
|
+
The Ralph Loop is responsible for an **initial scaffold push** immediately after npm install completes and before entering the iteration loop:
|
|
108
|
+
|
|
109
|
+
```
|
|
110
|
+
scaffold → npm install → push scaffold files → iteration 1 → iteration 2 → ...
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
**When to push**: Only if `githubAdapter.isAvailable()` AND a repo was created (non-null `repoUrl`).
|
|
114
|
+
|
|
115
|
+
**Files to push**: All `scaffoldResult.createdFiles` (relative paths within `outputDir`).
|
|
116
|
+
|
|
117
|
+
**Content**: Read from disk at `resolve(outputDir, filePath)` — same pattern as iteration pushes.
|
|
118
|
+
|
|
119
|
+
**On failure**: Log warning and continue — scaffold push failure is not fatal.
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## Graceful Degradation Rules
|
|
124
|
+
|
|
125
|
+
1. When GitHub MCP is unavailable (`isAvailable()` returns `false`): both methods return `{ available: false }` immediately without attempting any tool call.
|
|
126
|
+
2. When a tool call throws any error: catch, log at `warn` level, return `{ available: false, reason: err.message }`.
|
|
127
|
+
3. When `createRepository` fails: the Ralph Loop continues with local-only output (no remote repo).
|
|
128
|
+
4. When `pushFiles` fails: the local PoC is intact; the remote repo may be stale. Log the failure with iteration number.
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## Acceptance Tests
|
|
133
|
+
|
|
134
|
+
| Test | Type | Description |
|
|
135
|
+
|------|------|-------------|
|
|
136
|
+
| `createRepository dispatches create_repository tool call` | unit | Verify callTool called with correct server/tool/args |
|
|
137
|
+
| `createRepository extracts repoUrl from html_url response field` | unit | Mock response with `html_url` |
|
|
138
|
+
| `createRepository extracts repoUrl from url response field` | unit | Mock response with `url` (fallback) |
|
|
139
|
+
| `createRepository returns available:false when MCP unavailable` | unit | `isAvailable()` returns false |
|
|
140
|
+
| `createRepository returns available:false on callTool error` | unit | Transport throws |
|
|
141
|
+
| `createRepository returns available:false when response has no URL` | unit | Mock response missing all URL fields |
|
|
142
|
+
| `pushFiles dispatches push_files with actual content` | unit | Verify `files[n].content` is non-empty string |
|
|
143
|
+
| `pushFiles extracts commitSha from response.sha` | unit | Mock response with `sha` |
|
|
144
|
+
| `pushFiles extracts commitSha from response.commit.sha` | unit | Mock response with nested sha |
|
|
145
|
+
| `pushFiles returns available:false when MCP unavailable` | unit | `isAvailable()` returns false |
|
|
146
|
+
| `pushFiles returns available:false on callTool error` | unit | Transport throws |
|
|
147
|
+
| `ralphLoop pushFiles sends non-empty file content` | integration | Verify content !== '' for all pushed files |
|
|
148
|
+
| `ralphLoop pushes scaffold files after npm install` | integration | Scaffold push happens before iteration 1 |
|
|
149
|
+
| `ralphLoop skips out-of-bounds paths before pushFiles` | integration | Path traversal attempt is logged and skipped |
|