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,597 @@
|
|
|
1
|
+
import { existsSync, mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { execSync } from "node:child_process";
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
autoCommitCurrentBranch,
|
|
8
|
+
captureIntegrationBranch,
|
|
9
|
+
detectWorktreeName,
|
|
10
|
+
ensureSliceBranch,
|
|
11
|
+
getActiveSliceBranch,
|
|
12
|
+
getCurrentBranch,
|
|
13
|
+
getMainBranch,
|
|
14
|
+
getSliceBranchName,
|
|
15
|
+
isOnSliceBranch,
|
|
16
|
+
mergeSliceToMain,
|
|
17
|
+
parseSliceBranch,
|
|
18
|
+
setActiveMilestoneId,
|
|
19
|
+
SLICE_BRANCH_RE,
|
|
20
|
+
switchToMain,
|
|
21
|
+
} from "../worktree.ts";
|
|
22
|
+
import { readIntegrationBranch } from "../git-service.ts";
|
|
23
|
+
import { deriveState } from "../state.ts";
|
|
24
|
+
import { indexWorkspace } from "../workspace-index.ts";
|
|
25
|
+
import { createTestContext } from './test-helpers.ts';
|
|
26
|
+
|
|
27
|
+
const { assertEq, assertTrue, report } = createTestContext();
|
|
28
|
+
function run(command: string, cwd: string): string {
|
|
29
|
+
return execSync(command, { cwd, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" }).trim();
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const base = mkdtempSync(join(tmpdir(), "gsd-branch-test-"));
|
|
33
|
+
run("git init -b main", base);
|
|
34
|
+
run('git config user.name "Pi Test"', base);
|
|
35
|
+
run('git config user.email "pi@example.com"', base);
|
|
36
|
+
mkdirSync(join(base, ".gsd", "milestones", "M001", "slices", "S01", "tasks"), { recursive: true });
|
|
37
|
+
writeFileSync(join(base, "README.md"), "hello\n", "utf-8");
|
|
38
|
+
writeFileSync(join(base, ".gsd", "milestones", "M001", "M001-ROADMAP.md"), `# M001: Demo\n\n## Slices\n- [ ] **S01: Slice One** \`risk:low\` \`depends:[]\`\n > After this: demo works\n`, "utf-8");
|
|
39
|
+
writeFileSync(join(base, ".gsd", "milestones", "M001", "slices", "S01", "S01-PLAN.md"), `# S01: Slice One\n\n**Goal:** Demo\n**Demo:** Demo\n\n## Must-Haves\n- done\n\n## Tasks\n- [ ] **T01: Implement** \`est:10m\`\n do it\n`, "utf-8");
|
|
40
|
+
run("git add .", base);
|
|
41
|
+
run('git commit -m "chore: init"', base);
|
|
42
|
+
|
|
43
|
+
async function main(): Promise<void> {
|
|
44
|
+
console.log("\n=== ensureSliceBranch ===");
|
|
45
|
+
const created = ensureSliceBranch(base, "M001", "S01");
|
|
46
|
+
assertTrue(created, "branch created on first ensure");
|
|
47
|
+
assertEq(getCurrentBranch(base), "gsd/M001/S01", "switched to slice branch");
|
|
48
|
+
|
|
49
|
+
console.log("\n=== idempotent ensure ===");
|
|
50
|
+
const secondCreate = ensureSliceBranch(base, "M001", "S01");
|
|
51
|
+
assertEq(secondCreate, false, "branch not recreated on second ensure");
|
|
52
|
+
assertEq(getCurrentBranch(base), "gsd/M001/S01", "still on slice branch");
|
|
53
|
+
|
|
54
|
+
console.log("\n=== getActiveSliceBranch ===");
|
|
55
|
+
assertEq(getActiveSliceBranch(base), "gsd/M001/S01", "getActiveSliceBranch returns current slice branch");
|
|
56
|
+
|
|
57
|
+
console.log("\n=== state surfaces active branch ===");
|
|
58
|
+
const state = await deriveState(base);
|
|
59
|
+
assertEq(state.activeBranch, "gsd/M001/S01", "state exposes active branch");
|
|
60
|
+
|
|
61
|
+
console.log("\n=== workspace index surfaces branch ===");
|
|
62
|
+
const index = await indexWorkspace(base);
|
|
63
|
+
const slice = index.milestones[0]?.slices[0];
|
|
64
|
+
assertEq(slice?.branch, "gsd/M001/S01", "workspace index exposes branch");
|
|
65
|
+
|
|
66
|
+
console.log("\n=== autoCommitCurrentBranch ===");
|
|
67
|
+
// Clean — should return null
|
|
68
|
+
const cleanResult = autoCommitCurrentBranch(base, "execute-task", "M001/S01/T01");
|
|
69
|
+
assertEq(cleanResult, null, "returns null for clean repo");
|
|
70
|
+
|
|
71
|
+
// Make dirty
|
|
72
|
+
writeFileSync(join(base, "dirty.txt"), "uncommitted\n", "utf-8");
|
|
73
|
+
const dirtyResult = autoCommitCurrentBranch(base, "execute-task", "M001/S01/T01");
|
|
74
|
+
assertTrue(dirtyResult !== null, "returns commit message for dirty repo");
|
|
75
|
+
assertTrue(dirtyResult!.includes("M001/S01/T01"), "commit message includes unit id");
|
|
76
|
+
assertEq(run("git status --short", base), "", "repo is clean after auto-commit");
|
|
77
|
+
|
|
78
|
+
console.log("\n=== switchToMain ===");
|
|
79
|
+
switchToMain(base);
|
|
80
|
+
assertEq(getCurrentBranch(base), "main", "switched back to main");
|
|
81
|
+
assertEq(getActiveSliceBranch(base), null, "getActiveSliceBranch returns null on main");
|
|
82
|
+
|
|
83
|
+
console.log("\n=== mergeSliceToMain ===");
|
|
84
|
+
// Switch back to slice, make a change, switch to main, merge
|
|
85
|
+
ensureSliceBranch(base, "M001", "S01");
|
|
86
|
+
writeFileSync(join(base, "README.md"), "hello from slice\n", "utf-8");
|
|
87
|
+
run("git add README.md", base);
|
|
88
|
+
run('git commit -m "feat: slice change"', base);
|
|
89
|
+
switchToMain(base);
|
|
90
|
+
|
|
91
|
+
const merge = mergeSliceToMain(base, "M001", "S01", "Slice One");
|
|
92
|
+
assertEq(merge.branch, "gsd/M001/S01", "merge reports branch");
|
|
93
|
+
assertEq(getCurrentBranch(base), "main", "still on main after merge");
|
|
94
|
+
assertTrue(readFileSync(join(base, "README.md"), "utf-8").includes("slice"), "main got squashed content");
|
|
95
|
+
assertTrue(merge.deletedBranch, "branch was deleted");
|
|
96
|
+
|
|
97
|
+
// Verify branch is actually gone
|
|
98
|
+
const branches = run("git branch", base);
|
|
99
|
+
assertTrue(!branches.includes("gsd/M001/S01"), "slice branch no longer exists");
|
|
100
|
+
|
|
101
|
+
console.log("\n=== switchToMain auto-commits dirty files ===");
|
|
102
|
+
// Set up S02
|
|
103
|
+
mkdirSync(join(base, ".gsd", "milestones", "M001", "slices", "S02", "tasks"), { recursive: true });
|
|
104
|
+
writeFileSync(join(base, ".gsd", "milestones", "M001", "M001-ROADMAP.md"), [
|
|
105
|
+
"# M001: Demo", "", "## Slices",
|
|
106
|
+
"- [x] **S01: Slice One** `risk:low` `depends:[]`", " > Done",
|
|
107
|
+
"- [ ] **S02: Slice Two** `risk:low` `depends:[]`", " > Demo 2",
|
|
108
|
+
].join("\n") + "\n", "utf-8");
|
|
109
|
+
run("git add .", base);
|
|
110
|
+
run('git commit -m "chore: add S02"', base);
|
|
111
|
+
|
|
112
|
+
ensureSliceBranch(base, "M001", "S02");
|
|
113
|
+
writeFileSync(join(base, "feature.txt"), "new feature\n", "utf-8");
|
|
114
|
+
// Don't commit — switchToMain should auto-commit
|
|
115
|
+
switchToMain(base);
|
|
116
|
+
assertEq(getCurrentBranch(base), "main", "switched to main despite dirty files");
|
|
117
|
+
|
|
118
|
+
// Verify the commit happened on the slice branch
|
|
119
|
+
ensureSliceBranch(base, "M001", "S02");
|
|
120
|
+
assertTrue(readFileSync(join(base, "feature.txt"), "utf-8").includes("new feature"), "dirty file was committed on slice branch");
|
|
121
|
+
switchToMain(base);
|
|
122
|
+
|
|
123
|
+
// Now merge S02
|
|
124
|
+
const mergeS02 = mergeSliceToMain(base, "M001", "S02", "Slice Two");
|
|
125
|
+
assertTrue(readFileSync(join(base, "feature.txt"), "utf-8").includes("new feature"), "main got feature from auto-committed branch");
|
|
126
|
+
assertEq(mergeS02.deletedBranch, true, "S02 branch deleted");
|
|
127
|
+
|
|
128
|
+
console.log("\n=== getSliceBranchName ===");
|
|
129
|
+
assertEq(getSliceBranchName("M001", "S01"), "gsd/M001/S01", "branch name format correct");
|
|
130
|
+
assertEq(getSliceBranchName("M001", "S01", null), "gsd/M001/S01", "null worktree = plain branch");
|
|
131
|
+
assertEq(getSliceBranchName("M001", "S01", "my-wt"), "gsd/my-wt/M001/S01", "worktree-namespaced branch");
|
|
132
|
+
|
|
133
|
+
console.log("\n=== parseSliceBranch ===");
|
|
134
|
+
const plain = parseSliceBranch("gsd/M001/S01");
|
|
135
|
+
assertTrue(plain !== null, "parses plain branch");
|
|
136
|
+
assertEq(plain!.worktreeName, null, "plain branch has no worktree name");
|
|
137
|
+
assertEq(plain!.milestoneId, "M001", "plain branch milestone");
|
|
138
|
+
assertEq(plain!.sliceId, "S01", "plain branch slice");
|
|
139
|
+
|
|
140
|
+
const namespaced = parseSliceBranch("gsd/feature-auth/M001/S01");
|
|
141
|
+
assertTrue(namespaced !== null, "parses worktree-namespaced branch");
|
|
142
|
+
assertEq(namespaced!.worktreeName, "feature-auth", "worktree name extracted");
|
|
143
|
+
assertEq(namespaced!.milestoneId, "M001", "namespaced branch milestone");
|
|
144
|
+
assertEq(namespaced!.sliceId, "S01", "namespaced branch slice");
|
|
145
|
+
|
|
146
|
+
const invalid = parseSliceBranch("main");
|
|
147
|
+
assertEq(invalid, null, "non-slice branch returns null");
|
|
148
|
+
|
|
149
|
+
const worktreeBranch = parseSliceBranch("worktree/foo");
|
|
150
|
+
assertEq(worktreeBranch, null, "worktree/ prefix is not a slice branch");
|
|
151
|
+
|
|
152
|
+
console.log("\n=== SLICE_BRANCH_RE ===");
|
|
153
|
+
assertTrue(SLICE_BRANCH_RE.test("gsd/M001/S01"), "regex matches plain branch");
|
|
154
|
+
assertTrue(SLICE_BRANCH_RE.test("gsd/my-wt/M001/S01"), "regex matches worktree branch");
|
|
155
|
+
assertTrue(!SLICE_BRANCH_RE.test("main"), "regex rejects main");
|
|
156
|
+
assertTrue(!SLICE_BRANCH_RE.test("gsd/"), "regex rejects bare gsd/");
|
|
157
|
+
assertTrue(!SLICE_BRANCH_RE.test("worktree/foo"), "regex rejects worktree/foo");
|
|
158
|
+
|
|
159
|
+
console.log("\n=== detectWorktreeName ===");
|
|
160
|
+
assertEq(detectWorktreeName("/projects/myapp"), null, "no worktree in plain path");
|
|
161
|
+
assertEq(detectWorktreeName("/projects/myapp/.gsd/worktrees/feature-auth"), "feature-auth", "detects worktree name");
|
|
162
|
+
assertEq(detectWorktreeName("/projects/myapp/.gsd/worktrees/my-wt/subdir"), "my-wt", "detects worktree with subdir");
|
|
163
|
+
|
|
164
|
+
// ── Regression: slice branch from non-main working branch ───────────
|
|
165
|
+
// Reproduces the bug where planning artifacts committed to a working
|
|
166
|
+
// branch (e.g. "developer") are lost when the slice branch is created
|
|
167
|
+
// from "main" which doesn't have them.
|
|
168
|
+
console.log("\n=== ensureSliceBranch from non-main working branch ===");
|
|
169
|
+
const base2 = mkdtempSync(join(tmpdir(), "gsd-branch-base-test-"));
|
|
170
|
+
run("git init -b main", base2);
|
|
171
|
+
run('git config user.name "Pi Test"', base2);
|
|
172
|
+
run('git config user.email "pi@example.com"', base2);
|
|
173
|
+
writeFileSync(join(base2, "README.md"), "hello\n", "utf-8");
|
|
174
|
+
run("git add .", base2);
|
|
175
|
+
run('git commit -m "chore: init"', base2);
|
|
176
|
+
|
|
177
|
+
// Create a "developer" branch with planning artifacts (like the real scenario)
|
|
178
|
+
run("git checkout -b developer", base2);
|
|
179
|
+
mkdirSync(join(base2, ".gsd", "milestones", "M001", "slices", "S01", "tasks"), { recursive: true });
|
|
180
|
+
writeFileSync(join(base2, ".gsd", "milestones", "M001", "M001-CONTEXT.md"), "# M001 Context\nGoal: fix eslint\n", "utf-8");
|
|
181
|
+
writeFileSync(join(base2, ".gsd", "milestones", "M001", "M001-ROADMAP.md"), [
|
|
182
|
+
"# M001: ESLint Cleanup", "", "## Slices",
|
|
183
|
+
"- [ ] **S01: Config Fix** `risk:low` `depends:[]`", " > Fix config",
|
|
184
|
+
].join("\n") + "\n", "utf-8");
|
|
185
|
+
run("git add .", base2);
|
|
186
|
+
run('git commit -m "docs(M001): context and roadmap"', base2);
|
|
187
|
+
|
|
188
|
+
// Verify main does NOT have the artifacts
|
|
189
|
+
const mainRoadmap = run("git show main:.gsd/milestones/M001/M001-ROADMAP.md 2>&1 || echo MISSING", base2);
|
|
190
|
+
assertTrue(mainRoadmap.includes("MISSING") || mainRoadmap.includes("does not exist"), "main branch lacks roadmap");
|
|
191
|
+
|
|
192
|
+
// Now create slice branch from developer — should inherit artifacts
|
|
193
|
+
assertEq(getCurrentBranch(base2), "developer", "on developer branch before ensure");
|
|
194
|
+
const created3 = ensureSliceBranch(base2, "M001", "S01");
|
|
195
|
+
assertTrue(created3, "slice branch created from developer");
|
|
196
|
+
assertEq(getCurrentBranch(base2), "gsd/M001/S01", "switched to slice branch");
|
|
197
|
+
|
|
198
|
+
// The critical assertion: planning artifacts must exist on the slice branch
|
|
199
|
+
assertTrue(existsSync(join(base2, ".gsd", "milestones", "M001", "M001-ROADMAP.md")), "roadmap exists on slice branch");
|
|
200
|
+
assertTrue(existsSync(join(base2, ".gsd", "milestones", "M001", "M001-CONTEXT.md")), "context exists on slice branch");
|
|
201
|
+
|
|
202
|
+
// Verify deriveState sees the correct phase (not pre-planning)
|
|
203
|
+
const state2 = await deriveState(base2);
|
|
204
|
+
assertEq(state2.phase, "planning", "deriveState sees planning phase on slice branch");
|
|
205
|
+
assertTrue(state2.activeSlice !== null, "active slice found");
|
|
206
|
+
assertEq(state2.activeSlice!.id, "S01", "active slice is S01");
|
|
207
|
+
|
|
208
|
+
rmSync(base2, { recursive: true, force: true });
|
|
209
|
+
|
|
210
|
+
// ── Slice branch from another slice branch falls back to main ───────
|
|
211
|
+
console.log("\n=== ensureSliceBranch from slice branch falls back to main ===");
|
|
212
|
+
const base3 = mkdtempSync(join(tmpdir(), "gsd-branch-chain-test-"));
|
|
213
|
+
run("git init -b main", base3);
|
|
214
|
+
run('git config user.name "Pi Test"', base3);
|
|
215
|
+
run('git config user.email "pi@example.com"', base3);
|
|
216
|
+
mkdirSync(join(base3, ".gsd", "milestones", "M001", "slices", "S01", "tasks"), { recursive: true });
|
|
217
|
+
mkdirSync(join(base3, ".gsd", "milestones", "M001", "slices", "S02", "tasks"), { recursive: true });
|
|
218
|
+
writeFileSync(join(base3, "README.md"), "hello\n", "utf-8");
|
|
219
|
+
writeFileSync(join(base3, ".gsd", "milestones", "M001", "M001-ROADMAP.md"), [
|
|
220
|
+
"# M001: Demo", "", "## Slices",
|
|
221
|
+
"- [ ] **S01: First** `risk:low` `depends:[]`", " > first",
|
|
222
|
+
"- [ ] **S02: Second** `risk:low` `depends:[]`", " > second",
|
|
223
|
+
].join("\n") + "\n", "utf-8");
|
|
224
|
+
run("git add .", base3);
|
|
225
|
+
run('git commit -m "chore: init"', base3);
|
|
226
|
+
|
|
227
|
+
ensureSliceBranch(base3, "M001", "S01");
|
|
228
|
+
assertEq(getCurrentBranch(base3), "gsd/M001/S01", "on S01 slice branch");
|
|
229
|
+
|
|
230
|
+
// Creating S02 while on S01 should NOT chain from S01 — should use main
|
|
231
|
+
const created4 = ensureSliceBranch(base3, "M001", "S02");
|
|
232
|
+
assertTrue(created4, "S02 branch created");
|
|
233
|
+
assertEq(getCurrentBranch(base3), "gsd/M001/S02", "switched to S02");
|
|
234
|
+
|
|
235
|
+
// S02 should be based on main, not on gsd/M001/S01
|
|
236
|
+
const s02Base = run("git merge-base main gsd/M001/S02", base3);
|
|
237
|
+
const mainHead = run("git rev-parse main", base3);
|
|
238
|
+
assertEq(s02Base, mainHead, "S02 is based on main, not on S01 slice branch");
|
|
239
|
+
|
|
240
|
+
rmSync(base3, { recursive: true, force: true });
|
|
241
|
+
|
|
242
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
243
|
+
// Integration branch — facade-level tests
|
|
244
|
+
//
|
|
245
|
+
// These exercise the same codepath auto.ts uses:
|
|
246
|
+
// captureIntegrationBranch() → setActiveMilestoneId() → getMainBranch()
|
|
247
|
+
// → switchToMain() → mergeSliceToMain()
|
|
248
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
249
|
+
|
|
250
|
+
// ── captureIntegrationBranch on a feature branch ──────────────────────
|
|
251
|
+
|
|
252
|
+
console.log("\n=== captureIntegrationBranch: records current branch ===");
|
|
253
|
+
|
|
254
|
+
{
|
|
255
|
+
const repo = mkdtempSync(join(tmpdir(), "gsd-integ-facade-"));
|
|
256
|
+
run("git init -b main", repo);
|
|
257
|
+
run("git config user.name 'Pi Test'", repo);
|
|
258
|
+
run("git config user.email 'pi@example.com'", repo);
|
|
259
|
+
writeFileSync(join(repo, "README.md"), "init\n");
|
|
260
|
+
run("git add -A && git commit -m init", repo);
|
|
261
|
+
|
|
262
|
+
run("git checkout -b f-123-thing", repo);
|
|
263
|
+
assertEq(getCurrentBranch(repo), "f-123-thing", "on feature branch");
|
|
264
|
+
|
|
265
|
+
captureIntegrationBranch(repo, "M001");
|
|
266
|
+
assertEq(readIntegrationBranch(repo, "M001"), "f-123-thing",
|
|
267
|
+
"captureIntegrationBranch records the current branch");
|
|
268
|
+
|
|
269
|
+
// Verify it was committed (not just written to disk)
|
|
270
|
+
const logOut = run("git log --oneline -1", repo);
|
|
271
|
+
assertTrue(logOut.includes("integration branch"), "metadata committed to git");
|
|
272
|
+
|
|
273
|
+
rmSync(repo, { recursive: true, force: true });
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// ── captureIntegrationBranch is idempotent on same lineage ──────────
|
|
277
|
+
|
|
278
|
+
console.log("\n=== captureIntegrationBranch: idempotent ===");
|
|
279
|
+
|
|
280
|
+
{
|
|
281
|
+
const repo = mkdtempSync(join(tmpdir(), "gsd-integ-idem-"));
|
|
282
|
+
run("git init -b main", repo);
|
|
283
|
+
run("git config user.name 'Pi Test'", repo);
|
|
284
|
+
run("git config user.email 'pi@example.com'", repo);
|
|
285
|
+
writeFileSync(join(repo, "README.md"), "init\n");
|
|
286
|
+
run("git add -A && git commit -m init", repo);
|
|
287
|
+
run("git checkout -b f-first", repo);
|
|
288
|
+
|
|
289
|
+
captureIntegrationBranch(repo, "M001");
|
|
290
|
+
setActiveMilestoneId(repo, "M001");
|
|
291
|
+
assertEq(readIntegrationBranch(repo, "M001"), "f-first",
|
|
292
|
+
"first capture records f-first");
|
|
293
|
+
|
|
294
|
+
// Capture again on the same branch (simulates restart/resume) — should NOT overwrite
|
|
295
|
+
captureIntegrationBranch(repo, "M001");
|
|
296
|
+
assertEq(readIntegrationBranch(repo, "M001"), "f-first",
|
|
297
|
+
"second capture on same branch does not overwrite");
|
|
298
|
+
|
|
299
|
+
// After creating a slice branch (which inherits the metadata commit),
|
|
300
|
+
// capture should still be idempotent
|
|
301
|
+
ensureSliceBranch(repo, "M001", "S01");
|
|
302
|
+
// Now on gsd/M001/S01 — capture should be no-op (slice branch rejected)
|
|
303
|
+
captureIntegrationBranch(repo, "M001");
|
|
304
|
+
switchToMain(repo);
|
|
305
|
+
assertEq(readIntegrationBranch(repo, "M001"), "f-first",
|
|
306
|
+
"capture from slice branch is no-op, original preserved");
|
|
307
|
+
assertEq(getCurrentBranch(repo), "f-first",
|
|
308
|
+
"switchToMain returns to feature branch, confirming integration branch works");
|
|
309
|
+
|
|
310
|
+
rmSync(repo, { recursive: true, force: true });
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// ── captureIntegrationBranch skips slice branches ─────────────────────
|
|
314
|
+
|
|
315
|
+
console.log("\n=== captureIntegrationBranch: skips slice branches ===");
|
|
316
|
+
|
|
317
|
+
{
|
|
318
|
+
const repo = mkdtempSync(join(tmpdir(), "gsd-integ-skip-"));
|
|
319
|
+
run("git init -b main", repo);
|
|
320
|
+
run("git config user.name 'Pi Test'", repo);
|
|
321
|
+
run("git config user.email 'pi@example.com'", repo);
|
|
322
|
+
writeFileSync(join(repo, "README.md"), "init\n");
|
|
323
|
+
run("git add -A && git commit -m init", repo);
|
|
324
|
+
|
|
325
|
+
run("git checkout -b gsd/M001/S01", repo);
|
|
326
|
+
captureIntegrationBranch(repo, "M001");
|
|
327
|
+
|
|
328
|
+
assertEq(readIntegrationBranch(repo, "M001"), null,
|
|
329
|
+
"capture from slice branch is a no-op");
|
|
330
|
+
|
|
331
|
+
rmSync(repo, { recursive: true, force: true });
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// ── setActiveMilestoneId makes getMainBranch return integration branch ─
|
|
335
|
+
|
|
336
|
+
console.log("\n=== setActiveMilestoneId + getMainBranch ===");
|
|
337
|
+
|
|
338
|
+
{
|
|
339
|
+
const repo = mkdtempSync(join(tmpdir(), "gsd-integ-main-"));
|
|
340
|
+
run("git init -b main", repo);
|
|
341
|
+
run("git config user.name 'Pi Test'", repo);
|
|
342
|
+
run("git config user.email 'pi@example.com'", repo);
|
|
343
|
+
writeFileSync(join(repo, "README.md"), "init\n");
|
|
344
|
+
run("git add -A && git commit -m init", repo);
|
|
345
|
+
|
|
346
|
+
run("git checkout -b my-feature", repo);
|
|
347
|
+
captureIntegrationBranch(repo, "M001");
|
|
348
|
+
|
|
349
|
+
// Without milestone set, getMainBranch returns "main"
|
|
350
|
+
setActiveMilestoneId(repo, null);
|
|
351
|
+
assertEq(getMainBranch(repo), "main",
|
|
352
|
+
"getMainBranch returns main without milestone set");
|
|
353
|
+
|
|
354
|
+
// With milestone set, getMainBranch returns feature branch
|
|
355
|
+
setActiveMilestoneId(repo, "M001");
|
|
356
|
+
assertEq(getMainBranch(repo), "my-feature",
|
|
357
|
+
"getMainBranch returns integration branch with milestone set");
|
|
358
|
+
|
|
359
|
+
rmSync(repo, { recursive: true, force: true });
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
// ── Full multi-slice lifecycle on a feature branch ────────────────────
|
|
363
|
+
//
|
|
364
|
+
// Simulates what auto.ts does: start on feature branch, capture it,
|
|
365
|
+
// create S01, work, merge S01 back to feature branch, then S02 branches
|
|
366
|
+
// from feature branch (not main), works, merges to feature branch.
|
|
367
|
+
// Main stays untouched throughout.
|
|
368
|
+
|
|
369
|
+
console.log("\n=== Multi-slice lifecycle on feature branch ===");
|
|
370
|
+
|
|
371
|
+
{
|
|
372
|
+
const repo = mkdtempSync(join(tmpdir(), "gsd-integ-multi-"));
|
|
373
|
+
run("git init -b main", repo);
|
|
374
|
+
run("git config user.name 'Pi Test'", repo);
|
|
375
|
+
run("git config user.email 'pi@example.com'", repo);
|
|
376
|
+
writeFileSync(join(repo, "README.md"), "base\n");
|
|
377
|
+
run("git add -A && git commit -m init", repo);
|
|
378
|
+
|
|
379
|
+
// User creates feature branch
|
|
380
|
+
run("git checkout -b feature/big-change", repo);
|
|
381
|
+
writeFileSync(join(repo, "setup.txt"), "feature setup\n");
|
|
382
|
+
run('git add -A && git commit -m "feat: initial setup"', repo);
|
|
383
|
+
|
|
384
|
+
// auto.ts startup: capture + set milestone
|
|
385
|
+
captureIntegrationBranch(repo, "M001");
|
|
386
|
+
setActiveMilestoneId(repo, "M001");
|
|
387
|
+
|
|
388
|
+
assertEq(getMainBranch(repo), "feature/big-change",
|
|
389
|
+
"multi: getMainBranch returns feature branch");
|
|
390
|
+
|
|
391
|
+
// ── S01 lifecycle ──────────────────────────────────────────────────
|
|
392
|
+
ensureSliceBranch(repo, "M001", "S01");
|
|
393
|
+
assertEq(getCurrentBranch(repo), "gsd/M001/S01", "multi: on S01");
|
|
394
|
+
|
|
395
|
+
// Verify S01 has feature branch content
|
|
396
|
+
assertTrue(existsSync(join(repo, "setup.txt")),
|
|
397
|
+
"multi: S01 inherited feature branch content");
|
|
398
|
+
|
|
399
|
+
writeFileSync(join(repo, "s01-work.txt"), "s01 output\n");
|
|
400
|
+
run('git add -A && git commit -m "feat(S01): work"', repo);
|
|
401
|
+
|
|
402
|
+
switchToMain(repo);
|
|
403
|
+
assertEq(getCurrentBranch(repo), "feature/big-change",
|
|
404
|
+
"multi: switchToMain goes to feature branch");
|
|
405
|
+
|
|
406
|
+
const s01merge = mergeSliceToMain(repo, "M001", "S01", "First slice");
|
|
407
|
+
assertEq(getCurrentBranch(repo), "feature/big-change",
|
|
408
|
+
"multi: after S01 merge, on feature branch");
|
|
409
|
+
assertTrue(existsSync(join(repo, "s01-work.txt")),
|
|
410
|
+
"multi: S01 work merged to feature branch");
|
|
411
|
+
assertTrue(s01merge.deletedBranch, "multi: S01 branch deleted");
|
|
412
|
+
|
|
413
|
+
// Main should NOT have S01 work
|
|
414
|
+
run("git stash", repo); // stash any .gsd changes
|
|
415
|
+
run("git checkout main", repo);
|
|
416
|
+
assertTrue(!existsSync(join(repo, "s01-work.txt")),
|
|
417
|
+
"multi: main does NOT have S01 work");
|
|
418
|
+
run("git checkout feature/big-change", repo);
|
|
419
|
+
run("git stash pop || true", repo);
|
|
420
|
+
|
|
421
|
+
// ── S02 lifecycle ──────────────────────────────────────────────────
|
|
422
|
+
// S02 should branch from feature/big-change which now has S01's work
|
|
423
|
+
ensureSliceBranch(repo, "M001", "S02");
|
|
424
|
+
assertEq(getCurrentBranch(repo), "gsd/M001/S02", "multi: on S02");
|
|
425
|
+
|
|
426
|
+
// S02 should have S01's merged output (branched from feature branch)
|
|
427
|
+
assertTrue(existsSync(join(repo, "s01-work.txt")),
|
|
428
|
+
"multi: S02 has S01 output (inherited via feature branch)");
|
|
429
|
+
|
|
430
|
+
writeFileSync(join(repo, "s02-work.txt"), "s02 output\n");
|
|
431
|
+
run('git add -A && git commit -m "feat(S02): work"', repo);
|
|
432
|
+
|
|
433
|
+
switchToMain(repo);
|
|
434
|
+
assertEq(getCurrentBranch(repo), "feature/big-change",
|
|
435
|
+
"multi: switchToMain goes to feature branch after S02");
|
|
436
|
+
|
|
437
|
+
const s02merge = mergeSliceToMain(repo, "M001", "S02", "Second slice");
|
|
438
|
+
assertEq(getCurrentBranch(repo), "feature/big-change",
|
|
439
|
+
"multi: after S02 merge, on feature branch");
|
|
440
|
+
assertTrue(existsSync(join(repo, "s02-work.txt")),
|
|
441
|
+
"multi: S02 work merged to feature branch");
|
|
442
|
+
assertTrue(existsSync(join(repo, "s01-work.txt")),
|
|
443
|
+
"multi: S01 work still on feature branch after S02 merge");
|
|
444
|
+
assertTrue(s02merge.deletedBranch, "multi: S02 branch deleted");
|
|
445
|
+
|
|
446
|
+
// Final check: main still untouched
|
|
447
|
+
run("git stash", repo);
|
|
448
|
+
run("git checkout main", repo);
|
|
449
|
+
assertTrue(!existsSync(join(repo, "s01-work.txt")),
|
|
450
|
+
"multi: main still lacks S01 work at end");
|
|
451
|
+
assertTrue(!existsSync(join(repo, "s02-work.txt")),
|
|
452
|
+
"multi: main still lacks S02 work at end");
|
|
453
|
+
assertEq(readFileSync(join(repo, "README.md"), "utf-8").trim(), "base",
|
|
454
|
+
"multi: main README unchanged");
|
|
455
|
+
|
|
456
|
+
rmSync(repo, { recursive: true, force: true });
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
// ── Resume scenario: milestone ID re-set after restart ────────────────
|
|
460
|
+
//
|
|
461
|
+
// Simulates crash + restart: the cached GitServiceImpl is lost, but the
|
|
462
|
+
// metadata file persists on disk. Re-calling setActiveMilestoneId should
|
|
463
|
+
// restore integration branch resolution.
|
|
464
|
+
|
|
465
|
+
console.log("\n=== Resume: milestone ID re-set restores integration branch ===");
|
|
466
|
+
|
|
467
|
+
{
|
|
468
|
+
const repo = mkdtempSync(join(tmpdir(), "gsd-integ-resume-"));
|
|
469
|
+
run("git init -b main", repo);
|
|
470
|
+
run("git config user.name 'Pi Test'", repo);
|
|
471
|
+
run("git config user.email 'pi@example.com'", repo);
|
|
472
|
+
writeFileSync(join(repo, "README.md"), "init\n");
|
|
473
|
+
run("git add -A && git commit -m init", repo);
|
|
474
|
+
|
|
475
|
+
run("git checkout -b my-feature", repo);
|
|
476
|
+
captureIntegrationBranch(repo, "M001");
|
|
477
|
+
setActiveMilestoneId(repo, "M001");
|
|
478
|
+
|
|
479
|
+
// Create a slice and do some work
|
|
480
|
+
ensureSliceBranch(repo, "M001", "S01");
|
|
481
|
+
writeFileSync(join(repo, "work.txt"), "wip\n");
|
|
482
|
+
run('git add -A && git commit -m "wip"', repo);
|
|
483
|
+
|
|
484
|
+
// Simulate "restart" — clear milestone ID (fresh service instance)
|
|
485
|
+
setActiveMilestoneId(repo, null);
|
|
486
|
+
assertEq(getMainBranch(repo), "main",
|
|
487
|
+
"resume: getMainBranch returns main when milestone cleared");
|
|
488
|
+
|
|
489
|
+
// Re-set milestone ID (what auto.ts does on resume)
|
|
490
|
+
setActiveMilestoneId(repo, "M001");
|
|
491
|
+
assertEq(getMainBranch(repo), "my-feature",
|
|
492
|
+
"resume: getMainBranch returns feature branch after re-set");
|
|
493
|
+
|
|
494
|
+
// Full lifecycle still works after resume
|
|
495
|
+
switchToMain(repo);
|
|
496
|
+
assertEq(getCurrentBranch(repo), "my-feature",
|
|
497
|
+
"resume: switchToMain goes to feature branch after re-set");
|
|
498
|
+
|
|
499
|
+
const result = mergeSliceToMain(repo, "M001", "S01", "Resume slice");
|
|
500
|
+
assertEq(getCurrentBranch(repo), "my-feature",
|
|
501
|
+
"resume: merge lands on feature branch after re-set");
|
|
502
|
+
assertTrue(existsSync(join(repo, "work.txt")),
|
|
503
|
+
"resume: merged work exists on feature branch");
|
|
504
|
+
|
|
505
|
+
rmSync(repo, { recursive: true, force: true });
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
// ── Backward compat: no metadata file, plain main workflow ────────────
|
|
509
|
+
//
|
|
510
|
+
// Simulates existing projects that were created before this feature.
|
|
511
|
+
// No metadata file exists, milestone ID is set — getMainBranch should
|
|
512
|
+
// still return "main" and the entire slice lifecycle works unchanged.
|
|
513
|
+
|
|
514
|
+
console.log("\n=== Backward compat: no metadata, main workflow ===");
|
|
515
|
+
|
|
516
|
+
{
|
|
517
|
+
const repo = mkdtempSync(join(tmpdir(), "gsd-integ-compat-"));
|
|
518
|
+
run("git init -b main", repo);
|
|
519
|
+
run("git config user.name 'Pi Test'", repo);
|
|
520
|
+
run("git config user.email 'pi@example.com'", repo);
|
|
521
|
+
writeFileSync(join(repo, "README.md"), "init\n");
|
|
522
|
+
run("git add -A && git commit -m init", repo);
|
|
523
|
+
|
|
524
|
+
// Set milestone but DON'T capture integration branch (simulates old project)
|
|
525
|
+
setActiveMilestoneId(repo, "M001");
|
|
526
|
+
|
|
527
|
+
assertEq(getMainBranch(repo), "main",
|
|
528
|
+
"compat: getMainBranch returns main without metadata");
|
|
529
|
+
|
|
530
|
+
// Full lifecycle on main still works
|
|
531
|
+
ensureSliceBranch(repo, "M001", "S01");
|
|
532
|
+
writeFileSync(join(repo, "feature.txt"), "new\n");
|
|
533
|
+
run('git add -A && git commit -m "feat: work"', repo);
|
|
534
|
+
|
|
535
|
+
switchToMain(repo);
|
|
536
|
+
assertEq(getCurrentBranch(repo), "main",
|
|
537
|
+
"compat: switchToMain goes to main");
|
|
538
|
+
|
|
539
|
+
const result = mergeSliceToMain(repo, "M001", "S01", "Compat slice");
|
|
540
|
+
assertEq(getCurrentBranch(repo), "main",
|
|
541
|
+
"compat: merge lands on main");
|
|
542
|
+
assertTrue(existsSync(join(repo, "feature.txt")),
|
|
543
|
+
"compat: merged work exists on main");
|
|
544
|
+
assertTrue(result.deletedBranch, "compat: branch deleted");
|
|
545
|
+
|
|
546
|
+
rmSync(repo, { recursive: true, force: true });
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
// ── ensureSliceBranch from another slice with integration branch ──────
|
|
550
|
+
//
|
|
551
|
+
// When on gsd/M001/S01 and creating S02, the code falls back to
|
|
552
|
+
// getMainBranch() (not the current slice). With integration branch set,
|
|
553
|
+
// S02 should branch from the feature branch.
|
|
554
|
+
|
|
555
|
+
console.log("\n=== ensureSliceBranch: S02 from S01 uses integration branch as base ===");
|
|
556
|
+
|
|
557
|
+
{
|
|
558
|
+
const repo = mkdtempSync(join(tmpdir(), "gsd-integ-chain-"));
|
|
559
|
+
run("git init -b main", repo);
|
|
560
|
+
run("git config user.name 'Pi Test'", repo);
|
|
561
|
+
run("git config user.email 'pi@example.com'", repo);
|
|
562
|
+
writeFileSync(join(repo, "README.md"), "init\n");
|
|
563
|
+
run("git add -A && git commit -m init", repo);
|
|
564
|
+
|
|
565
|
+
run("git checkout -b dev-branch", repo);
|
|
566
|
+
writeFileSync(join(repo, "dev-only.txt"), "from dev\n");
|
|
567
|
+
run('git add -A && git commit -m "dev setup"', repo);
|
|
568
|
+
|
|
569
|
+
captureIntegrationBranch(repo, "M001");
|
|
570
|
+
setActiveMilestoneId(repo, "M001");
|
|
571
|
+
|
|
572
|
+
// Create S01 (from dev-branch)
|
|
573
|
+
ensureSliceBranch(repo, "M001", "S01");
|
|
574
|
+
writeFileSync(join(repo, "s01.txt"), "s01\n");
|
|
575
|
+
run('git add -A && git commit -m "s01 work"', repo);
|
|
576
|
+
|
|
577
|
+
// While on S01, create S02 — should fall back to integration branch
|
|
578
|
+
ensureSliceBranch(repo, "M001", "S02");
|
|
579
|
+
assertEq(getCurrentBranch(repo), "gsd/M001/S02", "chain: on S02");
|
|
580
|
+
|
|
581
|
+
// S02 should be based on dev-branch (the integration branch)
|
|
582
|
+
assertTrue(existsSync(join(repo, "dev-only.txt")),
|
|
583
|
+
"chain: S02 has dev-branch content");
|
|
584
|
+
assertTrue(!existsSync(join(repo, "s01.txt")),
|
|
585
|
+
"chain: S02 does NOT have S01 content (not chained from S01)");
|
|
586
|
+
|
|
587
|
+
rmSync(repo, { recursive: true, force: true });
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
rmSync(base, { recursive: true, force: true });
|
|
591
|
+
report();
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
main().catch((error) => {
|
|
595
|
+
console.error(error);
|
|
596
|
+
process.exit(1);
|
|
597
|
+
});
|