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,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* T040: Unit tests for PoC output validator.
|
|
3
|
+
*
|
|
4
|
+
* Tests all 8 validation checks from poc-output contract.
|
|
5
|
+
*/
|
|
6
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
7
|
+
import { mkdtemp, rm, writeFile, mkdir } from 'node:fs/promises';
|
|
8
|
+
import { join } from 'node:path';
|
|
9
|
+
import { tmpdir } from 'node:os';
|
|
10
|
+
import { validatePocOutput } from '../../../src/develop/pocScaffolder.js';
|
|
11
|
+
describe('validatePocOutput', () => {
|
|
12
|
+
let tmpDir;
|
|
13
|
+
beforeEach(async () => {
|
|
14
|
+
tmpDir = await mkdtemp(join(tmpdir(), 'sofia-validate-poc-'));
|
|
15
|
+
});
|
|
16
|
+
afterEach(async () => {
|
|
17
|
+
await rm(tmpDir, { recursive: true, force: true });
|
|
18
|
+
});
|
|
19
|
+
async function createCompleteScaffold() {
|
|
20
|
+
await mkdir(join(tmpDir, 'src'), { recursive: true });
|
|
21
|
+
await mkdir(join(tmpDir, 'tests'), { recursive: true });
|
|
22
|
+
await writeFile(join(tmpDir, 'package.json'), JSON.stringify({
|
|
23
|
+
name: 'test-poc',
|
|
24
|
+
version: '0.1.0',
|
|
25
|
+
scripts: { test: 'vitest run', build: 'tsc', start: 'node dist/index.js' },
|
|
26
|
+
dependencies: {},
|
|
27
|
+
devDependencies: { vitest: '^3.0.0', typescript: '^5.0.0' },
|
|
28
|
+
}), 'utf-8');
|
|
29
|
+
await writeFile(join(tmpDir, 'README.md'), '# Test PoC\n\nA test proof of concept.', 'utf-8');
|
|
30
|
+
await writeFile(join(tmpDir, 'tsconfig.json'), JSON.stringify({
|
|
31
|
+
compilerOptions: { target: 'ES2022', module: 'Node16', strict: true },
|
|
32
|
+
}), 'utf-8');
|
|
33
|
+
await writeFile(join(tmpDir, '.gitignore'), 'node_modules/\ndist/\ncoverage/\n', 'utf-8');
|
|
34
|
+
await writeFile(join(tmpDir, '.sofia-metadata.json'), JSON.stringify({
|
|
35
|
+
sessionId: 'test-001',
|
|
36
|
+
featureSpec: '002-poc-generation',
|
|
37
|
+
}), 'utf-8');
|
|
38
|
+
await writeFile(join(tmpDir, 'src', 'index.ts'), 'export function main() { return "ok"; }', 'utf-8');
|
|
39
|
+
await writeFile(join(tmpDir, 'tests', 'index.test.ts'), 'import { test, expect } from "vitest"; test("works", () => { expect(true).toBe(true); });', 'utf-8');
|
|
40
|
+
}
|
|
41
|
+
it('1. validates package.json exists and has test script', async () => {
|
|
42
|
+
await createCompleteScaffold();
|
|
43
|
+
const result = await validatePocOutput(tmpDir);
|
|
44
|
+
expect(result.valid).toBe(true);
|
|
45
|
+
});
|
|
46
|
+
it('2. reports missing package.json', async () => {
|
|
47
|
+
await createCompleteScaffold();
|
|
48
|
+
const { rm } = await import('node:fs/promises');
|
|
49
|
+
await rm(join(tmpDir, 'package.json'));
|
|
50
|
+
const result = await validatePocOutput(tmpDir);
|
|
51
|
+
expect(result.valid).toBe(false);
|
|
52
|
+
expect(result.missingFiles).toContain('package.json');
|
|
53
|
+
});
|
|
54
|
+
it('3. reports missing README.md', async () => {
|
|
55
|
+
await createCompleteScaffold();
|
|
56
|
+
const { rm } = await import('node:fs/promises');
|
|
57
|
+
await rm(join(tmpDir, 'README.md'));
|
|
58
|
+
const result = await validatePocOutput(tmpDir);
|
|
59
|
+
expect(result.valid).toBe(false);
|
|
60
|
+
expect(result.missingFiles).toContain('README.md');
|
|
61
|
+
});
|
|
62
|
+
it('4. reports missing tsconfig.json', async () => {
|
|
63
|
+
await createCompleteScaffold();
|
|
64
|
+
const { rm } = await import('node:fs/promises');
|
|
65
|
+
await rm(join(tmpDir, 'tsconfig.json'));
|
|
66
|
+
const result = await validatePocOutput(tmpDir);
|
|
67
|
+
expect(result.valid).toBe(false);
|
|
68
|
+
expect(result.missingFiles).toContain('tsconfig.json');
|
|
69
|
+
});
|
|
70
|
+
it('5. reports missing .gitignore', async () => {
|
|
71
|
+
await createCompleteScaffold();
|
|
72
|
+
const { rm } = await import('node:fs/promises');
|
|
73
|
+
await rm(join(tmpDir, '.gitignore'));
|
|
74
|
+
const result = await validatePocOutput(tmpDir);
|
|
75
|
+
expect(result.valid).toBe(false);
|
|
76
|
+
expect(result.missingFiles).toContain('.gitignore');
|
|
77
|
+
});
|
|
78
|
+
it('6. reports missing .sofia-metadata.json', async () => {
|
|
79
|
+
await createCompleteScaffold();
|
|
80
|
+
const { rm } = await import('node:fs/promises');
|
|
81
|
+
await rm(join(tmpDir, '.sofia-metadata.json'));
|
|
82
|
+
const result = await validatePocOutput(tmpDir);
|
|
83
|
+
expect(result.valid).toBe(false);
|
|
84
|
+
expect(result.missingFiles).toContain('.sofia-metadata.json');
|
|
85
|
+
});
|
|
86
|
+
it('7. reports no TypeScript files in src/', async () => {
|
|
87
|
+
await createCompleteScaffold();
|
|
88
|
+
const { rm } = await import('node:fs/promises');
|
|
89
|
+
await rm(join(tmpDir, 'src', 'index.ts'));
|
|
90
|
+
const result = await validatePocOutput(tmpDir);
|
|
91
|
+
expect(result.valid).toBe(false);
|
|
92
|
+
expect(result.errors.some((e) => e.includes('src/'))).toBe(true);
|
|
93
|
+
});
|
|
94
|
+
it('8. reports no test files in tests/', async () => {
|
|
95
|
+
await createCompleteScaffold();
|
|
96
|
+
const { rm } = await import('node:fs/promises');
|
|
97
|
+
await rm(join(tmpDir, 'tests', 'index.test.ts'));
|
|
98
|
+
const result = await validatePocOutput(tmpDir);
|
|
99
|
+
expect(result.valid).toBe(false);
|
|
100
|
+
expect(result.errors.some((e) => e.includes('tests/'))).toBe(true);
|
|
101
|
+
});
|
|
102
|
+
it('reports error when package.json has no test script', async () => {
|
|
103
|
+
await createCompleteScaffold();
|
|
104
|
+
await writeFile(join(tmpDir, 'package.json'), JSON.stringify({
|
|
105
|
+
name: 'test-poc',
|
|
106
|
+
scripts: { build: 'tsc' }, // no test script
|
|
107
|
+
}), 'utf-8');
|
|
108
|
+
const result = await validatePocOutput(tmpDir);
|
|
109
|
+
expect(result.valid).toBe(false);
|
|
110
|
+
expect(result.errors).toContain('package.json is missing "test" script');
|
|
111
|
+
});
|
|
112
|
+
it('reports valid=true when all checks pass', async () => {
|
|
113
|
+
await createCompleteScaffold();
|
|
114
|
+
const result = await validatePocOutput(tmpDir);
|
|
115
|
+
expect(result.valid).toBe(true);
|
|
116
|
+
expect(result.missingFiles).toHaveLength(0);
|
|
117
|
+
expect(result.errors).toHaveLength(0);
|
|
118
|
+
});
|
|
119
|
+
});
|
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* T011: Unit tests for PocScaffolder.
|
|
3
|
+
*
|
|
4
|
+
* Verifies scaffold creates all required files, skip-if-exists behavior,
|
|
5
|
+
* and ScaffoldContext population from session.
|
|
6
|
+
*/
|
|
7
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
8
|
+
import { mkdtemp, rm, readFile, readdir, stat } from 'node:fs/promises';
|
|
9
|
+
import { join } from 'node:path';
|
|
10
|
+
import { tmpdir } from 'node:os';
|
|
11
|
+
import { PocScaffolder, toKebabCase, validatePocOutput } from '../../../src/develop/pocScaffolder.js';
|
|
12
|
+
// ── Helpers ──────────────────────────────────────────────────────────────────
|
|
13
|
+
function makeSession(overrides) {
|
|
14
|
+
const now = new Date().toISOString();
|
|
15
|
+
return {
|
|
16
|
+
sessionId: 'scaffold-test-001',
|
|
17
|
+
schemaVersion: '1.0.0',
|
|
18
|
+
createdAt: now,
|
|
19
|
+
updatedAt: now,
|
|
20
|
+
phase: 'Develop',
|
|
21
|
+
status: 'Active',
|
|
22
|
+
participants: [],
|
|
23
|
+
artifacts: { generatedFiles: [] },
|
|
24
|
+
ideas: [
|
|
25
|
+
{
|
|
26
|
+
id: 'idea-1',
|
|
27
|
+
title: 'AI Route Optimizer',
|
|
28
|
+
description: 'Optimize delivery routes using AI.',
|
|
29
|
+
workflowStepIds: ['a1'],
|
|
30
|
+
},
|
|
31
|
+
],
|
|
32
|
+
selection: {
|
|
33
|
+
ideaId: 'idea-1',
|
|
34
|
+
selectionRationale: 'Best idea.',
|
|
35
|
+
confirmedByUser: true,
|
|
36
|
+
},
|
|
37
|
+
plan: {
|
|
38
|
+
milestones: [{ id: 'm1', title: 'Setup', items: ['Init project'] }],
|
|
39
|
+
architectureNotes: 'Node.js 20 + TypeScript + Express. Use vitest for tests.',
|
|
40
|
+
dependencies: ['express', 'typescript', 'vitest'],
|
|
41
|
+
},
|
|
42
|
+
...overrides,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
describe('toKebabCase', () => {
|
|
46
|
+
it('converts a title to kebab case', () => {
|
|
47
|
+
expect(toKebabCase('AI Route Optimizer')).toBe('ai-route-optimizer');
|
|
48
|
+
});
|
|
49
|
+
it('removes special characters', () => {
|
|
50
|
+
expect(toKebabCase('AI-Powered Delivery (Beta)')).toBe('ai-powered-delivery-beta');
|
|
51
|
+
});
|
|
52
|
+
it('handles leading/trailing spaces', () => {
|
|
53
|
+
expect(toKebabCase(' My Project ')).toBe('my-project');
|
|
54
|
+
});
|
|
55
|
+
it('truncates to 64 characters', () => {
|
|
56
|
+
const long = 'a'.repeat(100);
|
|
57
|
+
expect(toKebabCase(long)).toHaveLength(64);
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
describe('PocScaffolder', () => {
|
|
61
|
+
let tmpDir;
|
|
62
|
+
beforeEach(async () => {
|
|
63
|
+
tmpDir = await mkdtemp(join(tmpdir(), 'sofia-scaffold-test-'));
|
|
64
|
+
});
|
|
65
|
+
afterEach(async () => {
|
|
66
|
+
await rm(tmpDir, { recursive: true, force: true });
|
|
67
|
+
});
|
|
68
|
+
describe('buildContext', () => {
|
|
69
|
+
it('builds a context from a session', () => {
|
|
70
|
+
const session = makeSession();
|
|
71
|
+
const ctx = PocScaffolder.buildContext(session, tmpDir);
|
|
72
|
+
expect(ctx.sessionId).toBe('scaffold-test-001');
|
|
73
|
+
expect(ctx.projectName).toBe('ai-route-optimizer');
|
|
74
|
+
expect(ctx.ideaTitle).toBe('AI Route Optimizer');
|
|
75
|
+
expect(ctx.ideaDescription).toBe('Optimize delivery routes using AI.');
|
|
76
|
+
expect(ctx.outputDir).toBe(tmpDir);
|
|
77
|
+
});
|
|
78
|
+
it('infers Express framework from architecture notes', () => {
|
|
79
|
+
const session = makeSession();
|
|
80
|
+
const ctx = PocScaffolder.buildContext(session, tmpDir);
|
|
81
|
+
expect(ctx.techStack.framework).toBe('Express');
|
|
82
|
+
});
|
|
83
|
+
it('uses idea title as project name', () => {
|
|
84
|
+
const session = makeSession({
|
|
85
|
+
ideas: [{ id: 'idea-1', title: 'My Cool AI App', description: 'desc', workflowStepIds: [] }],
|
|
86
|
+
});
|
|
87
|
+
const ctx = PocScaffolder.buildContext(session, tmpDir);
|
|
88
|
+
expect(ctx.projectName).toBe('my-cool-ai-app');
|
|
89
|
+
});
|
|
90
|
+
it('falls back gracefully when no ideas or selection', () => {
|
|
91
|
+
const session = makeSession({ ideas: [], selection: undefined });
|
|
92
|
+
const ctx = PocScaffolder.buildContext(session, tmpDir);
|
|
93
|
+
expect(ctx.ideaTitle).toBe('AI PoC');
|
|
94
|
+
expect(ctx.projectName).toBe('ai-poc');
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
describe('scaffold', () => {
|
|
98
|
+
it('creates all required files', async () => {
|
|
99
|
+
const session = makeSession();
|
|
100
|
+
const scaffolder = new PocScaffolder();
|
|
101
|
+
const ctx = PocScaffolder.buildContext(session, tmpDir);
|
|
102
|
+
const result = await scaffolder.scaffold(ctx);
|
|
103
|
+
// Check all required files were created
|
|
104
|
+
const requiredFiles = [
|
|
105
|
+
'.gitignore',
|
|
106
|
+
'package.json',
|
|
107
|
+
'tsconfig.json',
|
|
108
|
+
'README.md',
|
|
109
|
+
'src/index.ts',
|
|
110
|
+
'tests/index.test.ts',
|
|
111
|
+
'.sofia-metadata.json',
|
|
112
|
+
];
|
|
113
|
+
for (const file of requiredFiles) {
|
|
114
|
+
const fullPath = join(tmpDir, file);
|
|
115
|
+
const exists = await stat(fullPath).then(() => true).catch(() => false);
|
|
116
|
+
expect(exists, `Expected ${file} to exist`).toBe(true);
|
|
117
|
+
}
|
|
118
|
+
expect(result.createdFiles).toContain('package.json');
|
|
119
|
+
expect(result.createdFiles).toContain('README.md');
|
|
120
|
+
expect(result.createdFiles).toContain('.gitignore');
|
|
121
|
+
expect(result.createdFiles).toContain('.sofia-metadata.json');
|
|
122
|
+
});
|
|
123
|
+
it('package.json has required structure', async () => {
|
|
124
|
+
const session = makeSession();
|
|
125
|
+
const scaffolder = new PocScaffolder();
|
|
126
|
+
const ctx = PocScaffolder.buildContext(session, tmpDir);
|
|
127
|
+
await scaffolder.scaffold(ctx);
|
|
128
|
+
const content = await readFile(join(tmpDir, 'package.json'), 'utf-8');
|
|
129
|
+
const pkg = JSON.parse(content);
|
|
130
|
+
expect(pkg.type).toBe('module');
|
|
131
|
+
expect(pkg.scripts.test).toBe('vitest run');
|
|
132
|
+
expect(pkg.scripts.build).toBeDefined();
|
|
133
|
+
expect(pkg.version).toBe('0.1.0');
|
|
134
|
+
expect(pkg.name).toBe('ai-route-optimizer');
|
|
135
|
+
});
|
|
136
|
+
it('tsconfig.json has strict TypeScript config', async () => {
|
|
137
|
+
const session = makeSession();
|
|
138
|
+
const scaffolder = new PocScaffolder();
|
|
139
|
+
const ctx = PocScaffolder.buildContext(session, tmpDir);
|
|
140
|
+
await scaffolder.scaffold(ctx);
|
|
141
|
+
const content = await readFile(join(tmpDir, 'tsconfig.json'), 'utf-8');
|
|
142
|
+
const tsconfig = JSON.parse(content);
|
|
143
|
+
expect(tsconfig.compilerOptions.strict).toBe(true);
|
|
144
|
+
expect(tsconfig.compilerOptions.target).toBe('ES2022');
|
|
145
|
+
});
|
|
146
|
+
it('.gitignore excludes node_modules, dist, coverage', async () => {
|
|
147
|
+
const session = makeSession();
|
|
148
|
+
const scaffolder = new PocScaffolder();
|
|
149
|
+
const ctx = PocScaffolder.buildContext(session, tmpDir);
|
|
150
|
+
await scaffolder.scaffold(ctx);
|
|
151
|
+
const content = await readFile(join(tmpDir, '.gitignore'), 'utf-8');
|
|
152
|
+
expect(content).toContain('node_modules/');
|
|
153
|
+
expect(content).toContain('dist/');
|
|
154
|
+
expect(content).toContain('coverage/');
|
|
155
|
+
});
|
|
156
|
+
it('.sofia-metadata.json links to session', async () => {
|
|
157
|
+
const session = makeSession();
|
|
158
|
+
const scaffolder = new PocScaffolder();
|
|
159
|
+
const ctx = PocScaffolder.buildContext(session, tmpDir);
|
|
160
|
+
await scaffolder.scaffold(ctx);
|
|
161
|
+
const content = await readFile(join(tmpDir, '.sofia-metadata.json'), 'utf-8');
|
|
162
|
+
const meta = JSON.parse(content);
|
|
163
|
+
expect(meta.sessionId).toBe('scaffold-test-001');
|
|
164
|
+
expect(meta.featureSpec).toBe('002-poc-generation');
|
|
165
|
+
expect(meta.ideaTitle).toBe('AI Route Optimizer');
|
|
166
|
+
expect(meta.generatedAt).toBeDefined();
|
|
167
|
+
});
|
|
168
|
+
it('README.md contains idea title and session ID', async () => {
|
|
169
|
+
const session = makeSession();
|
|
170
|
+
const scaffolder = new PocScaffolder();
|
|
171
|
+
const ctx = PocScaffolder.buildContext(session, tmpDir);
|
|
172
|
+
await scaffolder.scaffold(ctx);
|
|
173
|
+
const content = await readFile(join(tmpDir, 'README.md'), 'utf-8');
|
|
174
|
+
expect(content).toContain('AI Route Optimizer');
|
|
175
|
+
expect(content).toContain('scaffold-test-001');
|
|
176
|
+
});
|
|
177
|
+
it('creates src/ and tests/ directories', async () => {
|
|
178
|
+
const session = makeSession();
|
|
179
|
+
const scaffolder = new PocScaffolder();
|
|
180
|
+
const ctx = PocScaffolder.buildContext(session, tmpDir);
|
|
181
|
+
await scaffolder.scaffold(ctx);
|
|
182
|
+
const srcEntries = await readdir(join(tmpDir, 'src'));
|
|
183
|
+
const testEntries = await readdir(join(tmpDir, 'tests'));
|
|
184
|
+
expect(srcEntries.some((f) => f.endsWith('.ts'))).toBe(true);
|
|
185
|
+
expect(testEntries.some((f) => f.endsWith('.test.ts'))).toBe(true);
|
|
186
|
+
});
|
|
187
|
+
it('returns list of created files', async () => {
|
|
188
|
+
const session = makeSession();
|
|
189
|
+
const scaffolder = new PocScaffolder();
|
|
190
|
+
const ctx = PocScaffolder.buildContext(session, tmpDir);
|
|
191
|
+
const result = await scaffolder.scaffold(ctx);
|
|
192
|
+
expect(result.createdFiles.length).toBeGreaterThan(0);
|
|
193
|
+
expect(result.skippedFiles).toEqual([]);
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
describe('skip-if-exists behavior', () => {
|
|
197
|
+
it('skips package.json if it already exists (skipIfExists: true)', async () => {
|
|
198
|
+
const session = makeSession();
|
|
199
|
+
const scaffolder = new PocScaffolder();
|
|
200
|
+
const ctx = PocScaffolder.buildContext(session, tmpDir);
|
|
201
|
+
// Create a custom package.json first
|
|
202
|
+
const { writeFile, mkdir } = await import('node:fs/promises');
|
|
203
|
+
await mkdir(tmpDir, { recursive: true });
|
|
204
|
+
await writeFile(join(tmpDir, 'package.json'), JSON.stringify({ name: 'custom', scripts: { test: 'echo custom' } }), 'utf-8');
|
|
205
|
+
// Scaffold should skip existing package.json
|
|
206
|
+
const result = await scaffolder.scaffold(ctx);
|
|
207
|
+
expect(result.skippedFiles).toContain('package.json');
|
|
208
|
+
// Custom content should be preserved
|
|
209
|
+
const content = await readFile(join(tmpDir, 'package.json'), 'utf-8');
|
|
210
|
+
const pkg = JSON.parse(content);
|
|
211
|
+
expect(pkg.name).toBe('custom');
|
|
212
|
+
});
|
|
213
|
+
it('always overwrites .gitignore (skipIfExists: false)', async () => {
|
|
214
|
+
const session = makeSession();
|
|
215
|
+
const scaffolder = new PocScaffolder();
|
|
216
|
+
const ctx = PocScaffolder.buildContext(session, tmpDir);
|
|
217
|
+
// Create a custom .gitignore first
|
|
218
|
+
const { writeFile } = await import('node:fs/promises');
|
|
219
|
+
await writeFile(join(tmpDir, '.gitignore'), '# custom\n', 'utf-8');
|
|
220
|
+
// Scaffold should overwrite .gitignore
|
|
221
|
+
await scaffolder.scaffold(ctx);
|
|
222
|
+
const content = await readFile(join(tmpDir, '.gitignore'), 'utf-8');
|
|
223
|
+
expect(content).toContain('node_modules/'); // Generated content
|
|
224
|
+
});
|
|
225
|
+
});
|
|
226
|
+
describe('getTemplateFiles', () => {
|
|
227
|
+
it('returns list of template file paths', () => {
|
|
228
|
+
const scaffolder = new PocScaffolder();
|
|
229
|
+
const files = scaffolder.getTemplateFiles();
|
|
230
|
+
expect(files).toContain('package.json');
|
|
231
|
+
expect(files).toContain('README.md');
|
|
232
|
+
expect(files).toContain('.gitignore');
|
|
233
|
+
expect(files).toContain('src/index.ts');
|
|
234
|
+
expect(files).toContain('tests/index.test.ts');
|
|
235
|
+
});
|
|
236
|
+
});
|
|
237
|
+
});
|
|
238
|
+
describe('validatePocOutput', () => {
|
|
239
|
+
let tmpDir;
|
|
240
|
+
beforeEach(async () => {
|
|
241
|
+
tmpDir = await mkdtemp(join(tmpdir(), 'sofia-validate-test-'));
|
|
242
|
+
});
|
|
243
|
+
afterEach(async () => {
|
|
244
|
+
await rm(tmpDir, { recursive: true, force: true });
|
|
245
|
+
});
|
|
246
|
+
it('returns valid=true for a complete scaffold', async () => {
|
|
247
|
+
const session = makeSession();
|
|
248
|
+
const scaffolder = new PocScaffolder();
|
|
249
|
+
const ctx = PocScaffolder.buildContext(session, tmpDir);
|
|
250
|
+
await scaffolder.scaffold(ctx);
|
|
251
|
+
const result = await validatePocOutput(tmpDir);
|
|
252
|
+
expect(result.valid).toBe(true);
|
|
253
|
+
expect(result.missingFiles).toEqual([]);
|
|
254
|
+
expect(result.errors).toEqual([]);
|
|
255
|
+
});
|
|
256
|
+
it('reports missing required files', async () => {
|
|
257
|
+
const result = await validatePocOutput(tmpDir);
|
|
258
|
+
expect(result.valid).toBe(false);
|
|
259
|
+
expect(result.missingFiles).toContain('package.json');
|
|
260
|
+
expect(result.missingFiles).toContain('README.md');
|
|
261
|
+
});
|
|
262
|
+
it('reports error when package.json lacks test script', async () => {
|
|
263
|
+
const { writeFile, mkdir } = await import('node:fs/promises');
|
|
264
|
+
await mkdir(join(tmpDir, 'src'), { recursive: true });
|
|
265
|
+
await mkdir(join(tmpDir, 'tests'), { recursive: true });
|
|
266
|
+
await writeFile(join(tmpDir, 'package.json'), JSON.stringify({ name: 'test', scripts: {} }), 'utf-8');
|
|
267
|
+
await writeFile(join(tmpDir, 'README.md'), '# Test', 'utf-8');
|
|
268
|
+
await writeFile(join(tmpDir, 'tsconfig.json'), JSON.stringify({}), 'utf-8');
|
|
269
|
+
await writeFile(join(tmpDir, '.gitignore'), 'node_modules/', 'utf-8');
|
|
270
|
+
await writeFile(join(tmpDir, '.sofia-metadata.json'), JSON.stringify({ sessionId: 'x' }), 'utf-8');
|
|
271
|
+
await writeFile(join(tmpDir, 'src/index.ts'), 'export function main() {}', 'utf-8');
|
|
272
|
+
await writeFile(join(tmpDir, 'tests/index.test.ts'), 'import { test } from "vitest"', 'utf-8');
|
|
273
|
+
const result = await validatePocOutput(tmpDir);
|
|
274
|
+
expect(result.errors).toContain('package.json is missing "test" script');
|
|
275
|
+
});
|
|
276
|
+
});
|
|
277
|
+
// ── Template entry construction (T036) ────────────────────────────────────
|
|
278
|
+
describe('PocScaffolder with TemplateEntry', () => {
|
|
279
|
+
let tmpDir;
|
|
280
|
+
beforeEach(async () => {
|
|
281
|
+
tmpDir = await mkdtemp(join(tmpdir(), 'scaffolder-template-'));
|
|
282
|
+
});
|
|
283
|
+
afterEach(async () => {
|
|
284
|
+
await rm(tmpDir, { recursive: true, force: true });
|
|
285
|
+
});
|
|
286
|
+
it('uses TemplateEntry.files when constructed with a template entry (T036)', async () => {
|
|
287
|
+
const { PYTHON_PYTEST_TEMPLATE } = await import('../../../src/develop/templateRegistry.js');
|
|
288
|
+
const scaffolder = new PocScaffolder(PYTHON_PYTEST_TEMPLATE);
|
|
289
|
+
// The template should contain Python-specific file paths
|
|
290
|
+
const filePaths = scaffolder.getTemplateFiles();
|
|
291
|
+
expect(filePaths).toContain('requirements.txt');
|
|
292
|
+
expect(filePaths).toContain('src/main.py');
|
|
293
|
+
expect(filePaths).toContain('tests/test_main.py');
|
|
294
|
+
// Should NOT contain TypeScript files
|
|
295
|
+
expect(filePaths).not.toContain('tsconfig.json');
|
|
296
|
+
expect(filePaths).not.toContain('src/index.ts');
|
|
297
|
+
});
|
|
298
|
+
it('uses TemplateEntry.techStack in buildContext (T010)', async () => {
|
|
299
|
+
const { PYTHON_PYTEST_TEMPLATE } = await import('../../../src/develop/templateRegistry.js');
|
|
300
|
+
const session = makeSession();
|
|
301
|
+
const ctx = PocScaffolder.buildContext(session, tmpDir, PYTHON_PYTEST_TEMPLATE);
|
|
302
|
+
expect(ctx.techStack.language).toBe('Python');
|
|
303
|
+
expect(ctx.techStack.runtime).toBe('Python 3.11');
|
|
304
|
+
});
|
|
305
|
+
it('falls back to default TypeScript techStack when no template entry provided', () => {
|
|
306
|
+
const session = makeSession();
|
|
307
|
+
const ctx = PocScaffolder.buildContext(session, tmpDir);
|
|
308
|
+
expect(ctx.techStack.language).toBe('TypeScript');
|
|
309
|
+
expect(ctx.techStack.runtime).toBe('Node.js 20');
|
|
310
|
+
});
|
|
311
|
+
});
|
|
312
|
+
// ── T072: TODO marker scanning records totalInitial, remaining, markers ───
|
|
313
|
+
describe('PocScaffolder.scanAndRecordTodos (T072)', () => {
|
|
314
|
+
let tmpDir;
|
|
315
|
+
beforeEach(async () => {
|
|
316
|
+
tmpDir = await mkdtemp(join(tmpdir(), 'todo-scan-'));
|
|
317
|
+
});
|
|
318
|
+
afterEach(async () => {
|
|
319
|
+
await rm(tmpDir, { recursive: true, force: true });
|
|
320
|
+
});
|
|
321
|
+
it('scans scaffold files for TODO markers and records counts in .sofia-metadata.json', async () => {
|
|
322
|
+
const { writeFile, mkdir } = await import('node:fs/promises');
|
|
323
|
+
// Create a minimal project with TODO markers
|
|
324
|
+
await mkdir(join(tmpDir, 'src'), { recursive: true });
|
|
325
|
+
await writeFile(join(tmpDir, 'src/index.ts'), '// TODO: Implement the core functionality\nexport function main() {}\n// TODO: Add error handling\n');
|
|
326
|
+
await writeFile(join(tmpDir, 'src/utils.ts'), 'export function helper() { return 42; }\n');
|
|
327
|
+
await writeFile(join(tmpDir, '.sofia-metadata.json'), JSON.stringify({ sessionId: 'test-001', scaffoldedAt: new Date().toISOString() }));
|
|
328
|
+
const result = await PocScaffolder.scanAndRecordTodos(tmpDir);
|
|
329
|
+
// Verify return value
|
|
330
|
+
expect(result.totalInitial).toBe(2);
|
|
331
|
+
expect(result.remaining).toBe(2);
|
|
332
|
+
expect(result.markers).toHaveLength(2);
|
|
333
|
+
expect(result.markers[0]).toContain('src/index.ts:1');
|
|
334
|
+
expect(result.markers[0]).toContain('TODO:');
|
|
335
|
+
expect(result.markers[1]).toContain('src/index.ts:3');
|
|
336
|
+
// Verify .sofia-metadata.json was updated
|
|
337
|
+
const metaRaw = await readFile(join(tmpDir, '.sofia-metadata.json'), 'utf-8');
|
|
338
|
+
const metadata = JSON.parse(metaRaw);
|
|
339
|
+
expect(metadata.todos).toBeDefined();
|
|
340
|
+
expect(metadata.todos.totalInitial).toBe(2);
|
|
341
|
+
expect(metadata.todos.remaining).toBe(2);
|
|
342
|
+
expect(metadata.todos.markers).toHaveLength(2);
|
|
343
|
+
});
|
|
344
|
+
it('records zero TODOs when no markers exist', async () => {
|
|
345
|
+
const { writeFile } = await import('node:fs/promises');
|
|
346
|
+
await writeFile(join(tmpDir, 'index.ts'), 'export function main() { return "clean"; }\n');
|
|
347
|
+
await writeFile(join(tmpDir, '.sofia-metadata.json'), JSON.stringify({ sessionId: 'test-002' }));
|
|
348
|
+
const result = await PocScaffolder.scanAndRecordTodos(tmpDir);
|
|
349
|
+
expect(result.totalInitial).toBe(0);
|
|
350
|
+
expect(result.remaining).toBe(0);
|
|
351
|
+
expect(result.markers).toHaveLength(0);
|
|
352
|
+
});
|
|
353
|
+
});
|