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,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* T064: Unit tests for statusCommand — session name display.
|
|
3
|
+
*
|
|
4
|
+
* Verifies that statusCommand displays the session name in both
|
|
5
|
+
* TTY table and JSON output formats.
|
|
6
|
+
*/
|
|
7
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
8
|
+
|
|
9
|
+
import type { WorkshopSession } from '../../../src/shared/schemas/session.js';
|
|
10
|
+
|
|
11
|
+
function makeSession(overrides?: Partial<WorkshopSession>): WorkshopSession {
|
|
12
|
+
return {
|
|
13
|
+
sessionId: 'test-session-001',
|
|
14
|
+
schemaVersion: '1.0.0',
|
|
15
|
+
createdAt: '2026-01-01T00:00:00Z',
|
|
16
|
+
updatedAt: '2026-01-01T01:00:00Z',
|
|
17
|
+
phase: 'Discover',
|
|
18
|
+
status: 'Active',
|
|
19
|
+
participants: [],
|
|
20
|
+
artifacts: { generatedFiles: [] },
|
|
21
|
+
turns: [],
|
|
22
|
+
...overrides,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Mock sessionStore
|
|
27
|
+
const mockStore = {
|
|
28
|
+
load: vi.fn(),
|
|
29
|
+
save: vi.fn(),
|
|
30
|
+
exists: vi.fn(),
|
|
31
|
+
list: vi.fn(),
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
vi.mock('../../../src/sessions/sessionStore.js', () => ({
|
|
35
|
+
createDefaultStore: () => mockStore,
|
|
36
|
+
SessionStore: vi.fn(),
|
|
37
|
+
}));
|
|
38
|
+
|
|
39
|
+
describe('statusCommand', () => {
|
|
40
|
+
let stdoutChunks: string[];
|
|
41
|
+
let stderrChunks: string[];
|
|
42
|
+
const originalWrite = process.stdout.write;
|
|
43
|
+
const originalConsoleLog = console.log;
|
|
44
|
+
const originalConsoleError = console.error;
|
|
45
|
+
|
|
46
|
+
beforeEach(() => {
|
|
47
|
+
stdoutChunks = [];
|
|
48
|
+
stderrChunks = [];
|
|
49
|
+
process.stdout.write = vi.fn((chunk: string | Uint8Array) => {
|
|
50
|
+
stdoutChunks.push(chunk.toString());
|
|
51
|
+
return true;
|
|
52
|
+
}) as typeof process.stdout.write;
|
|
53
|
+
console.log = vi.fn((...args: unknown[]) => {
|
|
54
|
+
stdoutChunks.push(args.map(String).join(' '));
|
|
55
|
+
});
|
|
56
|
+
console.error = vi.fn((...args: unknown[]) => {
|
|
57
|
+
stderrChunks.push(args.map(String).join(' '));
|
|
58
|
+
});
|
|
59
|
+
process.exitCode = undefined;
|
|
60
|
+
vi.resetAllMocks();
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
afterEach(() => {
|
|
64
|
+
process.stdout.write = originalWrite;
|
|
65
|
+
console.log = originalConsoleLog;
|
|
66
|
+
console.error = originalConsoleError;
|
|
67
|
+
process.exitCode = undefined;
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
describe('session name display (T064)', () => {
|
|
71
|
+
it('displays session name in JSON output for single session', async () => {
|
|
72
|
+
const session = makeSession({ name: 'Logistics AI Workshop' } as Partial<WorkshopSession>);
|
|
73
|
+
mockStore.exists.mockResolvedValue(true);
|
|
74
|
+
mockStore.load.mockResolvedValue(session);
|
|
75
|
+
|
|
76
|
+
const { statusCommand } = await import('../../../src/cli/statusCommand.js');
|
|
77
|
+
await statusCommand({ session: 'test-session-001', json: true });
|
|
78
|
+
|
|
79
|
+
const output = stdoutChunks.join('');
|
|
80
|
+
const parsed = JSON.parse(output);
|
|
81
|
+
expect(parsed.name).toBe('Logistics AI Workshop');
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('omits name from JSON output when session has no name', async () => {
|
|
85
|
+
const session = makeSession();
|
|
86
|
+
mockStore.exists.mockResolvedValue(true);
|
|
87
|
+
mockStore.load.mockResolvedValue(session);
|
|
88
|
+
|
|
89
|
+
const { statusCommand } = await import('../../../src/cli/statusCommand.js');
|
|
90
|
+
await statusCommand({ session: 'test-session-001', json: true });
|
|
91
|
+
|
|
92
|
+
const output = stdoutChunks.join('');
|
|
93
|
+
const parsed = JSON.parse(output);
|
|
94
|
+
expect(parsed.name).toBeUndefined();
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it('displays session name in TTY output for single session', async () => {
|
|
98
|
+
const session = makeSession({ name: 'Retail AI Insights' } as Partial<WorkshopSession>);
|
|
99
|
+
mockStore.exists.mockResolvedValue(true);
|
|
100
|
+
mockStore.load.mockResolvedValue(session);
|
|
101
|
+
|
|
102
|
+
const { statusCommand } = await import('../../../src/cli/statusCommand.js');
|
|
103
|
+
await statusCommand({ session: 'test-session-001', json: false });
|
|
104
|
+
|
|
105
|
+
const output = stdoutChunks.join(' ');
|
|
106
|
+
expect(output).toContain('Retail AI Insights');
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it('displays session name in session list JSON output', async () => {
|
|
110
|
+
const session = makeSession({ name: 'Supply Chain AI' } as Partial<WorkshopSession>);
|
|
111
|
+
mockStore.list.mockResolvedValue(['test-session-001']);
|
|
112
|
+
mockStore.load.mockResolvedValue(session);
|
|
113
|
+
|
|
114
|
+
const { statusCommand } = await import('../../../src/cli/statusCommand.js');
|
|
115
|
+
await statusCommand({ json: true });
|
|
116
|
+
|
|
117
|
+
const output = stdoutChunks.join('');
|
|
118
|
+
const parsed = JSON.parse(output);
|
|
119
|
+
expect(parsed.sessions[0].name).toBe('Supply Chain AI');
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it('displays session name in session list TTY table', async () => {
|
|
123
|
+
const session = makeSession({ name: 'HR Automation' } as Partial<WorkshopSession>);
|
|
124
|
+
mockStore.list.mockResolvedValue(['test-session-001']);
|
|
125
|
+
mockStore.load.mockResolvedValue(session);
|
|
126
|
+
|
|
127
|
+
const { statusCommand } = await import('../../../src/cli/statusCommand.js');
|
|
128
|
+
await statusCommand({ json: false });
|
|
129
|
+
|
|
130
|
+
const output = stdoutChunks.join(' ');
|
|
131
|
+
expect(output).toContain('HR Automation');
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
});
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for workshopCommand client creation — silent mock fallback bug.
|
|
3
|
+
*
|
|
4
|
+
* Verifies:
|
|
5
|
+
* - When createCopilotClient() throws, the error is logged (not swallowed)
|
|
6
|
+
* - The fake client is never silently substituted in production mode
|
|
7
|
+
* - The user receives a clear error message when the SDK is unavailable
|
|
8
|
+
*/
|
|
9
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
10
|
+
|
|
11
|
+
// Mock copilotClient module so createCopilotClient always rejects
|
|
12
|
+
vi.mock('../../../src/shared/copilotClient.js', async (importOriginal) => {
|
|
13
|
+
const orig = await importOriginal<typeof import('../../../src/shared/copilotClient.js')>();
|
|
14
|
+
return {
|
|
15
|
+
...orig,
|
|
16
|
+
createCopilotClient: vi.fn().mockRejectedValue(
|
|
17
|
+
new Error('SDK not available'),
|
|
18
|
+
),
|
|
19
|
+
};
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
// Mock the logger so we can assert error logging
|
|
23
|
+
vi.mock('../../../src/logging/logger.js', () => {
|
|
24
|
+
const fakeLogger = {
|
|
25
|
+
error: vi.fn(),
|
|
26
|
+
warn: vi.fn(),
|
|
27
|
+
info: vi.fn(),
|
|
28
|
+
debug: vi.fn(),
|
|
29
|
+
fatal: vi.fn(),
|
|
30
|
+
child: vi.fn().mockReturnThis(),
|
|
31
|
+
};
|
|
32
|
+
return {
|
|
33
|
+
getLogger: vi.fn(() => fakeLogger),
|
|
34
|
+
createLogger: vi.fn(() => fakeLogger),
|
|
35
|
+
initGlobalLogger: vi.fn(() => fakeLogger),
|
|
36
|
+
};
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
import { workshopCommand } from '../../../src/cli/workshopCommand.js';
|
|
40
|
+
import { getLogger } from '../../../src/logging/logger.js';
|
|
41
|
+
|
|
42
|
+
describe('workshopCommand — client creation failure', () => {
|
|
43
|
+
let exitCodeBefore: number | undefined;
|
|
44
|
+
|
|
45
|
+
beforeEach(() => {
|
|
46
|
+
exitCodeBefore = process.exitCode as number | undefined;
|
|
47
|
+
process.exitCode = undefined;
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
afterEach(() => {
|
|
51
|
+
process.exitCode = exitCodeBefore;
|
|
52
|
+
vi.restoreAllMocks();
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('logs the error when createCopilotClient fails', async () => {
|
|
56
|
+
// Run with --new-session --non-interactive so no menus block
|
|
57
|
+
await workshopCommand({
|
|
58
|
+
newSession: true,
|
|
59
|
+
nonInteractive: true,
|
|
60
|
+
json: true,
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
const logger = getLogger();
|
|
64
|
+
expect(logger.error).toHaveBeenCalledWith(
|
|
65
|
+
expect.objectContaining({ err: expect.any(Error) }),
|
|
66
|
+
expect.stringContaining('Copilot'),
|
|
67
|
+
);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('sets non-zero exit code when SDK is unavailable', async () => {
|
|
71
|
+
await workshopCommand({
|
|
72
|
+
newSession: true,
|
|
73
|
+
nonInteractive: true,
|
|
74
|
+
json: true,
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
expect(process.exitCode).not.toBe(0);
|
|
78
|
+
expect(process.exitCode).toBeDefined();
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('does not silently fall back to fake client', async () => {
|
|
82
|
+
// Capture stdout to check there is no fake "Welcome" response
|
|
83
|
+
const writeSpy = vi.spyOn(process.stdout, 'write').mockImplementation(() => true);
|
|
84
|
+
|
|
85
|
+
await workshopCommand({
|
|
86
|
+
newSession: true,
|
|
87
|
+
nonInteractive: true,
|
|
88
|
+
json: true,
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
const allOutput = writeSpy.mock.calls.map(c => String(c[0])).join('');
|
|
92
|
+
|
|
93
|
+
// Should NOT contain the canned fake response
|
|
94
|
+
expect(allOutput).not.toContain('Welcome to the AI Discovery Workshop');
|
|
95
|
+
// Should contain an error indication
|
|
96
|
+
expect(allOutput).toContain('error');
|
|
97
|
+
|
|
98
|
+
writeSpy.mockRestore();
|
|
99
|
+
});
|
|
100
|
+
});
|
|
@@ -0,0 +1,378 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for workshopCommand — session name display, Plan→Develop
|
|
3
|
+
* transition guidance (T052), and auto-transition prompt (T053).
|
|
4
|
+
*/
|
|
5
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
6
|
+
|
|
7
|
+
import type { WorkshopSession } from '../../../src/shared/schemas/session.js';
|
|
8
|
+
|
|
9
|
+
// ── Mocks ───────────────────────────────────────────────────────────────────
|
|
10
|
+
|
|
11
|
+
const mockStore = {
|
|
12
|
+
load: vi.fn(),
|
|
13
|
+
save: vi.fn().mockResolvedValue(undefined),
|
|
14
|
+
exists: vi.fn(),
|
|
15
|
+
list: vi.fn(),
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
vi.mock('../../../src/sessions/sessionStore.js', () => ({
|
|
19
|
+
createDefaultStore: () => mockStore,
|
|
20
|
+
SessionStore: vi.fn(),
|
|
21
|
+
}));
|
|
22
|
+
|
|
23
|
+
// Minimal fake CopilotClient
|
|
24
|
+
const fakeClient = {
|
|
25
|
+
async createSession() {
|
|
26
|
+
return {
|
|
27
|
+
send: async function* () {
|
|
28
|
+
yield { type: 'TextDelta' as const, text: 'Hello!', timestamp: new Date().toISOString() };
|
|
29
|
+
},
|
|
30
|
+
getHistory: () => [],
|
|
31
|
+
};
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
vi.mock('../../../src/shared/copilotClient.js', async (importOriginal) => {
|
|
36
|
+
const orig = await importOriginal<typeof import('../../../src/shared/copilotClient.js')>();
|
|
37
|
+
return {
|
|
38
|
+
...orig,
|
|
39
|
+
createCopilotClient: vi.fn().mockResolvedValue(fakeClient),
|
|
40
|
+
};
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
vi.mock('../../../src/logging/logger.js', () => {
|
|
44
|
+
const fakeLogger = {
|
|
45
|
+
error: vi.fn(),
|
|
46
|
+
warn: vi.fn(),
|
|
47
|
+
info: vi.fn(),
|
|
48
|
+
debug: vi.fn(),
|
|
49
|
+
fatal: vi.fn(),
|
|
50
|
+
child: vi.fn().mockReturnThis(),
|
|
51
|
+
};
|
|
52
|
+
return {
|
|
53
|
+
getLogger: vi.fn(() => fakeLogger),
|
|
54
|
+
createLogger: vi.fn(() => fakeLogger),
|
|
55
|
+
initGlobalLogger: vi.fn(() => fakeLogger),
|
|
56
|
+
};
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// Track LoopIO writes — decision gate is configurable per test
|
|
60
|
+
let ioWrites: string[] = [];
|
|
61
|
+
let ioReadResponses: (string | null)[] = [];
|
|
62
|
+
let ioReadIndex = 0;
|
|
63
|
+
let ioReadInputPrompts: string[] = [];
|
|
64
|
+
let decisionGateResponses: Array<{ choice: string }> = [];
|
|
65
|
+
let decisionGateIndex = 0;
|
|
66
|
+
|
|
67
|
+
vi.mock('../../../src/cli/ioContext.js', () => ({
|
|
68
|
+
createLoopIO: () => ({
|
|
69
|
+
write: (text: string) => {
|
|
70
|
+
ioWrites.push(text);
|
|
71
|
+
},
|
|
72
|
+
writeActivity: () => {},
|
|
73
|
+
readInput: async (prompt?: string) => {
|
|
74
|
+
if (prompt) ioReadInputPrompts.push(prompt);
|
|
75
|
+
if (ioReadIndex >= ioReadResponses.length) return null;
|
|
76
|
+
return ioReadResponses[ioReadIndex++];
|
|
77
|
+
},
|
|
78
|
+
showDecisionGate: async () => {
|
|
79
|
+
if (decisionGateIndex < decisionGateResponses.length) {
|
|
80
|
+
return decisionGateResponses[decisionGateIndex++];
|
|
81
|
+
}
|
|
82
|
+
return { choice: 'exit' as const };
|
|
83
|
+
},
|
|
84
|
+
isJsonMode: false,
|
|
85
|
+
isTTY: true,
|
|
86
|
+
}),
|
|
87
|
+
}));
|
|
88
|
+
|
|
89
|
+
// Mock phaseHandlers to avoid loading prompts
|
|
90
|
+
vi.mock('../../../src/phases/phaseHandlers.js', async (importOriginal) => {
|
|
91
|
+
const orig = await importOriginal<typeof import('../../../src/phases/phaseHandlers.js')>();
|
|
92
|
+
return {
|
|
93
|
+
...orig,
|
|
94
|
+
createPhaseHandler: () => ({
|
|
95
|
+
phase: 'Discover',
|
|
96
|
+
buildSystemPrompt: () => 'system prompt',
|
|
97
|
+
getReferences: () => [],
|
|
98
|
+
extractResult: () => ({}),
|
|
99
|
+
isComplete: () => false,
|
|
100
|
+
_preload: async () => {},
|
|
101
|
+
}),
|
|
102
|
+
};
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
describe('workshopCommand session name display (T064b)', () => {
|
|
106
|
+
beforeEach(() => {
|
|
107
|
+
ioWrites = [];
|
|
108
|
+
ioReadResponses = [];
|
|
109
|
+
ioReadIndex = 0;
|
|
110
|
+
ioReadInputPrompts = [];
|
|
111
|
+
decisionGateResponses = [];
|
|
112
|
+
decisionGateIndex = 0;
|
|
113
|
+
vi.clearAllMocks();
|
|
114
|
+
process.exitCode = undefined;
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
afterEach(() => {
|
|
118
|
+
process.exitCode = undefined;
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it('displays session name on new session creation message', async () => {
|
|
122
|
+
// Simulate: main menu → choose "new" (option 1) → session starts → exit
|
|
123
|
+
ioReadResponses = ['1']; // Pick new session
|
|
124
|
+
mockStore.list.mockResolvedValue([]);
|
|
125
|
+
|
|
126
|
+
const { workshopCommand } = await import('../../../src/cli/workshopCommand.js');
|
|
127
|
+
await workshopCommand({});
|
|
128
|
+
|
|
129
|
+
const allOutput = ioWrites.join(' ');
|
|
130
|
+
// New session should show session ID (timestamp format)
|
|
131
|
+
expect(allOutput).toContain('New session');
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
it('displays session name when resuming a named session', async () => {
|
|
135
|
+
const session: WorkshopSession = {
|
|
136
|
+
sessionId: '2026-01-01_120000',
|
|
137
|
+
schemaVersion: '1.0.0',
|
|
138
|
+
createdAt: '2026-01-01T12:00:00Z',
|
|
139
|
+
updatedAt: '2026-01-01T12:30:00Z',
|
|
140
|
+
phase: 'Discover',
|
|
141
|
+
status: 'Active',
|
|
142
|
+
participants: [],
|
|
143
|
+
artifacts: { generatedFiles: [] },
|
|
144
|
+
turns: [],
|
|
145
|
+
name: 'Logistics AI Workshop',
|
|
146
|
+
} as WorkshopSession;
|
|
147
|
+
|
|
148
|
+
mockStore.exists.mockResolvedValue(true);
|
|
149
|
+
mockStore.load.mockResolvedValue(session);
|
|
150
|
+
|
|
151
|
+
const { workshopCommand } = await import('../../../src/cli/workshopCommand.js');
|
|
152
|
+
await workshopCommand({ session: '2026-01-01_120000' });
|
|
153
|
+
|
|
154
|
+
// The session name should appear in the output somewhere
|
|
155
|
+
const allOutput = ioWrites.join(' ');
|
|
156
|
+
expect(allOutput).toContain('Logistics AI Workshop');
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it('displays session name in pause message when session has a name', async () => {
|
|
160
|
+
const session: WorkshopSession = {
|
|
161
|
+
sessionId: '2026-01-01_120000',
|
|
162
|
+
schemaVersion: '1.0.0',
|
|
163
|
+
createdAt: '2026-01-01T12:00:00Z',
|
|
164
|
+
updatedAt: '2026-01-01T12:30:00Z',
|
|
165
|
+
phase: 'Discover',
|
|
166
|
+
status: 'Active',
|
|
167
|
+
participants: [],
|
|
168
|
+
artifacts: { generatedFiles: [] },
|
|
169
|
+
turns: [],
|
|
170
|
+
name: 'Retail Insights',
|
|
171
|
+
} as WorkshopSession;
|
|
172
|
+
|
|
173
|
+
mockStore.exists.mockResolvedValue(true);
|
|
174
|
+
mockStore.load.mockResolvedValue(session);
|
|
175
|
+
|
|
176
|
+
const { workshopCommand } = await import('../../../src/cli/workshopCommand.js');
|
|
177
|
+
// Direct session mode triggers run → decision gate returns exit → pauses
|
|
178
|
+
await workshopCommand({ session: '2026-01-01_120000' });
|
|
179
|
+
|
|
180
|
+
const allOutput = ioWrites.join(' ');
|
|
181
|
+
expect(allOutput).toContain('Retail Insights');
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
it('shows only session ID when no name is set', async () => {
|
|
185
|
+
const session: WorkshopSession = {
|
|
186
|
+
sessionId: '2026-01-01_120000',
|
|
187
|
+
schemaVersion: '1.0.0',
|
|
188
|
+
createdAt: '2026-01-01T12:00:00Z',
|
|
189
|
+
updatedAt: '2026-01-01T12:30:00Z',
|
|
190
|
+
phase: 'Discover',
|
|
191
|
+
status: 'Active',
|
|
192
|
+
participants: [],
|
|
193
|
+
artifacts: { generatedFiles: [] },
|
|
194
|
+
turns: [],
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
mockStore.exists.mockResolvedValue(true);
|
|
198
|
+
mockStore.load.mockResolvedValue(session);
|
|
199
|
+
|
|
200
|
+
const { workshopCommand } = await import('../../../src/cli/workshopCommand.js');
|
|
201
|
+
await workshopCommand({ session: '2026-01-01_120000' });
|
|
202
|
+
|
|
203
|
+
const allOutput = ioWrites.join(' ');
|
|
204
|
+
expect(allOutput).toContain('2026-01-01_120000');
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
it('shows only named sessions in the resume list', async () => {
|
|
208
|
+
const namedSession: WorkshopSession = {
|
|
209
|
+
sessionId: '2026-02-28_165120',
|
|
210
|
+
schemaVersion: '1.0.0',
|
|
211
|
+
createdAt: '2026-02-28T16:51:20Z',
|
|
212
|
+
updatedAt: '2026-02-28T16:55:00Z',
|
|
213
|
+
phase: 'Discover',
|
|
214
|
+
status: 'Active',
|
|
215
|
+
participants: [],
|
|
216
|
+
artifacts: { generatedFiles: [] },
|
|
217
|
+
turns: [],
|
|
218
|
+
name: 'Inventory Insights',
|
|
219
|
+
} as WorkshopSession;
|
|
220
|
+
|
|
221
|
+
const unnamedSession: WorkshopSession = {
|
|
222
|
+
sessionId: '2026-02-28_170457',
|
|
223
|
+
schemaVersion: '1.0.0',
|
|
224
|
+
createdAt: '2026-02-28T17:04:57Z',
|
|
225
|
+
updatedAt: '2026-02-28T17:05:00Z',
|
|
226
|
+
phase: 'Discover',
|
|
227
|
+
status: 'Active',
|
|
228
|
+
participants: [],
|
|
229
|
+
artifacts: { generatedFiles: [] },
|
|
230
|
+
turns: [],
|
|
231
|
+
} as WorkshopSession;
|
|
232
|
+
|
|
233
|
+
ioReadResponses = ['2', '1']; // Resume flow, choose first session
|
|
234
|
+
mockStore.list.mockResolvedValue([namedSession.sessionId, unnamedSession.sessionId]);
|
|
235
|
+
mockStore.load.mockImplementation(async (id: string) => {
|
|
236
|
+
if (id === namedSession.sessionId) return namedSession;
|
|
237
|
+
if (id === unnamedSession.sessionId) return unnamedSession;
|
|
238
|
+
throw new Error('Unknown session');
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
const { workshopCommand } = await import('../../../src/cli/workshopCommand.js');
|
|
242
|
+
await workshopCommand({});
|
|
243
|
+
|
|
244
|
+
const allOutput = ioWrites.join(' ');
|
|
245
|
+
expect(allOutput).toContain('Available sessions');
|
|
246
|
+
// Named session appears in the list
|
|
247
|
+
expect(allOutput).toContain('Inventory Insights');
|
|
248
|
+
expect(allOutput).toContain('2026-02-28_165120');
|
|
249
|
+
// Unnamed session is filtered out
|
|
250
|
+
expect(allOutput).not.toContain('2026-02-28_170457');
|
|
251
|
+
});
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
// ── T052: Plan→Develop transition displays "sofia dev --session {id}" ─────
|
|
255
|
+
|
|
256
|
+
describe('workshopCommand Plan→Develop transition (T052)', () => {
|
|
257
|
+
beforeEach(() => {
|
|
258
|
+
ioWrites = [];
|
|
259
|
+
ioReadResponses = [];
|
|
260
|
+
ioReadIndex = 0;
|
|
261
|
+
ioReadInputPrompts = [];
|
|
262
|
+
decisionGateResponses = [];
|
|
263
|
+
decisionGateIndex = 0;
|
|
264
|
+
vi.clearAllMocks();
|
|
265
|
+
process.exitCode = undefined;
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
afterEach(() => {
|
|
269
|
+
process.exitCode = undefined;
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
it('displays "sofia dev --session {id}" after Plan phase completes (FR-020)', async () => {
|
|
273
|
+
const session: WorkshopSession = {
|
|
274
|
+
sessionId: 'plan-test-001',
|
|
275
|
+
schemaVersion: '1.0.0',
|
|
276
|
+
createdAt: '2026-01-01T12:00:00Z',
|
|
277
|
+
updatedAt: '2026-01-01T12:30:00Z',
|
|
278
|
+
phase: 'Plan',
|
|
279
|
+
status: 'Active',
|
|
280
|
+
participants: [],
|
|
281
|
+
artifacts: { generatedFiles: [] },
|
|
282
|
+
turns: [],
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
mockStore.exists.mockResolvedValue(true);
|
|
286
|
+
mockStore.load.mockResolvedValue(session);
|
|
287
|
+
|
|
288
|
+
// First gate (Plan): continue → triggers transition to Develop
|
|
289
|
+
// Second gate (Develop): exit → stops the loop
|
|
290
|
+
decisionGateResponses = [{ choice: 'continue' }, { choice: 'exit' }];
|
|
291
|
+
|
|
292
|
+
const { workshopCommand } = await import('../../../src/cli/workshopCommand.js');
|
|
293
|
+
await workshopCommand({ session: 'plan-test-001' });
|
|
294
|
+
|
|
295
|
+
const allOutput = ioWrites.join(' ');
|
|
296
|
+
// FR-020: Shows transition message for PoC generation
|
|
297
|
+
expect(allOutput).toContain('Starting PoC Generation');
|
|
298
|
+
// Session lacks selection/plan so RalphLoop throws — workshop shows recovery guidance
|
|
299
|
+
expect(allOutput).toContain('sofia dev --session plan-test-001');
|
|
300
|
+
});
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
// ── T053: Workshop auto-runs PoC generation after Plan phase ─────────────
|
|
304
|
+
|
|
305
|
+
describe('workshopCommand auto-run PoC generation (T053)', () => {
|
|
306
|
+
beforeEach(() => {
|
|
307
|
+
ioWrites = [];
|
|
308
|
+
ioReadResponses = [];
|
|
309
|
+
ioReadIndex = 0;
|
|
310
|
+
ioReadInputPrompts = [];
|
|
311
|
+
decisionGateResponses = [];
|
|
312
|
+
decisionGateIndex = 0;
|
|
313
|
+
vi.clearAllMocks();
|
|
314
|
+
process.exitCode = undefined;
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
afterEach(() => {
|
|
318
|
+
process.exitCode = undefined;
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
it('auto-runs PoC generation after Plan phase, shows warning on failure (FR-021)', async () => {
|
|
322
|
+
const session: WorkshopSession = {
|
|
323
|
+
sessionId: 'transition-test-001',
|
|
324
|
+
schemaVersion: '1.0.0',
|
|
325
|
+
createdAt: '2026-01-01T12:00:00Z',
|
|
326
|
+
updatedAt: '2026-01-01T12:30:00Z',
|
|
327
|
+
phase: 'Plan',
|
|
328
|
+
status: 'Active',
|
|
329
|
+
participants: [],
|
|
330
|
+
artifacts: { generatedFiles: [] },
|
|
331
|
+
turns: [],
|
|
332
|
+
};
|
|
333
|
+
|
|
334
|
+
mockStore.exists.mockResolvedValue(true);
|
|
335
|
+
mockStore.load.mockResolvedValue(session);
|
|
336
|
+
|
|
337
|
+
// Continue from Plan → Develop, then exit
|
|
338
|
+
decisionGateResponses = [{ choice: 'continue' }, { choice: 'exit' }];
|
|
339
|
+
|
|
340
|
+
const { workshopCommand } = await import('../../../src/cli/workshopCommand.js');
|
|
341
|
+
await workshopCommand({ session: 'transition-test-001' });
|
|
342
|
+
|
|
343
|
+
const allOutput = ioWrites.join(' ');
|
|
344
|
+
// FR-021: PoC generation runs automatically after Plan phase
|
|
345
|
+
expect(allOutput).toContain('Starting PoC Generation');
|
|
346
|
+
// Session lacks selection/plan so RalphLoop throws — workshop shows recovery guidance
|
|
347
|
+
expect(allOutput).toContain('PoC generation failed');
|
|
348
|
+
expect(allOutput).toContain('sofia dev --session transition-test-001');
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
it('continues workshop after PoC generation failure (FR-021)', async () => {
|
|
352
|
+
const session: WorkshopSession = {
|
|
353
|
+
sessionId: 'auto-transition-001',
|
|
354
|
+
schemaVersion: '1.0.0',
|
|
355
|
+
createdAt: '2026-01-01T12:00:00Z',
|
|
356
|
+
updatedAt: '2026-01-01T12:30:00Z',
|
|
357
|
+
phase: 'Plan',
|
|
358
|
+
status: 'Active',
|
|
359
|
+
participants: [],
|
|
360
|
+
artifacts: { generatedFiles: [] },
|
|
361
|
+
turns: [],
|
|
362
|
+
};
|
|
363
|
+
|
|
364
|
+
mockStore.exists.mockResolvedValue(true);
|
|
365
|
+
mockStore.load.mockResolvedValue(session);
|
|
366
|
+
|
|
367
|
+
// Continue from Plan → PoC fails → continues to Develop phase → exit
|
|
368
|
+
decisionGateResponses = [{ choice: 'continue' }, { choice: 'exit' }];
|
|
369
|
+
|
|
370
|
+
const { workshopCommand } = await import('../../../src/cli/workshopCommand.js');
|
|
371
|
+
await workshopCommand({ session: 'auto-transition-001' });
|
|
372
|
+
|
|
373
|
+
const allOutput = ioWrites.join(' ');
|
|
374
|
+
// Workshop continues after PoC failure — doesn't block
|
|
375
|
+
expect(allOutput).toContain('Starting PoC Generation');
|
|
376
|
+
expect(allOutput).toContain('sofia dev --session auto-transition-001');
|
|
377
|
+
});
|
|
378
|
+
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import liveConfig from '../../../vitest.live.config';
|
|
4
|
+
import defaultConfig from '../../../vitest.config';
|
|
5
|
+
|
|
6
|
+
type VitestLikeConfig = {
|
|
7
|
+
test?: {
|
|
8
|
+
setupFiles?: string[];
|
|
9
|
+
};
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
describe('Vitest env setup', () => {
|
|
13
|
+
it('declares a setup file for default tests', () => {
|
|
14
|
+
const config = defaultConfig as VitestLikeConfig;
|
|
15
|
+
|
|
16
|
+
expect(config.test?.setupFiles).toContain('tests/setup/loadEnv.ts');
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('declares a setup file for live tests', () => {
|
|
20
|
+
const config = liveConfig as VitestLikeConfig;
|
|
21
|
+
|
|
22
|
+
expect(config.test?.setupFiles).toContain('tests/setup/loadEnv.ts');
|
|
23
|
+
});
|
|
24
|
+
});
|