gsd-pi 2.10.12 â 2.12.0
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/dist/bundled-extension-paths.d.ts +2 -0
- package/dist/bundled-extension-paths.js +10 -0
- package/dist/loader.js +45 -28
- package/dist/onboarding.js +100 -0
- package/dist/resource-loader.js +12 -3
- package/dist/resources/GSD-WORKFLOW.md +661 -0
- package/dist/resources/agents/researcher.md +29 -0
- package/dist/resources/agents/scout.md +56 -0
- package/dist/resources/agents/worker.md +31 -0
- package/dist/resources/extensions/ask-user-questions.ts +289 -0
- package/dist/resources/extensions/async-jobs/async-bash-tool.ts +211 -0
- package/dist/resources/extensions/async-jobs/await-tool.ts +101 -0
- package/dist/resources/extensions/async-jobs/cancel-job-tool.ts +34 -0
- package/dist/resources/extensions/async-jobs/index.ts +133 -0
- package/dist/resources/extensions/async-jobs/job-manager.ts +211 -0
- package/dist/resources/extensions/bg-shell/index.ts +3179 -0
- package/dist/resources/extensions/browser-tools/BROWSER-TOOLS-V2-PROPOSAL.md +1277 -0
- package/dist/resources/extensions/browser-tools/capture.ts +165 -0
- package/dist/resources/extensions/browser-tools/core.d.ts +205 -0
- package/dist/resources/extensions/browser-tools/core.js +1057 -0
- package/dist/resources/extensions/browser-tools/evaluate-helpers.ts +184 -0
- package/dist/resources/extensions/browser-tools/index.ts +51 -0
- package/dist/resources/extensions/browser-tools/lifecycle.ts +270 -0
- package/dist/resources/extensions/browser-tools/package.json +24 -0
- package/dist/resources/extensions/browser-tools/refs.ts +264 -0
- package/dist/resources/extensions/browser-tools/settle.ts +197 -0
- package/dist/resources/extensions/browser-tools/state.ts +408 -0
- package/dist/resources/extensions/browser-tools/tests/browser-tools-integration.test.mjs +652 -0
- package/dist/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +614 -0
- package/dist/resources/extensions/browser-tools/tools/assertions.ts +342 -0
- package/dist/resources/extensions/browser-tools/tools/forms.ts +801 -0
- package/dist/resources/extensions/browser-tools/tools/inspection.ts +492 -0
- package/dist/resources/extensions/browser-tools/tools/intent.ts +614 -0
- package/dist/resources/extensions/browser-tools/tools/interaction.ts +865 -0
- package/dist/resources/extensions/browser-tools/tools/navigation.ts +232 -0
- package/dist/resources/extensions/browser-tools/tools/pages.ts +303 -0
- package/dist/resources/extensions/browser-tools/tools/refs.ts +541 -0
- package/dist/resources/extensions/browser-tools/tools/screenshot.ts +83 -0
- package/dist/resources/extensions/browser-tools/tools/session.ts +400 -0
- package/dist/resources/extensions/browser-tools/tools/wait.ts +247 -0
- package/dist/resources/extensions/browser-tools/utils.ts +660 -0
- package/dist/resources/extensions/context7/index.ts +428 -0
- package/dist/resources/extensions/context7/package.json +11 -0
- package/dist/resources/extensions/get-secrets-from-user.ts +625 -0
- package/dist/resources/extensions/google-search/index.ts +336 -0
- package/dist/resources/extensions/google-search/package.json +9 -0
- package/dist/resources/extensions/gsd/activity-log.ts +116 -0
- package/dist/resources/extensions/gsd/auto.ts +3732 -0
- package/dist/resources/extensions/gsd/commands.ts +544 -0
- package/dist/resources/extensions/gsd/crash-recovery.ts +105 -0
- package/dist/resources/extensions/gsd/dashboard-overlay.ts +564 -0
- package/dist/resources/extensions/gsd/dispatch-guard.ts +78 -0
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +278 -0
- package/dist/resources/extensions/gsd/doctor.ts +766 -0
- package/dist/resources/extensions/gsd/exit-command.ts +18 -0
- package/dist/resources/extensions/gsd/files.ts +857 -0
- package/dist/resources/extensions/gsd/git-service.ts +904 -0
- package/dist/resources/extensions/gsd/gitignore.ts +200 -0
- package/dist/resources/extensions/gsd/guided-flow.ts +1054 -0
- package/dist/resources/extensions/gsd/index.ts +735 -0
- package/dist/resources/extensions/gsd/metrics.ts +374 -0
- package/dist/resources/extensions/gsd/migrate/command.ts +218 -0
- package/dist/resources/extensions/gsd/migrate/index.ts +42 -0
- package/dist/resources/extensions/gsd/migrate/parser.ts +323 -0
- package/dist/resources/extensions/gsd/migrate/parsers.ts +624 -0
- package/dist/resources/extensions/gsd/migrate/preview.ts +48 -0
- package/dist/resources/extensions/gsd/migrate/transformer.ts +346 -0
- package/dist/resources/extensions/gsd/migrate/types.ts +370 -0
- package/dist/resources/extensions/gsd/migrate/validator.ts +55 -0
- package/dist/resources/extensions/gsd/migrate/writer.ts +539 -0
- package/dist/resources/extensions/gsd/native-git-bridge.ts +181 -0
- package/dist/resources/extensions/gsd/native-parser-bridge.ts +135 -0
- package/dist/resources/extensions/gsd/observability-validator.ts +408 -0
- package/dist/resources/extensions/gsd/package.json +11 -0
- package/dist/resources/extensions/gsd/paths.ts +339 -0
- package/dist/resources/extensions/gsd/post-unit-hooks.ts +449 -0
- package/dist/resources/extensions/gsd/preferences.ts +988 -0
- package/dist/resources/extensions/gsd/prompt-loader.ts +92 -0
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +25 -0
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +27 -0
- package/dist/resources/extensions/gsd/prompts/discuss.md +237 -0
- package/dist/resources/extensions/gsd/prompts/doctor-heal.md +29 -0
- package/dist/resources/extensions/gsd/prompts/execute-task.md +63 -0
- package/dist/resources/extensions/gsd/prompts/guided-complete-slice.md +3 -0
- package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +5 -0
- package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +61 -0
- package/dist/resources/extensions/gsd/prompts/guided-execute-task.md +3 -0
- package/dist/resources/extensions/gsd/prompts/guided-plan-milestone.md +29 -0
- package/dist/resources/extensions/gsd/prompts/guided-plan-slice.md +3 -0
- package/dist/resources/extensions/gsd/prompts/guided-research-slice.md +13 -0
- package/dist/resources/extensions/gsd/prompts/guided-resume-task.md +1 -0
- package/dist/resources/extensions/gsd/prompts/plan-milestone.md +78 -0
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +55 -0
- package/dist/resources/extensions/gsd/prompts/queue.md +100 -0
- package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +48 -0
- package/dist/resources/extensions/gsd/prompts/replan-slice.md +39 -0
- package/dist/resources/extensions/gsd/prompts/research-milestone.md +37 -0
- package/dist/resources/extensions/gsd/prompts/research-slice.md +28 -0
- package/dist/resources/extensions/gsd/prompts/review-migration.md +66 -0
- package/dist/resources/extensions/gsd/prompts/run-uat.md +109 -0
- package/dist/resources/extensions/gsd/prompts/system.md +190 -0
- package/dist/resources/extensions/gsd/prompts/worktree-merge.md +123 -0
- package/dist/resources/extensions/gsd/roadmap-slices.ts +50 -0
- package/dist/resources/extensions/gsd/session-forensics.ts +500 -0
- package/dist/resources/extensions/gsd/skill-discovery.ts +137 -0
- package/dist/resources/extensions/gsd/state.ts +569 -0
- package/dist/resources/extensions/gsd/templates/context.md +76 -0
- package/dist/resources/extensions/gsd/templates/decisions.md +8 -0
- package/dist/resources/extensions/gsd/templates/milestone-summary.md +73 -0
- package/dist/resources/extensions/gsd/templates/plan.md +131 -0
- package/dist/resources/extensions/gsd/templates/preferences.md +23 -0
- package/dist/resources/extensions/gsd/templates/project.md +31 -0
- package/dist/resources/extensions/gsd/templates/reassessment.md +28 -0
- package/dist/resources/extensions/gsd/templates/requirements.md +81 -0
- package/dist/resources/extensions/gsd/templates/research.md +46 -0
- package/dist/resources/extensions/gsd/templates/roadmap.md +118 -0
- package/dist/resources/extensions/gsd/templates/secrets-manifest.md +22 -0
- package/dist/resources/extensions/gsd/templates/slice-context.md +58 -0
- package/dist/resources/extensions/gsd/templates/slice-summary.md +99 -0
- package/dist/resources/extensions/gsd/templates/state.md +19 -0
- package/dist/resources/extensions/gsd/templates/task-plan.md +52 -0
- package/dist/resources/extensions/gsd/templates/task-summary.md +57 -0
- package/dist/resources/extensions/gsd/templates/uat.md +54 -0
- package/dist/resources/extensions/gsd/tests/activity-log-prune.test.ts +297 -0
- package/dist/resources/extensions/gsd/tests/activity-log-save.test.ts +127 -0
- package/dist/resources/extensions/gsd/tests/auto-draft-pause.test.ts +109 -0
- package/dist/resources/extensions/gsd/tests/auto-preflight.test.ts +45 -0
- package/dist/resources/extensions/gsd/tests/auto-secrets-gate.test.ts +196 -0
- package/dist/resources/extensions/gsd/tests/auto-supervisor.test.mjs +53 -0
- package/dist/resources/extensions/gsd/tests/collect-from-manifest.test.ts +469 -0
- package/dist/resources/extensions/gsd/tests/complete-milestone.test.ts +200 -0
- package/dist/resources/extensions/gsd/tests/cost-projection.test.ts +134 -0
- package/dist/resources/extensions/gsd/tests/derive-state-deps.test.ts +312 -0
- package/dist/resources/extensions/gsd/tests/derive-state-draft.test.ts +299 -0
- package/dist/resources/extensions/gsd/tests/derive-state.test.ts +660 -0
- package/dist/resources/extensions/gsd/tests/discuss-prompt.test.ts +27 -0
- package/dist/resources/extensions/gsd/tests/dispatch-guard.test.ts +91 -0
- package/dist/resources/extensions/gsd/tests/doctor-fixlevel.test.ts +170 -0
- package/dist/resources/extensions/gsd/tests/doctor.test.ts +594 -0
- package/dist/resources/extensions/gsd/tests/draft-promotion.test.ts +169 -0
- package/dist/resources/extensions/gsd/tests/exit-command.test.ts +50 -0
- package/dist/resources/extensions/gsd/tests/git-service.test.ts +1788 -0
- package/dist/resources/extensions/gsd/tests/idle-recovery.test.ts +577 -0
- package/dist/resources/extensions/gsd/tests/integration-mixed-milestones.test.ts +580 -0
- package/dist/resources/extensions/gsd/tests/manifest-status.test.ts +283 -0
- package/dist/resources/extensions/gsd/tests/metrics-io.test.ts +176 -0
- package/dist/resources/extensions/gsd/tests/metrics.test.ts +188 -0
- package/dist/resources/extensions/gsd/tests/migrate-command.test.ts +369 -0
- package/dist/resources/extensions/gsd/tests/migrate-parser.test.ts +757 -0
- package/dist/resources/extensions/gsd/tests/migrate-transformer.test.ts +635 -0
- package/dist/resources/extensions/gsd/tests/migrate-validator-parsers.test.ts +414 -0
- package/dist/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +297 -0
- package/dist/resources/extensions/gsd/tests/migrate-writer.test.ts +398 -0
- package/dist/resources/extensions/gsd/tests/must-have-parser.test.ts +291 -0
- package/dist/resources/extensions/gsd/tests/network-error-fallback.test.ts +54 -0
- package/dist/resources/extensions/gsd/tests/next-milestone-id.test.ts +66 -0
- package/dist/resources/extensions/gsd/tests/orphaned-branch.test.ts +353 -0
- package/dist/resources/extensions/gsd/tests/parsers.test.ts +1664 -0
- package/dist/resources/extensions/gsd/tests/plan-milestone.test.ts +133 -0
- package/dist/resources/extensions/gsd/tests/plan-quality-validator.test.ts +363 -0
- package/dist/resources/extensions/gsd/tests/post-unit-hooks.test.ts +297 -0
- package/dist/resources/extensions/gsd/tests/preferences-hooks.test.ts +226 -0
- package/dist/resources/extensions/gsd/tests/queue-draft-detection.test.ts +126 -0
- package/dist/resources/extensions/gsd/tests/reassess-prompt.test.ts +142 -0
- package/dist/resources/extensions/gsd/tests/regex-hardening.test.ts +281 -0
- package/dist/resources/extensions/gsd/tests/remote-questions.test.ts +155 -0
- package/dist/resources/extensions/gsd/tests/remote-status.test.ts +99 -0
- package/dist/resources/extensions/gsd/tests/replan-slice.test.ts +493 -0
- package/dist/resources/extensions/gsd/tests/requirements.test.ts +106 -0
- package/dist/resources/extensions/gsd/tests/resolve-ts-hooks.mjs +35 -0
- package/dist/resources/extensions/gsd/tests/resolve-ts.mjs +11 -0
- package/dist/resources/extensions/gsd/tests/roadmap-slices.test.ts +41 -0
- package/dist/resources/extensions/gsd/tests/run-uat.test.ts +316 -0
- package/dist/resources/extensions/gsd/tests/secure-env-collect.test.ts +185 -0
- package/dist/resources/extensions/gsd/tests/smart-entry-draft.test.ts +123 -0
- package/dist/resources/extensions/gsd/tests/test-helpers.ts +61 -0
- package/dist/resources/extensions/gsd/tests/unique-milestone-ids.test.ts +219 -0
- package/dist/resources/extensions/gsd/tests/unit-runtime.test.ts +234 -0
- package/dist/resources/extensions/gsd/tests/workspace-index.test.ts +75 -0
- package/dist/resources/extensions/gsd/tests/worktree-integration.test.ts +234 -0
- package/dist/resources/extensions/gsd/tests/worktree-manager.test.ts +141 -0
- package/dist/resources/extensions/gsd/tests/worktree.test.ts +597 -0
- package/dist/resources/extensions/gsd/tests/write-gate.test.ts +122 -0
- package/dist/resources/extensions/gsd/types.ts +296 -0
- package/dist/resources/extensions/gsd/unit-runtime.ts +184 -0
- package/dist/resources/extensions/gsd/workspace-index.ts +189 -0
- package/dist/resources/extensions/gsd/worktree-command.ts +845 -0
- package/dist/resources/extensions/gsd/worktree-manager.ts +459 -0
- package/dist/resources/extensions/gsd/{worktree.js â worktree.ts} +92 -61
- package/dist/resources/extensions/mac-tools/index.ts +852 -0
- package/dist/resources/extensions/mac-tools/swift-cli/Package.swift +22 -0
- package/dist/resources/extensions/mac-tools/swift-cli/Sources/main.swift +1318 -0
- package/dist/resources/extensions/mcporter/index.ts +429 -0
- package/dist/resources/extensions/remote-questions/config.ts +81 -0
- package/dist/resources/extensions/remote-questions/discord-adapter.ts +128 -0
- package/dist/resources/extensions/remote-questions/format.ts +163 -0
- package/dist/resources/extensions/remote-questions/manager.ts +192 -0
- package/dist/resources/extensions/remote-questions/remote-command.ts +361 -0
- package/dist/resources/extensions/remote-questions/slack-adapter.ts +92 -0
- package/dist/resources/extensions/remote-questions/status.ts +31 -0
- package/dist/resources/extensions/remote-questions/store.ts +77 -0
- package/dist/resources/extensions/remote-questions/types.ts +75 -0
- package/dist/resources/extensions/search-the-web/cache.ts +78 -0
- package/dist/resources/extensions/search-the-web/command-search-provider.ts +99 -0
- package/dist/resources/extensions/search-the-web/format.ts +258 -0
- package/dist/resources/extensions/search-the-web/http.ts +238 -0
- package/dist/resources/extensions/search-the-web/index.ts +65 -0
- package/dist/resources/extensions/search-the-web/native-search.ts +165 -0
- package/dist/resources/extensions/search-the-web/provider.ts +136 -0
- package/dist/resources/extensions/search-the-web/tavily.ts +116 -0
- package/dist/resources/extensions/search-the-web/tool-fetch-page.ts +581 -0
- package/dist/resources/extensions/search-the-web/tool-llm-context.ts +620 -0
- package/dist/resources/extensions/search-the-web/tool-search.ts +635 -0
- package/dist/resources/extensions/search-the-web/url-utils.ts +91 -0
- package/dist/resources/extensions/shared/bundled-extension-paths.ts +11 -0
- package/dist/resources/extensions/shared/confirm-ui.ts +126 -0
- package/dist/resources/extensions/shared/interview-ui.ts +613 -0
- package/dist/resources/extensions/shared/next-action-ui.ts +197 -0
- package/dist/resources/extensions/shared/progress-widget.ts +282 -0
- package/dist/resources/extensions/shared/terminal.ts +23 -0
- package/dist/resources/extensions/shared/thinking-widget.ts +107 -0
- package/dist/resources/extensions/shared/ui.ts +400 -0
- package/dist/resources/extensions/shared/wizard-ui.ts +551 -0
- package/dist/resources/extensions/slash-commands/audit.ts +88 -0
- package/dist/resources/extensions/slash-commands/clear.ts +10 -0
- package/dist/resources/extensions/slash-commands/create-extension.ts +297 -0
- package/dist/resources/extensions/slash-commands/create-slash-command.ts +234 -0
- package/dist/resources/extensions/slash-commands/index.ts +12 -0
- package/dist/resources/extensions/subagent/agents.ts +126 -0
- package/dist/resources/extensions/subagent/index.ts +1072 -0
- package/dist/resources/extensions/subagent/isolation.ts +498 -0
- package/dist/resources/extensions/ttsr/index.ts +163 -0
- package/dist/resources/extensions/ttsr/rule-loader.ts +121 -0
- package/dist/resources/extensions/ttsr/ttsr-interrupt.md +6 -0
- package/dist/resources/extensions/ttsr/ttsr-manager.ts +430 -0
- package/dist/resources/extensions/universal-config/discovery.ts +78 -0
- package/dist/resources/extensions/universal-config/format.ts +160 -0
- package/dist/resources/extensions/universal-config/index.ts +118 -0
- package/dist/resources/extensions/universal-config/package.json +11 -0
- package/dist/resources/extensions/universal-config/scanners.ts +579 -0
- package/dist/resources/extensions/universal-config/tests/discovery.test.ts +111 -0
- package/dist/resources/extensions/universal-config/tests/format.test.ts +111 -0
- package/dist/resources/extensions/universal-config/tests/scanners.test.ts +438 -0
- package/dist/resources/extensions/universal-config/tools.ts +60 -0
- package/dist/resources/extensions/universal-config/types.ts +116 -0
- package/dist/resources/extensions/voice/index.ts +271 -0
- package/dist/resources/extensions/voice/speech-recognizer.py +504 -0
- package/dist/resources/extensions/voice/speech-recognizer.swift +154 -0
- package/dist/resources/skills/debug-like-expert/SKILL.md +231 -0
- package/dist/resources/skills/debug-like-expert/references/debugging-mindset.md +253 -0
- package/dist/resources/skills/debug-like-expert/references/hypothesis-testing.md +373 -0
- package/dist/resources/skills/debug-like-expert/references/investigation-techniques.md +337 -0
- package/dist/resources/skills/debug-like-expert/references/verification-patterns.md +425 -0
- package/dist/resources/skills/debug-like-expert/references/when-to-research.md +361 -0
- package/dist/resources/skills/frontend-design/SKILL.md +45 -0
- package/dist/resources/skills/github-workflows/SKILL.md +92 -0
- package/dist/resources/skills/github-workflows/references/gh/SKILL.md +255 -0
- package/dist/resources/skills/github-workflows/references/gh/references/issue-stories.md +204 -0
- package/dist/resources/skills/github-workflows/references/gh/references/labels.md +170 -0
- package/dist/resources/skills/github-workflows/references/gh/references/milestones.md +158 -0
- package/dist/resources/skills/github-workflows/references/gh/references/projects-v2.md +177 -0
- package/dist/resources/skills/github-workflows/references/gh/scripts/experiment_cleanup.py +191 -0
- package/dist/resources/skills/github-workflows/references/gh/scripts/github_project_setup.py +799 -0
- package/dist/resources/skills/github-workflows/references/gh/tests/__init__.py +0 -0
- package/dist/resources/skills/github-workflows/references/gh/tests/test_github_project_setup.py +608 -0
- package/dist/resources/skills/swiftui/SKILL.md +208 -0
- package/dist/resources/skills/swiftui/references/animations.md +921 -0
- package/dist/resources/skills/swiftui/references/architecture.md +1561 -0
- package/dist/resources/skills/swiftui/references/layout-system.md +1186 -0
- package/dist/resources/skills/swiftui/references/navigation.md +1492 -0
- package/dist/resources/skills/swiftui/references/networking-async.md +214 -0
- package/dist/resources/skills/swiftui/references/performance.md +1706 -0
- package/dist/resources/skills/swiftui/references/platform-integration.md +204 -0
- package/dist/resources/skills/swiftui/references/state-management.md +1443 -0
- package/dist/resources/skills/swiftui/references/swiftdata.md +297 -0
- package/dist/resources/skills/swiftui/references/testing-debugging.md +247 -0
- package/dist/resources/skills/swiftui/references/uikit-appkit-interop.md +218 -0
- package/dist/resources/skills/swiftui/workflows/add-feature.md +191 -0
- package/dist/resources/skills/swiftui/workflows/build-new-app.md +311 -0
- package/dist/resources/skills/swiftui/workflows/debug-swiftui.md +192 -0
- package/dist/resources/skills/swiftui/workflows/optimize-performance.md +197 -0
- package/dist/resources/skills/swiftui/workflows/ship-app.md +203 -0
- package/dist/resources/skills/swiftui/workflows/write-tests.md +235 -0
- package/dist/wizard.js +1 -0
- package/package.json +8 -6
- package/packages/native/dist/fd/index.d.ts +1 -0
- package/packages/native/dist/fd/index.js +1 -0
- package/packages/native/dist/grep/index.d.ts +2 -1
- package/packages/native/dist/grep/index.js +1 -0
- package/packages/native/src/__tests__/fd.test.mjs +35 -0
- package/packages/native/src/__tests__/grep.test.mjs +26 -9
- package/packages/native/src/fd/index.ts +1 -0
- package/packages/native/src/grep/index.ts +3 -2
- package/packages/pi-agent-core/dist/agent-loop.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/agent-loop.js +169 -55
- package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
- package/packages/pi-agent-core/dist/agent.d.ts +13 -1
- package/packages/pi-agent-core/dist/agent.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/agent.js +16 -0
- package/packages/pi-agent-core/dist/agent.js.map +1 -1
- package/packages/pi-agent-core/dist/types.d.ts +91 -1
- package/packages/pi-agent-core/dist/types.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/types.js.map +1 -1
- package/packages/pi-agent-core/src/agent-loop.ts +273 -63
- package/packages/pi-agent-core/src/agent.ts +24 -0
- package/packages/pi-agent-core/src/types.ts +98 -0
- package/packages/pi-ai/dist/env-api-keys.js +2 -0
- package/packages/pi-ai/dist/env-api-keys.js.map +1 -1
- package/packages/pi-ai/dist/models.generated.d.ts +314 -0
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +236 -0
- package/packages/pi-ai/dist/models.generated.js.map +1 -1
- package/packages/pi-ai/dist/providers/google-gemini-cli.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/google-gemini-cli.js +6 -0
- package/packages/pi-ai/dist/providers/google-gemini-cli.js.map +1 -1
- package/packages/pi-ai/dist/providers/openai-completions.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/openai-completions.js +2 -0
- package/packages/pi-ai/dist/providers/openai-completions.js.map +1 -1
- package/packages/pi-ai/dist/types.d.ts +1 -1
- package/packages/pi-ai/dist/types.d.ts.map +1 -1
- package/packages/pi-ai/dist/types.js.map +1 -1
- package/packages/pi-ai/src/env-api-keys.ts +2 -0
- package/packages/pi-ai/src/models.generated.ts +236 -0
- package/packages/pi-ai/src/providers/google-gemini-cli.ts +8 -0
- package/packages/pi-ai/src/providers/openai-completions.ts +3 -0
- package/packages/pi-ai/src/types.ts +2 -1
- package/packages/pi-coding-agent/dist/cli/args.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/cli/args.js +1 -0
- package/packages/pi-coding-agent/dist/cli/args.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts +26 -0
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js +137 -22
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.d.ts +20 -0
- package/packages/pi-coding-agent/dist/core/auth-storage.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.js +43 -0
- package/packages/pi-coding-agent/dist/core/auth-storage.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/fallback-resolver.d.ts +51 -0
- package/packages/pi-coding-agent/dist/core/fallback-resolver.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/fallback-resolver.js +119 -0
- package/packages/pi-coding-agent/dist/core/fallback-resolver.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/fallback-resolver.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/fallback-resolver.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/fallback-resolver.test.js +183 -0
- package/packages/pi-coding-agent/dist/core/fallback-resolver.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/index.d.ts +1 -0
- package/packages/pi-coding-agent/dist/core/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/index.js +1 -0
- package/packages/pi-coding-agent/dist/core/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-resolver.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-resolver.js +1 -0
- package/packages/pi-coding-agent/dist/core/model-resolver.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/session-manager.d.ts +12 -1
- package/packages/pi-coding-agent/dist/core/session-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/session-manager.js +37 -1
- package/packages/pi-coding-agent/dist/core/session-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/session-manager.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/session-manager.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/session-manager.test.js +61 -0
- package/packages/pi-coding-agent/dist/core/session-manager.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +20 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js +47 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/find.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/find.js +1 -0
- package/packages/pi-coding-agent/dist/core/tools/find.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +6 -15
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/login-dialog.d.ts +18 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/login-dialog.js +46 -4
- package/packages/pi-coding-agent/dist/modes/interactive/components/login-dialog.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +25 -2
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/src/cli/args.ts +1 -0
- package/packages/pi-coding-agent/src/core/agent-session.ts +167 -22
- package/packages/pi-coding-agent/src/core/auth-storage.ts +45 -0
- package/packages/pi-coding-agent/src/core/fallback-resolver.test.ts +229 -0
- package/packages/pi-coding-agent/src/core/fallback-resolver.ts +165 -0
- package/packages/pi-coding-agent/src/core/index.ts +1 -0
- package/packages/pi-coding-agent/src/core/model-resolver.ts +1 -0
- package/packages/pi-coding-agent/src/core/session-manager.test.ts +65 -0
- package/packages/pi-coding-agent/src/core/session-manager.ts +51 -1
- package/packages/pi-coding-agent/src/core/settings-manager.ts +66 -0
- package/packages/pi-coding-agent/src/core/tools/find.ts +1 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +6 -16
- package/packages/pi-coding-agent/src/modes/interactive/components/login-dialog.ts +49 -4
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +28 -2
- package/packages/pi-tui/dist/autocomplete.d.ts.map +1 -1
- package/packages/pi-tui/dist/autocomplete.js +3 -4
- package/packages/pi-tui/dist/autocomplete.js.map +1 -1
- package/packages/pi-tui/dist/components/editor.d.ts +7 -0
- package/packages/pi-tui/dist/components/editor.d.ts.map +1 -1
- package/packages/pi-tui/dist/components/editor.js +57 -50
- package/packages/pi-tui/dist/components/editor.js.map +1 -1
- package/packages/pi-tui/src/autocomplete.ts +3 -5
- package/packages/pi-tui/src/components/editor.ts +70 -49
- package/pkg/dist/core/export-html/ansi-to-html.d.ts +22 -0
- package/pkg/dist/core/export-html/ansi-to-html.d.ts.map +1 -0
- package/pkg/dist/core/export-html/ansi-to-html.js +249 -0
- package/pkg/dist/core/export-html/ansi-to-html.js.map +1 -0
- package/pkg/dist/core/export-html/index.d.ts +37 -0
- package/pkg/dist/core/export-html/index.d.ts.map +1 -0
- package/pkg/dist/core/export-html/index.js +223 -0
- package/pkg/dist/core/export-html/index.js.map +1 -0
- package/pkg/dist/core/export-html/template.css +971 -0
- package/pkg/dist/core/export-html/template.html +54 -0
- package/pkg/dist/core/export-html/template.js +1583 -0
- package/pkg/dist/core/export-html/tool-renderer.d.ts +38 -0
- package/pkg/dist/core/export-html/tool-renderer.d.ts.map +1 -0
- package/pkg/dist/core/export-html/tool-renderer.js +70 -0
- package/pkg/dist/core/export-html/tool-renderer.js.map +1 -0
- package/pkg/dist/core/export-html/vendor/highlight.min.js +1213 -0
- package/pkg/dist/core/export-html/vendor/marked.min.js +6 -0
- package/scripts/postinstall.js +30 -17
- package/src/resources/extensions/bg-shell/index.ts +51 -7
- package/src/resources/extensions/gsd/activity-log.ts +61 -14
- package/src/resources/extensions/gsd/auto.ts +288 -19
- package/src/resources/extensions/gsd/commands.ts +9 -3
- package/src/resources/extensions/gsd/dashboard-overlay.ts +55 -12
- package/src/resources/extensions/gsd/docs/preferences-reference.md +25 -0
- package/src/resources/extensions/gsd/doctor.ts +60 -3
- package/src/resources/extensions/gsd/files.ts +45 -1
- package/src/resources/extensions/gsd/git-service.ts +46 -41
- package/src/resources/extensions/gsd/guided-flow.ts +81 -9
- package/src/resources/extensions/gsd/index.ts +62 -1
- package/src/resources/extensions/gsd/native-git-bridge.ts +181 -0
- package/src/resources/extensions/gsd/paths.ts +35 -4
- package/src/resources/extensions/gsd/post-unit-hooks.ts +449 -0
- package/src/resources/extensions/gsd/preferences.ts +232 -1
- package/src/resources/extensions/gsd/prompt-loader.ts +45 -3
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -3
- package/src/resources/extensions/gsd/prompts/discuss.md +10 -8
- package/src/resources/extensions/gsd/prompts/execute-task.md +4 -2
- package/src/resources/extensions/gsd/prompts/guided-complete-slice.md +3 -1
- package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +3 -1
- package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +3 -1
- package/src/resources/extensions/gsd/prompts/guided-execute-task.md +3 -1
- package/src/resources/extensions/gsd/prompts/guided-plan-milestone.md +4 -2
- package/src/resources/extensions/gsd/prompts/guided-plan-slice.md +3 -1
- package/src/resources/extensions/gsd/prompts/guided-research-slice.md +3 -1
- package/src/resources/extensions/gsd/prompts/plan-milestone.md +9 -12
- package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -3
- package/src/resources/extensions/gsd/prompts/queue.md +3 -1
- package/src/resources/extensions/gsd/prompts/research-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/research-slice.md +1 -1
- package/src/resources/extensions/gsd/state.ts +130 -18
- package/src/resources/extensions/gsd/templates/context.md +1 -1
- package/src/resources/extensions/gsd/templates/state.md +3 -3
- package/src/resources/extensions/gsd/tests/activity-log-save.test.ts +127 -0
- package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +5 -1
- package/src/resources/extensions/gsd/tests/doctor.test.ts +115 -1
- package/src/resources/extensions/gsd/tests/draft-promotion.test.ts +6 -2
- package/src/resources/extensions/gsd/tests/git-service.test.ts +35 -35
- package/src/resources/extensions/gsd/tests/idle-recovery.test.ts +8 -8
- package/src/resources/extensions/gsd/tests/integration-mixed-milestones.test.ts +4 -1
- package/src/resources/extensions/gsd/tests/network-error-fallback.test.ts +54 -0
- package/src/resources/extensions/gsd/tests/orphaned-branch.test.ts +5 -5
- package/src/resources/extensions/gsd/tests/post-unit-hooks.test.ts +297 -0
- package/src/resources/extensions/gsd/tests/preferences-hooks.test.ts +226 -0
- package/src/resources/extensions/gsd/tests/regex-hardening.test.ts +12 -0
- package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +6 -0
- package/src/resources/extensions/gsd/tests/worktree-integration.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/worktree-manager.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/worktree.test.ts +19 -19
- package/src/resources/extensions/gsd/types.ts +109 -0
- package/src/resources/extensions/gsd/worktree-manager.ts +72 -13
- package/src/resources/extensions/gsd/worktree.ts +5 -4
- package/src/resources/extensions/search-the-web/command-search-provider.ts +8 -4
- package/src/resources/extensions/search-the-web/native-search.ts +32 -23
- package/src/resources/extensions/search-the-web/provider.ts +19 -2
- package/src/resources/extensions/search-the-web/tool-fetch-page.ts +62 -0
- package/src/resources/extensions/search-the-web/tool-llm-context.ts +62 -3
- package/src/resources/extensions/search-the-web/tool-search.ts +62 -3
- package/src/resources/extensions/shared/bundled-extension-paths.ts +11 -0
- package/src/resources/extensions/subagent/index.ts +2 -1
- package/src/resources/skills/github-workflows/SKILL.md +5 -0
- package/dist/resources/extensions/gsd/git-service.d.ts +0 -225
- package/dist/resources/extensions/gsd/git-service.js +0 -756
- package/dist/resources/extensions/gsd/preferences.d.ts +0 -122
- package/dist/resources/extensions/gsd/preferences.js +0 -616
- package/dist/resources/extensions/gsd/worktree.d.ts +0 -106
- package/dist/resources/extensions/remote-questions/config.d.ts +0 -14
- package/dist/resources/extensions/remote-questions/config.js +0 -68
- package/dist/resources/extensions/remote-questions/discord-adapter.d.ts +0 -17
- package/dist/resources/extensions/remote-questions/discord-adapter.js +0 -118
- package/dist/resources/extensions/remote-questions/format.d.ts +0 -38
- package/dist/resources/extensions/remote-questions/format.js +0 -119
- package/dist/resources/extensions/remote-questions/manager.d.ts +0 -23
- package/dist/resources/extensions/remote-questions/manager.js +0 -161
- package/dist/resources/extensions/remote-questions/remote-command.d.ts +0 -6
- package/dist/resources/extensions/remote-questions/remote-command.js +0 -358
- package/dist/resources/extensions/remote-questions/slack-adapter.d.ts +0 -15
- package/dist/resources/extensions/remote-questions/slack-adapter.js +0 -82
- package/dist/resources/extensions/remote-questions/status.d.ts +0 -9
- package/dist/resources/extensions/remote-questions/status.js +0 -25
- package/dist/resources/extensions/remote-questions/store.d.ts +0 -11
- package/dist/resources/extensions/remote-questions/store.js +0 -66
- package/dist/resources/extensions/remote-questions/types.d.ts +0 -68
- package/dist/resources/extensions/remote-questions/types.js +0 -4
|
@@ -0,0 +1,469 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for S02 Enhanced Collection TUI functions:
|
|
3
|
+
* - collectSecretsFromManifest() orchestrator categorization and flow
|
|
4
|
+
* - showSecretsSummary() render output
|
|
5
|
+
* - collectOneSecret() guidance rendering
|
|
6
|
+
*
|
|
7
|
+
* These tests import functions that don't exist yet (T02/T03 will build them).
|
|
8
|
+
* They are expected to fail until implementation is complete.
|
|
9
|
+
*
|
|
10
|
+
* Uses dynamic imports so individual tests fail with clear messages
|
|
11
|
+
* instead of the entire file crashing at import time.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import test from "node:test";
|
|
15
|
+
import assert from "node:assert/strict";
|
|
16
|
+
import { mkdirSync, writeFileSync, readFileSync, rmSync } from "node:fs";
|
|
17
|
+
import { join } from "node:path";
|
|
18
|
+
import { tmpdir } from "node:os";
|
|
19
|
+
import type { SecretsManifest, SecretsManifestEntry } from "../types.ts";
|
|
20
|
+
|
|
21
|
+
// Dynamic imports for files.ts functions to avoid cascading failure
|
|
22
|
+
// when paths.js isn't available (files.ts statically imports paths.js)
|
|
23
|
+
async function loadFilesExports(): Promise<{
|
|
24
|
+
formatSecretsManifest: (m: SecretsManifest) => string;
|
|
25
|
+
parseSecretsManifest: (content: string) => SecretsManifest;
|
|
26
|
+
}> {
|
|
27
|
+
const mod = await import("../files.ts");
|
|
28
|
+
return {
|
|
29
|
+
formatSecretsManifest: mod.formatSecretsManifest,
|
|
30
|
+
parseSecretsManifest: mod.parseSecretsManifest,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// âââ Helpers ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
|
|
35
|
+
|
|
36
|
+
function makeTempDir(prefix: string): string {
|
|
37
|
+
const dir = join(tmpdir(), `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
|
38
|
+
mkdirSync(dir, { recursive: true });
|
|
39
|
+
return dir;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function makeManifest(entries: Partial<SecretsManifestEntry>[]): SecretsManifest {
|
|
43
|
+
return {
|
|
44
|
+
milestone: "M001",
|
|
45
|
+
generatedAt: "2026-03-12T00:00:00Z",
|
|
46
|
+
entries: entries.map((e) => ({
|
|
47
|
+
key: e.key ?? "TEST_KEY",
|
|
48
|
+
service: e.service ?? "TestService",
|
|
49
|
+
dashboardUrl: e.dashboardUrl ?? "",
|
|
50
|
+
guidance: e.guidance ?? [],
|
|
51
|
+
formatHint: e.formatHint ?? "",
|
|
52
|
+
status: e.status ?? "pending",
|
|
53
|
+
destination: e.destination ?? "dotenv",
|
|
54
|
+
})),
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async function writeManifestFile(dir: string, manifest: SecretsManifest): Promise<string> {
|
|
59
|
+
const { formatSecretsManifest } = await loadFilesExports();
|
|
60
|
+
const milestoneDir = join(dir, ".gsd", "milestones", "M001");
|
|
61
|
+
mkdirSync(milestoneDir, { recursive: true });
|
|
62
|
+
const filePath = join(milestoneDir, "M001-SECRETS.md");
|
|
63
|
+
writeFileSync(filePath, formatSecretsManifest(manifest));
|
|
64
|
+
return filePath;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async function loadOrchestrator(): Promise<{
|
|
68
|
+
collectSecretsFromManifest: Function;
|
|
69
|
+
showSecretsSummary: Function;
|
|
70
|
+
}> {
|
|
71
|
+
const mod = await import("../../get-secrets-from-user.ts");
|
|
72
|
+
if (typeof mod.collectSecretsFromManifest !== "function") {
|
|
73
|
+
throw new Error("collectSecretsFromManifest is not exported from get-secrets-from-user.ts â T03 will implement this");
|
|
74
|
+
}
|
|
75
|
+
if (typeof mod.showSecretsSummary !== "function") {
|
|
76
|
+
throw new Error("showSecretsSummary is not exported from get-secrets-from-user.ts â T03 will implement this");
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
collectSecretsFromManifest: mod.collectSecretsFromManifest,
|
|
80
|
+
showSecretsSummary: mod.showSecretsSummary,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
async function loadGuidanceExport(): Promise<{ collectOneSecretWithGuidance: Function }> {
|
|
85
|
+
const mod = await import("../../get-secrets-from-user.ts");
|
|
86
|
+
if (typeof mod.collectOneSecretWithGuidance !== "function") {
|
|
87
|
+
throw new Error("collectOneSecretWithGuidance is not exported from get-secrets-from-user.ts â T02 will implement this");
|
|
88
|
+
}
|
|
89
|
+
return { collectOneSecretWithGuidance: mod.collectOneSecretWithGuidance };
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// âââ collectSecretsFromManifest: categorization âââââââââââââââââââââââââââââââ
|
|
93
|
+
|
|
94
|
+
test("collectSecretsFromManifest: categorizes entries â pending keys need collection, existing keys are skipped", async () => {
|
|
95
|
+
const { collectSecretsFromManifest } = await loadOrchestrator();
|
|
96
|
+
|
|
97
|
+
const tmp = makeTempDir("manifest-collect");
|
|
98
|
+
const savedA = process.env.EXISTING_KEY_A;
|
|
99
|
+
try {
|
|
100
|
+
process.env.EXISTING_KEY_A = "already-set";
|
|
101
|
+
|
|
102
|
+
const manifest = makeManifest([
|
|
103
|
+
{ key: "EXISTING_KEY_A", status: "pending" },
|
|
104
|
+
{ key: "PENDING_KEY_B", status: "pending", guidance: ["Step 1: Go to dashboard", "Step 2: Click create key"] },
|
|
105
|
+
{ key: "SKIPPED_KEY_C", status: "skipped" },
|
|
106
|
+
]);
|
|
107
|
+
await writeManifestFile(tmp, manifest);
|
|
108
|
+
|
|
109
|
+
let callIndex = 0;
|
|
110
|
+
const mockCtx = {
|
|
111
|
+
cwd: tmp,
|
|
112
|
+
hasUI: true,
|
|
113
|
+
ui: {
|
|
114
|
+
custom: async (_factory: any) => {
|
|
115
|
+
callIndex++;
|
|
116
|
+
if (callIndex <= 1) return null; // summary screen dismiss
|
|
117
|
+
return "mock-secret-value"; // collect pending key
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
const result = await collectSecretsFromManifest(tmp, "M001", mockCtx as any);
|
|
123
|
+
|
|
124
|
+
// EXISTING_KEY_A should be in existingSkipped (it's in process.env)
|
|
125
|
+
assert.ok(result.existingSkipped?.includes("EXISTING_KEY_A"),
|
|
126
|
+
"EXISTING_KEY_A should be in existingSkipped");
|
|
127
|
+
|
|
128
|
+
// PENDING_KEY_B should have been collected (applied)
|
|
129
|
+
assert.ok(result.applied.includes("PENDING_KEY_B"),
|
|
130
|
+
"PENDING_KEY_B should be in applied");
|
|
131
|
+
|
|
132
|
+
// SKIPPED_KEY_C should remain skipped
|
|
133
|
+
assert.ok(result.skipped.includes("SKIPPED_KEY_C"),
|
|
134
|
+
"SKIPPED_KEY_C should be in skipped");
|
|
135
|
+
} finally {
|
|
136
|
+
delete process.env.EXISTING_KEY_A;
|
|
137
|
+
if (savedA !== undefined) process.env.EXISTING_KEY_A = savedA;
|
|
138
|
+
rmSync(tmp, { recursive: true, force: true });
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
test("collectSecretsFromManifest: existing keys are excluded from the collection list â not prompted", async () => {
|
|
143
|
+
const { collectSecretsFromManifest } = await loadOrchestrator();
|
|
144
|
+
|
|
145
|
+
const tmp = makeTempDir("manifest-collect-skip");
|
|
146
|
+
const savedA = process.env.ALREADY_SET_KEY;
|
|
147
|
+
try {
|
|
148
|
+
process.env.ALREADY_SET_KEY = "present";
|
|
149
|
+
|
|
150
|
+
const manifest = makeManifest([
|
|
151
|
+
{ key: "ALREADY_SET_KEY", status: "pending" },
|
|
152
|
+
{ key: "NEEDS_COLLECTION", status: "pending" },
|
|
153
|
+
]);
|
|
154
|
+
await writeManifestFile(tmp, manifest);
|
|
155
|
+
|
|
156
|
+
const collectedKeyNames: string[] = [];
|
|
157
|
+
let summaryShown = false;
|
|
158
|
+
const mockCtx = {
|
|
159
|
+
cwd: tmp,
|
|
160
|
+
hasUI: true,
|
|
161
|
+
ui: {
|
|
162
|
+
custom: async (factory: any) => {
|
|
163
|
+
// Intercept the factory to check what key is being collected
|
|
164
|
+
if (!summaryShown) {
|
|
165
|
+
summaryShown = true;
|
|
166
|
+
return null; // dismiss summary
|
|
167
|
+
}
|
|
168
|
+
collectedKeyNames.push("prompted");
|
|
169
|
+
return "mock-value";
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
const result = await collectSecretsFromManifest(tmp, "M001", mockCtx as any);
|
|
175
|
+
|
|
176
|
+
// ALREADY_SET_KEY should not have been prompted â only NEEDS_COLLECTION should
|
|
177
|
+
assert.ok(!result.applied.includes("ALREADY_SET_KEY"),
|
|
178
|
+
"ALREADY_SET_KEY should not be in applied (it was auto-skipped)");
|
|
179
|
+
assert.ok(result.existingSkipped?.includes("ALREADY_SET_KEY"),
|
|
180
|
+
"ALREADY_SET_KEY should be in existingSkipped");
|
|
181
|
+
} finally {
|
|
182
|
+
delete process.env.ALREADY_SET_KEY;
|
|
183
|
+
if (savedA !== undefined) process.env.ALREADY_SET_KEY = savedA;
|
|
184
|
+
rmSync(tmp, { recursive: true, force: true });
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
test("collectSecretsFromManifest: manifest statuses are updated after collection", async () => {
|
|
189
|
+
const { collectSecretsFromManifest } = await loadOrchestrator();
|
|
190
|
+
|
|
191
|
+
const tmp = makeTempDir("manifest-update");
|
|
192
|
+
try {
|
|
193
|
+
const manifest = makeManifest([
|
|
194
|
+
{ key: "KEY_TO_COLLECT", status: "pending" },
|
|
195
|
+
{ key: "KEY_TO_SKIP", status: "pending" },
|
|
196
|
+
]);
|
|
197
|
+
const manifestPath = await writeManifestFile(tmp, manifest);
|
|
198
|
+
|
|
199
|
+
let callIndex = 0;
|
|
200
|
+
const mockCtx = {
|
|
201
|
+
cwd: tmp,
|
|
202
|
+
hasUI: true,
|
|
203
|
+
ui: {
|
|
204
|
+
custom: async (_factory: any) => {
|
|
205
|
+
callIndex++;
|
|
206
|
+
if (callIndex <= 1) return null; // summary screen dismiss
|
|
207
|
+
if (callIndex === 2) return "secret-value"; // KEY_TO_COLLECT
|
|
208
|
+
return null; // KEY_TO_SKIP â user skips
|
|
209
|
+
},
|
|
210
|
+
},
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
await collectSecretsFromManifest(tmp, "M001", mockCtx as any);
|
|
214
|
+
|
|
215
|
+
// Read back the manifest file and verify statuses were updated
|
|
216
|
+
const { parseSecretsManifest } = await loadFilesExports();
|
|
217
|
+
const updatedContent = readFileSync(manifestPath, "utf8");
|
|
218
|
+
const updatedManifest = parseSecretsManifest(updatedContent);
|
|
219
|
+
|
|
220
|
+
const keyToCollect = updatedManifest.entries.find(e => e.key === "KEY_TO_COLLECT");
|
|
221
|
+
const keyToSkip = updatedManifest.entries.find(e => e.key === "KEY_TO_SKIP");
|
|
222
|
+
|
|
223
|
+
assert.equal(keyToCollect?.status, "collected",
|
|
224
|
+
"KEY_TO_COLLECT should have status 'collected' after providing a value");
|
|
225
|
+
assert.equal(keyToSkip?.status, "skipped",
|
|
226
|
+
"KEY_TO_SKIP should have status 'skipped' after user skipped it");
|
|
227
|
+
} finally {
|
|
228
|
+
rmSync(tmp, { recursive: true, force: true });
|
|
229
|
+
}
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
// âââ showSecretsSummary: render output ââââââââââââââââââââââââââââââââââââââââ
|
|
233
|
+
|
|
234
|
+
test("showSecretsSummary: produces lines with correct status glyphs for each entry status", async () => {
|
|
235
|
+
const { showSecretsSummary } = await loadOrchestrator();
|
|
236
|
+
|
|
237
|
+
const entries: SecretsManifestEntry[] = [
|
|
238
|
+
{ key: "PENDING_KEY", service: "Svc", dashboardUrl: "", guidance: [], formatHint: "", status: "pending", destination: "dotenv" },
|
|
239
|
+
{ key: "COLLECTED_KEY", service: "Svc", dashboardUrl: "", guidance: [], formatHint: "", status: "collected", destination: "dotenv" },
|
|
240
|
+
{ key: "SKIPPED_KEY", service: "Svc", dashboardUrl: "", guidance: [], formatHint: "", status: "skipped", destination: "dotenv" },
|
|
241
|
+
];
|
|
242
|
+
|
|
243
|
+
// showSecretsSummary renders a ctx.ui.custom screen. We capture the render output.
|
|
244
|
+
let renderFn: ((width: number) => string[]) | undefined;
|
|
245
|
+
const mockCtx = {
|
|
246
|
+
hasUI: true,
|
|
247
|
+
ui: {
|
|
248
|
+
custom: async (factory: any) => {
|
|
249
|
+
const mockTheme = {
|
|
250
|
+
fg: (_color: string, text: string) => text,
|
|
251
|
+
bold: (text: string) => text,
|
|
252
|
+
};
|
|
253
|
+
const mockTui = { requestRender: () => {}, terminal: { rows: 24, columns: 80 } };
|
|
254
|
+
const component = factory(mockTui, mockTheme, {}, () => {});
|
|
255
|
+
renderFn = component.render;
|
|
256
|
+
// Simulate immediate dismiss
|
|
257
|
+
component.handleInput("\x1b"); // escape
|
|
258
|
+
},
|
|
259
|
+
},
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
await showSecretsSummary(mockCtx as any, entries, []);
|
|
263
|
+
|
|
264
|
+
assert.ok(renderFn, "render function should have been captured from factory");
|
|
265
|
+
const lines = renderFn!(80);
|
|
266
|
+
|
|
267
|
+
// Verify each key appears in the output
|
|
268
|
+
const output = lines.join("\n");
|
|
269
|
+
assert.ok(output.includes("PENDING_KEY"), "should include PENDING_KEY");
|
|
270
|
+
assert.ok(output.includes("COLLECTED_KEY"), "should include COLLECTED_KEY");
|
|
271
|
+
assert.ok(output.includes("SKIPPED_KEY"), "should include SKIPPED_KEY");
|
|
272
|
+
|
|
273
|
+
// Verify we have at least one line per entry plus header/footer
|
|
274
|
+
assert.ok(lines.length >= 5, `should have at least 5 lines (got ${lines.length})`);
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
test("showSecretsSummary: existing keys shown with distinct status indicator", async () => {
|
|
278
|
+
const { showSecretsSummary } = await loadOrchestrator();
|
|
279
|
+
|
|
280
|
+
const entries: SecretsManifestEntry[] = [
|
|
281
|
+
{ key: "NEW_KEY", service: "Svc", dashboardUrl: "", guidance: [], formatHint: "", status: "pending", destination: "dotenv" },
|
|
282
|
+
{ key: "OLD_KEY", service: "Svc", dashboardUrl: "", guidance: [], formatHint: "", status: "collected", destination: "dotenv" },
|
|
283
|
+
];
|
|
284
|
+
const existingKeys = ["OLD_KEY"];
|
|
285
|
+
|
|
286
|
+
let renderFn: ((width: number) => string[]) | undefined;
|
|
287
|
+
const mockCtx = {
|
|
288
|
+
hasUI: true,
|
|
289
|
+
ui: {
|
|
290
|
+
custom: async (factory: any) => {
|
|
291
|
+
const mockTheme = {
|
|
292
|
+
fg: (_color: string, text: string) => text,
|
|
293
|
+
bold: (text: string) => text,
|
|
294
|
+
};
|
|
295
|
+
const mockTui = { requestRender: () => {}, terminal: { rows: 24, columns: 80 } };
|
|
296
|
+
const component = factory(mockTui, mockTheme, {}, () => {});
|
|
297
|
+
renderFn = component.render;
|
|
298
|
+
component.handleInput("\x1b");
|
|
299
|
+
},
|
|
300
|
+
},
|
|
301
|
+
};
|
|
302
|
+
|
|
303
|
+
await showSecretsSummary(mockCtx as any, entries, existingKeys);
|
|
304
|
+
|
|
305
|
+
assert.ok(renderFn, "render function should have been captured");
|
|
306
|
+
const lines = renderFn!(80);
|
|
307
|
+
const output = lines.join("\n");
|
|
308
|
+
|
|
309
|
+
assert.ok(output.includes("NEW_KEY"), "should include NEW_KEY");
|
|
310
|
+
assert.ok(output.includes("OLD_KEY"), "should include OLD_KEY");
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
// âââ collectOneSecret: guidance rendering âââââââââââââââââââââââââââââââââââââ
|
|
314
|
+
|
|
315
|
+
test("collectOneSecret: guidance lines appear in render output when guidance is provided", async () => {
|
|
316
|
+
const { collectOneSecretWithGuidance } = await loadGuidanceExport();
|
|
317
|
+
|
|
318
|
+
const guidanceSteps = [
|
|
319
|
+
"Navigate to https://platform.openai.com/api-keys",
|
|
320
|
+
"Click 'Create new secret key'",
|
|
321
|
+
"Copy the key value",
|
|
322
|
+
];
|
|
323
|
+
|
|
324
|
+
// Use the exported test helper to capture render output with guidance
|
|
325
|
+
let renderFn: ((width: number) => string[]) | undefined;
|
|
326
|
+
const mockCtx = {
|
|
327
|
+
hasUI: true,
|
|
328
|
+
ui: {
|
|
329
|
+
custom: async (factory: any) => {
|
|
330
|
+
const mockTheme = {
|
|
331
|
+
fg: (_color: string, text: string) => text,
|
|
332
|
+
bold: (text: string) => text,
|
|
333
|
+
};
|
|
334
|
+
const mockTui = { requestRender: () => {}, terminal: { rows: 24, columns: 80 } };
|
|
335
|
+
const component = factory(mockTui, mockTheme, {}, () => {});
|
|
336
|
+
renderFn = component.render;
|
|
337
|
+
component.handleInput("\x1b"); // escape to dismiss
|
|
338
|
+
},
|
|
339
|
+
},
|
|
340
|
+
};
|
|
341
|
+
|
|
342
|
+
await collectOneSecretWithGuidance(mockCtx, 0, 1, "OPENAI_API_KEY", "starts with sk-", guidanceSteps);
|
|
343
|
+
|
|
344
|
+
assert.ok(renderFn, "render function should have been captured");
|
|
345
|
+
const lines = renderFn!(80);
|
|
346
|
+
const output = lines.join("\n");
|
|
347
|
+
|
|
348
|
+
// Verify guidance steps appear in the output
|
|
349
|
+
assert.ok(output.includes("Navigate to"), "should include first guidance step");
|
|
350
|
+
assert.ok(output.includes("Create new secret key"), "should include second guidance step");
|
|
351
|
+
assert.ok(output.includes("Copy the key value"), "should include third guidance step");
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
test("collectOneSecret: guidance lines wrap long URLs instead of truncating", async () => {
|
|
355
|
+
const { collectOneSecretWithGuidance } = await loadGuidanceExport();
|
|
356
|
+
|
|
357
|
+
const longGuidance = [
|
|
358
|
+
"Navigate to https://platform.openai.com/account/api-keys and click 'Create new secret key'",
|
|
359
|
+
];
|
|
360
|
+
|
|
361
|
+
let renderFn: ((width: number) => string[]) | undefined;
|
|
362
|
+
const mockCtx = {
|
|
363
|
+
hasUI: true,
|
|
364
|
+
ui: {
|
|
365
|
+
custom: async (factory: any) => {
|
|
366
|
+
const mockTheme = {
|
|
367
|
+
fg: (_color: string, text: string) => text,
|
|
368
|
+
bold: (text: string) => text,
|
|
369
|
+
};
|
|
370
|
+
const mockTui = { requestRender: () => {}, terminal: { rows: 24, columns: 80 } };
|
|
371
|
+
const component = factory(mockTui, mockTheme, {}, () => {});
|
|
372
|
+
renderFn = component.render;
|
|
373
|
+
component.handleInput("\x1b");
|
|
374
|
+
},
|
|
375
|
+
},
|
|
376
|
+
};
|
|
377
|
+
|
|
378
|
+
await collectOneSecretWithGuidance(mockCtx, 0, 1, "TEST_KEY", undefined, longGuidance);
|
|
379
|
+
|
|
380
|
+
assert.ok(renderFn, "render function should have been captured");
|
|
381
|
+
// Render at narrow width to force wrapping
|
|
382
|
+
const lines = renderFn!(50);
|
|
383
|
+
const output = lines.join("\n");
|
|
384
|
+
|
|
385
|
+
// The full URL should be present (wrapped, not truncated)
|
|
386
|
+
assert.ok(output.includes("platform.openai.com"), "URL should not be truncated");
|
|
387
|
+
assert.ok(output.includes("Create new secret key"), "text after URL should not be truncated");
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
test("collectOneSecret: no guidance provided â render output has no guidance section", async () => {
|
|
391
|
+
const { collectOneSecretWithGuidance } = await loadGuidanceExport();
|
|
392
|
+
|
|
393
|
+
let renderFn: ((width: number) => string[]) | undefined;
|
|
394
|
+
const mockCtx = {
|
|
395
|
+
hasUI: true,
|
|
396
|
+
ui: {
|
|
397
|
+
custom: async (factory: any) => {
|
|
398
|
+
const mockTheme = {
|
|
399
|
+
fg: (_color: string, text: string) => text,
|
|
400
|
+
bold: (text: string) => text,
|
|
401
|
+
};
|
|
402
|
+
const mockTui = { requestRender: () => {}, terminal: { rows: 24, columns: 80 } };
|
|
403
|
+
const component = factory(mockTui, mockTheme, {}, () => {});
|
|
404
|
+
renderFn = component.render;
|
|
405
|
+
component.handleInput("\x1b");
|
|
406
|
+
},
|
|
407
|
+
},
|
|
408
|
+
};
|
|
409
|
+
|
|
410
|
+
// Call without guidance (undefined)
|
|
411
|
+
await collectOneSecretWithGuidance(mockCtx, 0, 1, "SOME_KEY", "hint text", undefined);
|
|
412
|
+
|
|
413
|
+
assert.ok(renderFn, "render function should have been captured");
|
|
414
|
+
const lines = renderFn!(80);
|
|
415
|
+
const output = lines.join("\n");
|
|
416
|
+
|
|
417
|
+
// Should include the key name and hint but no numbered guidance steps
|
|
418
|
+
assert.ok(output.includes("SOME_KEY"), "should include key name");
|
|
419
|
+
assert.ok(output.includes("hint text"), "should include hint");
|
|
420
|
+
// Should NOT have numbered step indicators (1., 2., etc.) for guidance
|
|
421
|
+
assert.ok(!output.match(/^\s*1\.\s/m), "should not have numbered guidance steps when no guidance provided");
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
// âââ collectSecretsFromManifest: returns structured result ââââââââââââââââââââ
|
|
425
|
+
|
|
426
|
+
test("collectSecretsFromManifest: returns result with applied, skipped, and existingSkipped arrays", async () => {
|
|
427
|
+
const { collectSecretsFromManifest } = await loadOrchestrator();
|
|
428
|
+
|
|
429
|
+
const tmp = makeTempDir("manifest-result");
|
|
430
|
+
const savedKey = process.env.RESULT_TEST_EXISTING;
|
|
431
|
+
try {
|
|
432
|
+
process.env.RESULT_TEST_EXISTING = "already-here";
|
|
433
|
+
|
|
434
|
+
const manifest = makeManifest([
|
|
435
|
+
{ key: "RESULT_TEST_EXISTING", status: "pending" },
|
|
436
|
+
{ key: "RESULT_TEST_NEW", status: "pending" },
|
|
437
|
+
]);
|
|
438
|
+
await writeManifestFile(tmp, manifest);
|
|
439
|
+
|
|
440
|
+
let callIndex = 0;
|
|
441
|
+
const mockCtx = {
|
|
442
|
+
cwd: tmp,
|
|
443
|
+
hasUI: true,
|
|
444
|
+
ui: {
|
|
445
|
+
custom: async (_factory: any) => {
|
|
446
|
+
callIndex++;
|
|
447
|
+
if (callIndex <= 1) return null; // summary dismiss
|
|
448
|
+
return "secret-value"; // collect the pending key
|
|
449
|
+
},
|
|
450
|
+
},
|
|
451
|
+
};
|
|
452
|
+
|
|
453
|
+
const result = await collectSecretsFromManifest(tmp, "M001", mockCtx as any);
|
|
454
|
+
|
|
455
|
+
// Verify result shape
|
|
456
|
+
assert.ok(Array.isArray(result.applied), "result should have applied array");
|
|
457
|
+
assert.ok(Array.isArray(result.skipped), "result should have skipped array");
|
|
458
|
+
assert.ok(Array.isArray(result.existingSkipped), "result should have existingSkipped array");
|
|
459
|
+
|
|
460
|
+
assert.ok(result.existingSkipped.includes("RESULT_TEST_EXISTING"),
|
|
461
|
+
"existing key should be in existingSkipped");
|
|
462
|
+
assert.ok(result.applied.includes("RESULT_TEST_NEW"),
|
|
463
|
+
"collected key should be in applied");
|
|
464
|
+
} finally {
|
|
465
|
+
delete process.env.RESULT_TEST_EXISTING;
|
|
466
|
+
if (savedKey !== undefined) process.env.RESULT_TEST_EXISTING = savedKey;
|
|
467
|
+
rmSync(tmp, { recursive: true, force: true });
|
|
468
|
+
}
|
|
469
|
+
});
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import { mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { join, dirname } from "node:path";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { createTestContext } from './test-helpers.ts';
|
|
6
|
+
import { clearPathCache } from '../paths.ts';
|
|
7
|
+
import { invalidateStateCache } from '../state.ts';
|
|
8
|
+
|
|
9
|
+
// loadPrompt reads from ~/.gsd/agent/extensions/gsd/prompts/ (main checkout).
|
|
10
|
+
// In a worktree the file may not exist there yet, so we resolve prompts
|
|
11
|
+
// relative to this test file's location (the worktree copy).
|
|
12
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
13
|
+
const worktreePromptsDir = join(__dirname, "..", "prompts");
|
|
14
|
+
|
|
15
|
+
const { assertEq, assertTrue, report } = createTestContext();
|
|
16
|
+
/**
|
|
17
|
+
* Load a prompt template from the worktree prompts directory
|
|
18
|
+
* and apply variable substitution (mirrors loadPrompt logic).
|
|
19
|
+
*/
|
|
20
|
+
function loadPromptFromWorktree(name: string, vars: Record<string, string> = {}): string {
|
|
21
|
+
const path = join(worktreePromptsDir, `${name}.md`);
|
|
22
|
+
let content = readFileSync(path, "utf-8");
|
|
23
|
+
for (const [key, value] of Object.entries(vars)) {
|
|
24
|
+
content = content.replaceAll(`{{${key}}}`, value);
|
|
25
|
+
}
|
|
26
|
+
return content.trim();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// âââ Fixture Helpers âââââââââââââââââââââââââââââââââââââââââââââââââââââââ
|
|
30
|
+
|
|
31
|
+
function createFixtureBase(): string {
|
|
32
|
+
const base = mkdtempSync(join(tmpdir(), "gsd-complete-ms-test-"));
|
|
33
|
+
mkdirSync(join(base, ".gsd", "milestones"), { recursive: true });
|
|
34
|
+
return base;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function writeRoadmap(base: string, mid: string, content: string): void {
|
|
38
|
+
const dir = join(base, ".gsd", "milestones", mid);
|
|
39
|
+
mkdirSync(dir, { recursive: true });
|
|
40
|
+
writeFileSync(join(dir, `${mid}-ROADMAP.md`), content);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function writeMilestoneSummary(base: string, mid: string, content: string): void {
|
|
44
|
+
const dir = join(base, ".gsd", "milestones", mid);
|
|
45
|
+
mkdirSync(dir, { recursive: true });
|
|
46
|
+
writeFileSync(join(dir, `${mid}-SUMMARY.md`), content);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function cleanup(base: string): void {
|
|
50
|
+
rmSync(base, { recursive: true, force: true });
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
|
|
54
|
+
// Tests
|
|
55
|
+
// âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
|
|
56
|
+
|
|
57
|
+
async function main(): Promise<void> {
|
|
58
|
+
|
|
59
|
+
// âââ Prompt Template Loading âââââââââââââââââââââââââââââââââââââââââââ
|
|
60
|
+
console.log("\n=== complete-milestone prompt template exists ===");
|
|
61
|
+
{
|
|
62
|
+
let result: string;
|
|
63
|
+
let threw = false;
|
|
64
|
+
try {
|
|
65
|
+
result = loadPromptFromWorktree("complete-milestone", {
|
|
66
|
+
milestoneId: "M001",
|
|
67
|
+
milestoneTitle: "Test Milestone",
|
|
68
|
+
roadmapPath: ".gsd/milestones/M001/M001-ROADMAP.md",
|
|
69
|
+
inlinedContext: "test context block",
|
|
70
|
+
});
|
|
71
|
+
} catch (err) {
|
|
72
|
+
threw = true;
|
|
73
|
+
result = "";
|
|
74
|
+
console.error(` ERROR: loadPrompt threw: ${err}`);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
assertTrue(!threw, "loadPrompt does not throw for complete-milestone");
|
|
78
|
+
assertTrue(typeof result === "string" && result.length > 0, "loadPrompt returns a non-empty string");
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// âââ Variable Substitution âââââââââââââââââââââââââââââââââââââââââââââ
|
|
82
|
+
console.log("\n=== prompt variable substitution ===");
|
|
83
|
+
{
|
|
84
|
+
const prompt = loadPromptFromWorktree("complete-milestone", {
|
|
85
|
+
milestoneId: "M001",
|
|
86
|
+
milestoneTitle: "Integration Feature",
|
|
87
|
+
roadmapPath: ".gsd/milestones/M001/M001-ROADMAP.md",
|
|
88
|
+
inlinedContext: "--- inlined slice summaries and context ---",
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
assertTrue(prompt.includes("M001"), "prompt contains milestoneId 'M001'");
|
|
92
|
+
assertTrue(prompt.includes("Integration Feature"), "prompt contains milestoneTitle");
|
|
93
|
+
assertTrue(prompt.includes(".gsd/milestones/M001/M001-ROADMAP.md"), "prompt contains roadmapPath");
|
|
94
|
+
assertTrue(prompt.includes("--- inlined slice summaries and context ---"), "prompt contains inlinedContext");
|
|
95
|
+
assertTrue(!prompt.includes("{{milestoneId}}"), "no un-substituted {{milestoneId}}");
|
|
96
|
+
assertTrue(!prompt.includes("{{milestoneTitle}}"), "no un-substituted {{milestoneTitle}}");
|
|
97
|
+
assertTrue(!prompt.includes("{{roadmapPath}}"), "no un-substituted {{roadmapPath}}");
|
|
98
|
+
assertTrue(!prompt.includes("{{inlinedContext}}"), "no un-substituted {{inlinedContext}}");
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// âââ Prompt Content Integrity ââââââââââââââââââââââââââââââââââââââââââ
|
|
102
|
+
console.log("\n=== prompt content integrity ===");
|
|
103
|
+
{
|
|
104
|
+
const prompt = loadPromptFromWorktree("complete-milestone", {
|
|
105
|
+
milestoneId: "M002",
|
|
106
|
+
milestoneTitle: "Completion Workflow",
|
|
107
|
+
roadmapPath: ".gsd/milestones/M002/M002-ROADMAP.md",
|
|
108
|
+
inlinedContext: "context",
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
assertTrue(prompt.includes("Complete Milestone"), "prompt contains 'Complete Milestone' heading");
|
|
112
|
+
assertTrue(prompt.includes("success criter") || prompt.includes("success criteria"), "prompt mentions success criteria verification");
|
|
113
|
+
assertTrue(prompt.includes("milestone-summary") || prompt.includes("milestoneSummary"), "prompt references milestone summary artifact");
|
|
114
|
+
assertTrue(prompt.includes("Milestone M002 complete"), "prompt contains completion sentinel for M002");
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// âââ diagnoseExpectedArtifact behavior âââââââââââââââââââââââââââââââââ
|
|
118
|
+
// Since diagnoseExpectedArtifact is not exported from auto.ts, we test
|
|
119
|
+
// the same logic by reimplementing the switch case for complete-milestone
|
|
120
|
+
// and verifying against known path patterns.
|
|
121
|
+
console.log("\n=== diagnoseExpectedArtifact logic for complete-milestone ===");
|
|
122
|
+
{
|
|
123
|
+
// Import the path helpers used by diagnoseExpectedArtifact
|
|
124
|
+
const { relMilestoneFile } = await import("../paths.ts");
|
|
125
|
+
|
|
126
|
+
// Simulate diagnoseExpectedArtifact("complete-milestone", "M001", base) logic
|
|
127
|
+
const base = createFixtureBase();
|
|
128
|
+
try {
|
|
129
|
+
writeRoadmap(base, "M001", `# M001\n\n## Slices\n- [x] **S01: Done** \`risk:low\` \`depends:[]\`\n > After this: done\n`);
|
|
130
|
+
|
|
131
|
+
const unitType = "complete-milestone";
|
|
132
|
+
const unitId = "M001";
|
|
133
|
+
const parts = unitId.split("/");
|
|
134
|
+
const mid = parts[0]!;
|
|
135
|
+
|
|
136
|
+
// This is the exact logic from diagnoseExpectedArtifact for "complete-milestone"
|
|
137
|
+
const result = `${relMilestoneFile(base, mid, "SUMMARY")} (milestone summary)`;
|
|
138
|
+
|
|
139
|
+
assertTrue(typeof result === "string", "diagnose returns a string");
|
|
140
|
+
assertTrue(result.includes("SUMMARY"), "diagnose result mentions SUMMARY");
|
|
141
|
+
assertTrue(result.includes("milestone"), "diagnose result mentions milestone");
|
|
142
|
+
assertTrue(result.includes("M001"), "diagnose result includes the milestone ID");
|
|
143
|
+
} finally {
|
|
144
|
+
cleanup(base);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// âââ deriveState integration: completing-milestone dispatches correctly â
|
|
149
|
+
console.log("\n=== deriveState completing-milestone integration ===");
|
|
150
|
+
{
|
|
151
|
+
const { deriveState, isMilestoneComplete, invalidateStateCache } = await import("../state.ts");
|
|
152
|
+
const { parseRoadmap } = await import("../files.ts");
|
|
153
|
+
|
|
154
|
+
const base = createFixtureBase();
|
|
155
|
+
try {
|
|
156
|
+
writeRoadmap(base, "M001", `# M001: Integration Test
|
|
157
|
+
|
|
158
|
+
**Vision:** Test completing-milestone flow.
|
|
159
|
+
|
|
160
|
+
## Slices
|
|
161
|
+
|
|
162
|
+
- [x] **S01: Slice One** \`risk:low\` \`depends:[]\`
|
|
163
|
+
> After this: done.
|
|
164
|
+
|
|
165
|
+
- [x] **S02: Slice Two** \`risk:low\` \`depends:[S01]\`
|
|
166
|
+
> After this: done.
|
|
167
|
+
`);
|
|
168
|
+
|
|
169
|
+
// Verify isMilestoneComplete returns true
|
|
170
|
+
const { loadFile } = await import("../files.ts");
|
|
171
|
+
const roadmapPath = join(base, ".gsd", "milestones", "M001", "M001-ROADMAP.md");
|
|
172
|
+
const roadmapContent = await loadFile(roadmapPath);
|
|
173
|
+
const roadmap = parseRoadmap(roadmapContent!);
|
|
174
|
+
assertTrue(isMilestoneComplete(roadmap), "isMilestoneComplete returns true when all slices are [x]");
|
|
175
|
+
|
|
176
|
+
// Verify deriveState returns completing-milestone phase
|
|
177
|
+
const state = await deriveState(base);
|
|
178
|
+
assertEq(state.phase, "completing-milestone", "deriveState returns completing-milestone when all slices done, no summary");
|
|
179
|
+
assertEq(state.activeMilestone?.id, "M001", "active milestone is M001");
|
|
180
|
+
assertEq(state.activeSlice, null, "no active slice in completing-milestone");
|
|
181
|
+
|
|
182
|
+
// Now add the summary and verify it transitions to complete
|
|
183
|
+
writeMilestoneSummary(base, "M001", "# M001 Summary\n\nDone.");
|
|
184
|
+
clearPathCache();
|
|
185
|
+
invalidateStateCache();
|
|
186
|
+
const stateAfter = await deriveState(base);
|
|
187
|
+
assertEq(stateAfter.phase, "complete", "deriveState returns complete after summary exists");
|
|
188
|
+
assertEq(stateAfter.registry[0]?.status, "complete", "registry shows complete status");
|
|
189
|
+
} finally {
|
|
190
|
+
cleanup(base);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
report();
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
main().catch((error) => {
|
|
198
|
+
console.error(error);
|
|
199
|
+
process.exit(1);
|
|
200
|
+
});
|