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
|
@@ -18,7 +18,7 @@ Then research what this slice needs. Narrate key findings and surprises as you g
|
|
|
18
18
|
2. **Skill Discovery ({{skillDiscoveryMode}}):**{{skillDiscoveryInstructions}}
|
|
19
19
|
3. Explore relevant code for this slice's scope. For targeted exploration, use `rg`, `find`, and reads. For broad or unfamiliar subsystems, use `scout` to map the relevant area first.
|
|
20
20
|
4. Use `resolve_library` / `get_library_docs` for unfamiliar libraries
|
|
21
|
-
5.
|
|
21
|
+
5. Use the **Research** output template from the inlined context above
|
|
22
22
|
6. Write `{{outputPath}}`
|
|
23
23
|
|
|
24
24
|
The slice directory already exists at `{{slicePath}}/`. Do NOT mkdir — just write the file.
|
|
@@ -27,11 +27,13 @@ import {
|
|
|
27
27
|
resolveSliceFile,
|
|
28
28
|
resolveTaskFile,
|
|
29
29
|
resolveGsdRootFile,
|
|
30
|
+
gsdRoot,
|
|
30
31
|
} from './paths.js';
|
|
31
32
|
import { getActiveSliceBranch } from './worktree.js';
|
|
32
33
|
import { milestoneIdSort, findMilestoneIds } from './guided-flow.js';
|
|
34
|
+
import { nativeBatchParseGsdFiles, type BatchParsedFile } from './native-parser-bridge.js';
|
|
33
35
|
|
|
34
|
-
import { join } from 'path';
|
|
36
|
+
import { join, resolve } from 'path';
|
|
35
37
|
|
|
36
38
|
// ─── Query Functions ───────────────────────────────────────────────────────
|
|
37
39
|
|
|
@@ -51,6 +53,27 @@ export function isMilestoneComplete(roadmap: Roadmap): boolean {
|
|
|
51
53
|
|
|
52
54
|
// ─── State Derivation ──────────────────────────────────────────────────────
|
|
53
55
|
|
|
56
|
+
// ── deriveState memoization ─────────────────────────────────────────────────
|
|
57
|
+
// Cache the most recent deriveState() result keyed by basePath. Within a single
|
|
58
|
+
// dispatch cycle (~100ms window), repeated calls return the cached value instead
|
|
59
|
+
// of re-reading the entire .gsd/ tree from disk.
|
|
60
|
+
|
|
61
|
+
interface StateCache {
|
|
62
|
+
basePath: string;
|
|
63
|
+
result: GSDState;
|
|
64
|
+
timestamp: number;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const CACHE_TTL_MS = 100;
|
|
68
|
+
let _stateCache: StateCache | null = null;
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Invalidate the deriveState() cache. Call this whenever planning files on disk
|
|
72
|
+
* may have changed (unit completion, merges, file writes).
|
|
73
|
+
*/
|
|
74
|
+
export function invalidateStateCache(): void {
|
|
75
|
+
_stateCache = null;
|
|
76
|
+
}
|
|
54
77
|
|
|
55
78
|
/**
|
|
56
79
|
* Returns the ID of the first incomplete milestone, or null if all are complete.
|
|
@@ -77,10 +100,94 @@ export async function getActiveMilestoneId(basePath: string): Promise<string | n
|
|
|
77
100
|
/**
|
|
78
101
|
* Reconstruct GSD state from files on disk.
|
|
79
102
|
* This is the source of truth — STATE.md is just a cache of this output.
|
|
103
|
+
*
|
|
104
|
+
* Uses native batch parsing when available: a single Rust call reads and parses
|
|
105
|
+
* every .md file under .gsd/, populating an in-memory cache that replaces all
|
|
106
|
+
* individual loadFile() calls during milestone/slice/task traversal.
|
|
107
|
+
* Falls back to sequential JS file reads when the native module is absent.
|
|
80
108
|
*/
|
|
81
109
|
export async function deriveState(basePath: string): Promise<GSDState> {
|
|
110
|
+
// Return cached result if within the TTL window for the same basePath
|
|
111
|
+
if (
|
|
112
|
+
_stateCache &&
|
|
113
|
+
_stateCache.basePath === basePath &&
|
|
114
|
+
Date.now() - _stateCache.timestamp < CACHE_TTL_MS
|
|
115
|
+
) {
|
|
116
|
+
return _stateCache.result;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const result = await _deriveStateImpl(basePath);
|
|
120
|
+
_stateCache = { basePath, result, timestamp: Date.now() };
|
|
121
|
+
return result;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
async function _deriveStateImpl(basePath: string): Promise<GSDState> {
|
|
82
125
|
const milestoneIds = findMilestoneIds(basePath);
|
|
83
|
-
|
|
126
|
+
|
|
127
|
+
// ── Batch-parse file cache ──────────────────────────────────────────────
|
|
128
|
+
// When the native Rust parser is available, read every .md file under .gsd/
|
|
129
|
+
// in one call and build an in-memory content map keyed by absolute path.
|
|
130
|
+
// This eliminates O(N) individual fs.readFile calls during traversal.
|
|
131
|
+
const fileContentCache = new Map<string, string>();
|
|
132
|
+
const gsdDir = gsdRoot(basePath);
|
|
133
|
+
|
|
134
|
+
const batchFiles = nativeBatchParseGsdFiles(gsdDir);
|
|
135
|
+
if (batchFiles) {
|
|
136
|
+
for (const f of batchFiles) {
|
|
137
|
+
// Reconstruct the full file content from parsed components so downstream
|
|
138
|
+
// parsers (parseRoadmap, parseSummary, etc.) receive the same input they
|
|
139
|
+
// expect from loadFile(). Files with frontmatter get it re-serialized;
|
|
140
|
+
// files without get just the body.
|
|
141
|
+
const absPath = resolve(gsdDir, f.path);
|
|
142
|
+
const hasMetadata = Object.keys(f.metadata).length > 0;
|
|
143
|
+
if (hasMetadata) {
|
|
144
|
+
// Re-serialize frontmatter as simple YAML key: value lines
|
|
145
|
+
const fmLines: string[] = ['---'];
|
|
146
|
+
for (const [key, value] of Object.entries(f.metadata)) {
|
|
147
|
+
if (Array.isArray(value)) {
|
|
148
|
+
if (value.length === 0) {
|
|
149
|
+
fmLines.push(`${key}: []`);
|
|
150
|
+
} else if (typeof value[0] === 'object' && value[0] !== null) {
|
|
151
|
+
fmLines.push(`${key}:`);
|
|
152
|
+
for (const obj of value) {
|
|
153
|
+
const entries = Object.entries(obj as Record<string, unknown>);
|
|
154
|
+
if (entries.length > 0) {
|
|
155
|
+
fmLines.push(` - ${entries[0][0]}: ${entries[0][1]}`);
|
|
156
|
+
for (let i = 1; i < entries.length; i++) {
|
|
157
|
+
fmLines.push(` ${entries[i][0]}: ${entries[i][1]}`);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
} else {
|
|
162
|
+
fmLines.push(`${key}:`);
|
|
163
|
+
for (const item of value) {
|
|
164
|
+
fmLines.push(` - ${item}`);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
} else {
|
|
168
|
+
fmLines.push(`${key}: ${value}`);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
fmLines.push('---');
|
|
172
|
+
fileContentCache.set(absPath, fmLines.join('\n') + '\n\n' + f.body);
|
|
173
|
+
} else {
|
|
174
|
+
fileContentCache.set(absPath, f.body);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Load file content from batch cache first, falling back to disk read.
|
|
181
|
+
* Resolves the path to absolute before cache lookup.
|
|
182
|
+
*/
|
|
183
|
+
async function cachedLoadFile(path: string): Promise<string | null> {
|
|
184
|
+
const abs = resolve(path);
|
|
185
|
+
const cached = fileContentCache.get(abs);
|
|
186
|
+
if (cached !== undefined) return cached;
|
|
187
|
+
return loadFile(path);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const requirements = parseRequirementCounts(await cachedLoadFile(resolveGsdRootFile(basePath, "REQUIREMENTS")));
|
|
84
191
|
|
|
85
192
|
if (milestoneIds.length === 0) {
|
|
86
193
|
return {
|
|
@@ -99,25 +206,31 @@ export async function deriveState(basePath: string): Promise<GSDState> {
|
|
|
99
206
|
};
|
|
100
207
|
}
|
|
101
208
|
|
|
102
|
-
//
|
|
103
|
-
//
|
|
209
|
+
// ── Single-pass milestone scan ──────────────────────────────────────────
|
|
210
|
+
// Parse each milestone's roadmap once, caching results. First pass determines
|
|
211
|
+
// completeness for dependency resolution; second pass builds the registry.
|
|
212
|
+
// With the batch cache, all file reads hit memory instead of disk.
|
|
213
|
+
|
|
214
|
+
// Phase 1: Build roadmap cache and completeness set
|
|
215
|
+
const roadmapCache = new Map<string, Roadmap>();
|
|
104
216
|
const completeMilestoneIds = new Set<string>();
|
|
217
|
+
|
|
105
218
|
for (const mid of milestoneIds) {
|
|
106
219
|
const rf = resolveMilestoneFile(basePath, mid, "ROADMAP");
|
|
107
|
-
const rc = rf ? await
|
|
220
|
+
const rc = rf ? await cachedLoadFile(rf) : null;
|
|
108
221
|
if (!rc) {
|
|
109
|
-
// No roadmap — milestone is complete if it has a summary
|
|
110
222
|
const sf = resolveMilestoneFile(basePath, mid, "SUMMARY");
|
|
111
223
|
if (sf) completeMilestoneIds.add(mid);
|
|
112
224
|
continue;
|
|
113
225
|
}
|
|
114
226
|
const rmap = parseRoadmap(rc);
|
|
227
|
+
roadmapCache.set(mid, rmap);
|
|
115
228
|
if (!isMilestoneComplete(rmap)) continue;
|
|
116
229
|
const sf = resolveMilestoneFile(basePath, mid, "SUMMARY");
|
|
117
230
|
if (sf) completeMilestoneIds.add(mid);
|
|
118
231
|
}
|
|
119
232
|
|
|
120
|
-
// Build
|
|
233
|
+
// Phase 2: Build registry using cached roadmaps (no re-parsing or re-reading)
|
|
121
234
|
const registry: MilestoneRegistryEntry[] = [];
|
|
122
235
|
let activeMilestone: ActiveRef | null = null;
|
|
123
236
|
let activeRoadmap: Roadmap | null = null;
|
|
@@ -125,13 +238,13 @@ export async function deriveState(basePath: string): Promise<GSDState> {
|
|
|
125
238
|
let activeMilestoneHasDraft = false;
|
|
126
239
|
|
|
127
240
|
for (const mid of milestoneIds) {
|
|
128
|
-
const
|
|
129
|
-
|
|
130
|
-
if (!
|
|
241
|
+
const roadmap = roadmapCache.get(mid) ?? null;
|
|
242
|
+
|
|
243
|
+
if (!roadmap) {
|
|
131
244
|
// No roadmap — check if a summary exists (completed milestone without roadmap)
|
|
132
245
|
const summaryFile = resolveMilestoneFile(basePath, mid, "SUMMARY");
|
|
133
246
|
if (summaryFile) {
|
|
134
|
-
const summaryContent = await
|
|
247
|
+
const summaryContent = await cachedLoadFile(summaryFile);
|
|
135
248
|
const summaryTitle = summaryContent
|
|
136
249
|
? (parseSummary(summaryContent).title || mid)
|
|
137
250
|
: mid;
|
|
@@ -157,7 +270,6 @@ export async function deriveState(basePath: string): Promise<GSDState> {
|
|
|
157
270
|
continue;
|
|
158
271
|
}
|
|
159
272
|
|
|
160
|
-
const roadmap = parseRoadmap(content);
|
|
161
273
|
const title = roadmap.title.replace(/^M\d+(?:-[a-z0-9]{6})?[^:]*:\s*/, '');
|
|
162
274
|
const complete = isMilestoneComplete(roadmap);
|
|
163
275
|
|
|
@@ -176,7 +288,7 @@ export async function deriveState(basePath: string): Promise<GSDState> {
|
|
|
176
288
|
} else if (!activeMilestoneFound) {
|
|
177
289
|
// Check milestone-level dependencies before promoting to active
|
|
178
290
|
const contextFile = resolveMilestoneFile(basePath, mid, "CONTEXT");
|
|
179
|
-
const contextContent = contextFile ? await
|
|
291
|
+
const contextContent = contextFile ? await cachedLoadFile(contextFile) : null;
|
|
180
292
|
const deps = parseContextDependsOn(contextContent);
|
|
181
293
|
const depsUnmet = deps.some(dep => !completeMilestoneIds.has(dep));
|
|
182
294
|
if (depsUnmet) {
|
|
@@ -190,7 +302,7 @@ export async function deriveState(basePath: string): Promise<GSDState> {
|
|
|
190
302
|
}
|
|
191
303
|
} else {
|
|
192
304
|
const contextFile2 = resolveMilestoneFile(basePath, mid, "CONTEXT");
|
|
193
|
-
const contextContent2 = contextFile2 ? await
|
|
305
|
+
const contextContent2 = contextFile2 ? await cachedLoadFile(contextFile2) : null;
|
|
194
306
|
const deps2 = parseContextDependsOn(contextContent2);
|
|
195
307
|
registry.push({ id: mid, title, status: 'pending', ...(deps2.length > 0 ? { dependsOn: deps2 } : {}) });
|
|
196
308
|
}
|
|
@@ -330,7 +442,7 @@ export async function deriveState(basePath: string): Promise<GSDState> {
|
|
|
330
442
|
|
|
331
443
|
// Check if the slice has a plan
|
|
332
444
|
const planFile = resolveSliceFile(basePath, activeMilestone.id, activeSlice.id, "PLAN");
|
|
333
|
-
const slicePlanContent = planFile ? await
|
|
445
|
+
const slicePlanContent = planFile ? await cachedLoadFile(planFile) : null;
|
|
334
446
|
|
|
335
447
|
if (!slicePlanContent) {
|
|
336
448
|
return {
|
|
@@ -392,7 +504,7 @@ export async function deriveState(basePath: string): Promise<GSDState> {
|
|
|
392
504
|
for (const ct of completedTasks) {
|
|
393
505
|
const summaryFile = resolveTaskFile(basePath, activeMilestone.id, activeSlice.id, ct.id, "SUMMARY");
|
|
394
506
|
if (!summaryFile) continue;
|
|
395
|
-
const summaryContent = await
|
|
507
|
+
const summaryContent = await cachedLoadFile(summaryFile);
|
|
396
508
|
if (!summaryContent) continue;
|
|
397
509
|
const summary = parseSummary(summaryContent);
|
|
398
510
|
if (summary.frontmatter.blocker_discovered) {
|
|
@@ -432,8 +544,8 @@ export async function deriveState(basePath: string): Promise<GSDState> {
|
|
|
432
544
|
const sDir = resolveSlicePath(basePath, activeMilestone.id, activeSlice.id);
|
|
433
545
|
const continueFile = sDir ? resolveSliceFile(basePath, activeMilestone.id, activeSlice.id, "CONTINUE") : null;
|
|
434
546
|
// Also check legacy continue.md
|
|
435
|
-
const hasInterrupted = !!(continueFile && await
|
|
436
|
-
!!(sDir && await
|
|
547
|
+
const hasInterrupted = !!(continueFile && await cachedLoadFile(continueFile)) ||
|
|
548
|
+
!!(sDir && await cachedLoadFile(join(sDir, "continue.md")));
|
|
437
549
|
|
|
438
550
|
return {
|
|
439
551
|
activeMilestone,
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# GSD State
|
|
2
2
|
|
|
3
|
-
**Active Milestone:** {{milestoneId}}
|
|
4
|
-
**Active Slice:** {{sliceId}}
|
|
5
|
-
**Active Task:** {{taskId}}
|
|
3
|
+
**Active Milestone:** {{milestoneId}}: {{milestoneTitle}}
|
|
4
|
+
**Active Slice:** {{sliceId}}: {{sliceTitle}}
|
|
5
|
+
**Active Task:** {{taskId}}: {{taskTitle}}
|
|
6
6
|
**Phase:** {{phase}}
|
|
7
7
|
**Slice Branch:** {{activeBranch}}
|
|
8
8
|
**Active Workspace:** {{activeWorkspace}}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
// Tests for saveActivityLog performance behavior:
|
|
2
|
+
// - cache next sequence per activity directory instead of rescanning every save
|
|
3
|
+
// - skip rewriting identical snapshots for the same unit
|
|
4
|
+
// - recover safely if another writer creates the cached next sequence
|
|
5
|
+
|
|
6
|
+
import { existsSync, mkdtempSync, readdirSync, rmSync, writeFileSync } from "node:fs";
|
|
7
|
+
import { tmpdir } from "node:os";
|
|
8
|
+
import { join } from "node:path";
|
|
9
|
+
|
|
10
|
+
import { saveActivityLog } from "../activity-log.ts";
|
|
11
|
+
import { createTestContext } from "./test-helpers.ts";
|
|
12
|
+
|
|
13
|
+
const { assertEq, assertTrue, report } = createTestContext();
|
|
14
|
+
|
|
15
|
+
let tmpDirs: string[] = [];
|
|
16
|
+
|
|
17
|
+
function createBaseDir(): string {
|
|
18
|
+
const dir = mkdtempSync(join(tmpdir(), "gsd-activity-save-test-"));
|
|
19
|
+
tmpDirs.push(dir);
|
|
20
|
+
return dir;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function activityDir(baseDir: string): string {
|
|
24
|
+
return join(baseDir, ".gsd", "activity");
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function listActivityFiles(baseDir: string): string[] {
|
|
28
|
+
const dir = activityDir(baseDir);
|
|
29
|
+
return existsSync(dir) ? readdirSync(dir).sort() : [];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function createCtx(entries: unknown[]) {
|
|
33
|
+
return {
|
|
34
|
+
sessionManager: {
|
|
35
|
+
getEntries: () => entries,
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function cleanup(): void {
|
|
41
|
+
for (const dir of tmpDirs) {
|
|
42
|
+
rmSync(dir, { recursive: true, force: true });
|
|
43
|
+
}
|
|
44
|
+
tmpDirs = [];
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
process.on("exit", cleanup);
|
|
48
|
+
|
|
49
|
+
async function main(): Promise<void> {
|
|
50
|
+
console.log("\n── (a) cache next sequence instead of rescanning every save");
|
|
51
|
+
{
|
|
52
|
+
const baseDir = createBaseDir();
|
|
53
|
+
saveActivityLog(createCtx([{ kind: "first", n: 1 }]) as any, baseDir, "execute-task", "M001/S01/T01");
|
|
54
|
+
|
|
55
|
+
writeFileSync(
|
|
56
|
+
join(activityDir(baseDir), "999-external-manual.jsonl"),
|
|
57
|
+
'{"external":true}\n',
|
|
58
|
+
"utf-8",
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
saveActivityLog(createCtx([{ kind: "second", n: 2 }]) as any, baseDir, "execute-task", "M001/S01/T02");
|
|
62
|
+
|
|
63
|
+
const files = listActivityFiles(baseDir);
|
|
64
|
+
assertTrue(files.includes("001-execute-task-M001-S01-T01.jsonl"), "(a) first save uses sequence 001");
|
|
65
|
+
assertTrue(files.includes("002-execute-task-M001-S01-T02.jsonl"), "(a) second save uses cached next sequence 002");
|
|
66
|
+
assertTrue(files.includes("999-external-manual.jsonl"), "(a) externally added file remains present");
|
|
67
|
+
assertTrue(!files.some(file => file.startsWith("1000-")), "(a) second save did not rescan and jump to sequence 1000");
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
console.log("\n── (b) skip rewriting identical snapshots for the same unit");
|
|
71
|
+
{
|
|
72
|
+
const baseDir = createBaseDir();
|
|
73
|
+
const ctx = createCtx([{ role: "assistant", content: "same snapshot" }]);
|
|
74
|
+
|
|
75
|
+
saveActivityLog(ctx as any, baseDir, "plan-slice", "M002/S01");
|
|
76
|
+
saveActivityLog(ctx as any, baseDir, "plan-slice", "M002/S01");
|
|
77
|
+
|
|
78
|
+
let files = listActivityFiles(baseDir);
|
|
79
|
+
assertEq(files.length, 1, "(b) identical repeated save writes only one activity file");
|
|
80
|
+
assertTrue(files[0] === "001-plan-slice-M002-S01.jsonl", "(b) the original sequence is preserved");
|
|
81
|
+
|
|
82
|
+
saveActivityLog(createCtx([{ role: "assistant", content: "changed snapshot" }]) as any, baseDir, "plan-slice", "M002/S01");
|
|
83
|
+
files = listActivityFiles(baseDir);
|
|
84
|
+
assertEq(files.length, 2, "(b) changed snapshot writes a new activity file");
|
|
85
|
+
assertTrue(files.includes("002-plan-slice-M002-S01.jsonl"), "(b) deduped save did not consume the next sequence");
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
console.log("\n── (c) recover if another writer creates the exact cached target file");
|
|
89
|
+
{
|
|
90
|
+
const baseDir = createBaseDir();
|
|
91
|
+
saveActivityLog(createCtx([{ turn: 1 }]) as any, baseDir, "execute-task", "M003/S02/T01");
|
|
92
|
+
|
|
93
|
+
writeFileSync(
|
|
94
|
+
join(activityDir(baseDir), "002-execute-task-M003-S02-T02.jsonl"),
|
|
95
|
+
'{"collision":true}\n',
|
|
96
|
+
"utf-8",
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
saveActivityLog(createCtx([{ turn: 2 }]) as any, baseDir, "execute-task", "M003/S02/T02");
|
|
100
|
+
|
|
101
|
+
const files = listActivityFiles(baseDir);
|
|
102
|
+
assertTrue(files.includes("002-execute-task-M003-S02-T02.jsonl"), "(c) exact collision file is preserved");
|
|
103
|
+
assertTrue(files.includes("003-execute-task-M003-S02-T02.jsonl"), "(c) logger rescans only on collision and advances to 003");
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
console.log("\n── (d) dedupe is tracked per unit, not just the last write in the directory");
|
|
107
|
+
{
|
|
108
|
+
const baseDir = createBaseDir();
|
|
109
|
+
const repeatedCtx = createCtx([{ role: "assistant", content: "same-for-unit-a" }]);
|
|
110
|
+
|
|
111
|
+
saveActivityLog(repeatedCtx as any, baseDir, "execute-task", "M004/S01/T01");
|
|
112
|
+
saveActivityLog(createCtx([{ role: "assistant", content: "other-unit" }]) as any, baseDir, "execute-task", "M004/S01/T02");
|
|
113
|
+
saveActivityLog(repeatedCtx as any, baseDir, "execute-task", "M004/S01/T01");
|
|
114
|
+
|
|
115
|
+
const files = listActivityFiles(baseDir);
|
|
116
|
+
assertEq(files.length, 2, "(d) interleaving another unit does not force a duplicate rewrite for unit A");
|
|
117
|
+
assertTrue(files.includes("001-execute-task-M004-S01-T01.jsonl"), "(d) original unit A snapshot is retained");
|
|
118
|
+
assertTrue(files.includes("002-execute-task-M004-S01-T02.jsonl"), "(d) unit B snapshot is retained");
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
report();
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
main().catch((error) => {
|
|
125
|
+
console.error(error);
|
|
126
|
+
process.exit(1);
|
|
127
|
+
});
|
|
@@ -3,6 +3,8 @@ import { join, dirname } from "node:path";
|
|
|
3
3
|
import { tmpdir } from "node:os";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
import { createTestContext } from './test-helpers.ts';
|
|
6
|
+
import { clearPathCache } from '../paths.ts';
|
|
7
|
+
import { invalidateStateCache } from '../state.ts';
|
|
6
8
|
|
|
7
9
|
// loadPrompt reads from ~/.gsd/agent/extensions/gsd/prompts/ (main checkout).
|
|
8
10
|
// In a worktree the file may not exist there yet, so we resolve prompts
|
|
@@ -146,7 +148,7 @@ async function main(): Promise<void> {
|
|
|
146
148
|
// ─── deriveState integration: completing-milestone dispatches correctly ─
|
|
147
149
|
console.log("\n=== deriveState completing-milestone integration ===");
|
|
148
150
|
{
|
|
149
|
-
const { deriveState, isMilestoneComplete } = await import("../state.ts");
|
|
151
|
+
const { deriveState, isMilestoneComplete, invalidateStateCache } = await import("../state.ts");
|
|
150
152
|
const { parseRoadmap } = await import("../files.ts");
|
|
151
153
|
|
|
152
154
|
const base = createFixtureBase();
|
|
@@ -179,6 +181,8 @@ async function main(): Promise<void> {
|
|
|
179
181
|
|
|
180
182
|
// Now add the summary and verify it transitions to complete
|
|
181
183
|
writeMilestoneSummary(base, "M001", "# M001 Summary\n\nDone.");
|
|
184
|
+
clearPathCache();
|
|
185
|
+
invalidateStateCache();
|
|
182
186
|
const stateAfter = await deriveState(base);
|
|
183
187
|
assertEq(stateAfter.phase, "complete", "deriveState returns complete after summary exists");
|
|
184
188
|
assertEq(stateAfter.registry[0]?.status, "complete", "registry shows complete status");
|
|
@@ -2,7 +2,7 @@ import { mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync, existsSync
|
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { tmpdir } from "node:os";
|
|
4
4
|
|
|
5
|
-
import { formatDoctorReport, runGSDDoctor, summarizeDoctorIssues, filterDoctorIssues, selectDoctorScope } from "../doctor.js";
|
|
5
|
+
import { formatDoctorReport, runGSDDoctor, summarizeDoctorIssues, filterDoctorIssues, selectDoctorScope, validateTitle } from "../doctor.js";
|
|
6
6
|
import { createTestContext } from './test-helpers.ts';
|
|
7
7
|
|
|
8
8
|
const { assertEq, assertTrue, report } = createTestContext();
|
|
@@ -471,6 +471,120 @@ Discovered an issue.
|
|
|
471
471
|
rmSync(mhBase, { recursive: true, force: true });
|
|
472
472
|
}
|
|
473
473
|
|
|
474
|
+
// ─── validateTitle: em dash and slash detection ────────────────────────
|
|
475
|
+
console.log("\n=== validateTitle: returns null for clean titles ===");
|
|
476
|
+
{
|
|
477
|
+
assertEq(validateTitle("Foundation"), null, "clean title passes");
|
|
478
|
+
assertEq(validateTitle("Build Core Systems"), null, "clean title with spaces passes");
|
|
479
|
+
assertEq(validateTitle("API v2 Integration"), null, "clean title with version passes");
|
|
480
|
+
assertEq(validateTitle(""), null, "empty title passes");
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
console.log("\n=== validateTitle: detects em dash ===");
|
|
484
|
+
{
|
|
485
|
+
const result = validateTitle("Foundation — Build Core");
|
|
486
|
+
assertTrue(result !== null, "detects em dash in title");
|
|
487
|
+
assertTrue(result!.includes("em/en dash"), "message mentions em/en dash");
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
console.log("\n=== validateTitle: detects en dash ===");
|
|
491
|
+
{
|
|
492
|
+
const result = validateTitle("Phase 1 – Phase 2");
|
|
493
|
+
assertTrue(result !== null, "detects en dash in title");
|
|
494
|
+
assertTrue(result!.includes("em/en dash"), "message mentions em/en dash for en dash");
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
console.log("\n=== validateTitle: detects forward slash ===");
|
|
498
|
+
{
|
|
499
|
+
const result = validateTitle("Client/Server");
|
|
500
|
+
assertTrue(result !== null, "detects forward slash in title");
|
|
501
|
+
assertTrue(result!.includes("forward slash"), "message mentions forward slash");
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
console.log("\n=== validateTitle: detects both em dash and slash ===");
|
|
505
|
+
{
|
|
506
|
+
const result = validateTitle("Client — Server/API");
|
|
507
|
+
assertTrue(result !== null, "detects both delimiters");
|
|
508
|
+
assertTrue(result!.includes("em/en dash"), "message mentions em/en dash");
|
|
509
|
+
assertTrue(result!.includes("forward slash"), "message mentions forward slash");
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
// ─── doctor detects delimiter_in_title for milestone ───────────────────
|
|
513
|
+
console.log("\n=== doctor detects em dash in milestone title ===");
|
|
514
|
+
{
|
|
515
|
+
const dtBase = mkdtempSync(join(tmpdir(), "gsd-doctor-dt-test-"));
|
|
516
|
+
const dtGsd = join(dtBase, ".gsd");
|
|
517
|
+
const dtMDir = join(dtGsd, "milestones", "M001");
|
|
518
|
+
const dtSDir = join(dtMDir, "slices", "S01");
|
|
519
|
+
const dtTDir = join(dtSDir, "tasks");
|
|
520
|
+
mkdirSync(dtTDir, { recursive: true });
|
|
521
|
+
|
|
522
|
+
// Roadmap with em dash in milestone title
|
|
523
|
+
writeFileSync(join(dtMDir, "M001-ROADMAP.md"), `# M001: Foundation — Build Core\n\n## Slices\n- [ ] **S01: Demo Slice** \`risk:low\` \`depends:[]\`\n > After this: demo works\n`);
|
|
524
|
+
writeFileSync(join(dtSDir, "S01-PLAN.md"), `# S01: Demo Slice\n\n**Goal:** Demo\n**Demo:** Demo\n\n## Tasks\n- [ ] **T01: Implement** \`est:10m\`\n Task.\n`);
|
|
525
|
+
writeFileSync(join(dtTDir, "T01-PLAN.md"), `# T01: Implement\n\n## Steps\n\n1. Do the thing.\n`);
|
|
526
|
+
|
|
527
|
+
const report = await runGSDDoctor(dtBase, { fix: false });
|
|
528
|
+
const dtIssues = report.issues.filter(i => i.code === "delimiter_in_title");
|
|
529
|
+
assertTrue(dtIssues.length >= 1, "detects delimiter_in_title for milestone with em dash");
|
|
530
|
+
const milestoneIssue = dtIssues.find(i => i.scope === "milestone");
|
|
531
|
+
assertTrue(milestoneIssue !== undefined, "delimiter issue has milestone scope");
|
|
532
|
+
assertEq(milestoneIssue?.severity, "warning", "delimiter issue has warning severity");
|
|
533
|
+
assertEq(milestoneIssue?.unitId, "M001", "delimiter issue unitId is M001");
|
|
534
|
+
assertTrue(milestoneIssue?.message?.includes("em/en dash") ?? false, "issue message mentions em/en dash");
|
|
535
|
+
assertEq(milestoneIssue?.fixable, false, "delimiter issue is not auto-fixable");
|
|
536
|
+
|
|
537
|
+
rmSync(dtBase, { recursive: true, force: true });
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
// ─── doctor detects delimiter_in_title for slice ────────────────────────
|
|
541
|
+
console.log("\n=== doctor detects em dash in slice title ===");
|
|
542
|
+
{
|
|
543
|
+
const dtBase = mkdtempSync(join(tmpdir(), "gsd-doctor-dt-slice-"));
|
|
544
|
+
const dtGsd = join(dtBase, ".gsd");
|
|
545
|
+
const dtMDir = join(dtGsd, "milestones", "M001");
|
|
546
|
+
const dtSDir = join(dtMDir, "slices", "S01");
|
|
547
|
+
const dtTDir = join(dtSDir, "tasks");
|
|
548
|
+
mkdirSync(dtTDir, { recursive: true });
|
|
549
|
+
|
|
550
|
+
// Roadmap with em dash in slice title (milestone title is clean)
|
|
551
|
+
writeFileSync(join(dtMDir, "M001-ROADMAP.md"), `# M001: Clean Milestone\n\n## Slices\n- [ ] **S01: Core — Foundation** \`risk:low\` \`depends:[]\`\n > After this: demo works\n`);
|
|
552
|
+
writeFileSync(join(dtSDir, "S01-PLAN.md"), `# S01: Core — Foundation\n\n**Goal:** Demo\n**Demo:** Demo\n\n## Tasks\n- [ ] **T01: Implement** \`est:10m\`\n Task.\n`);
|
|
553
|
+
writeFileSync(join(dtTDir, "T01-PLAN.md"), `# T01: Implement\n\n## Steps\n\n1. Do the thing.\n`);
|
|
554
|
+
|
|
555
|
+
const report = await runGSDDoctor(dtBase, { fix: false });
|
|
556
|
+
const dtIssues = report.issues.filter(i => i.code === "delimiter_in_title");
|
|
557
|
+
assertTrue(dtIssues.length >= 1, "detects delimiter_in_title for slice with em dash");
|
|
558
|
+
const sliceIssue = dtIssues.find(i => i.scope === "slice");
|
|
559
|
+
assertTrue(sliceIssue !== undefined, "delimiter issue has slice scope");
|
|
560
|
+
assertEq(sliceIssue?.severity, "warning", "slice delimiter issue has warning severity");
|
|
561
|
+
assertEq(sliceIssue?.unitId, "M001/S01", "slice delimiter issue unitId is M001/S01");
|
|
562
|
+
|
|
563
|
+
rmSync(dtBase, { recursive: true, force: true });
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
// ─── doctor does NOT flag clean titles ──────────────────────────────────
|
|
567
|
+
console.log("\n=== doctor does NOT flag milestone with clean title ===");
|
|
568
|
+
{
|
|
569
|
+
const dtBase = mkdtempSync(join(tmpdir(), "gsd-doctor-dt-clean-"));
|
|
570
|
+
const dtGsd = join(dtBase, ".gsd");
|
|
571
|
+
const dtMDir = join(dtGsd, "milestones", "M001");
|
|
572
|
+
const dtSDir = join(dtMDir, "slices", "S01");
|
|
573
|
+
const dtTDir = join(dtSDir, "tasks");
|
|
574
|
+
mkdirSync(dtTDir, { recursive: true });
|
|
575
|
+
|
|
576
|
+
// Roadmap with clean titles (no delimiters)
|
|
577
|
+
writeFileSync(join(dtMDir, "M001-ROADMAP.md"), `# M001: Foundation Build Core\n\n## Slices\n- [ ] **S01: Demo Slice** \`risk:low\` \`depends:[]\`\n > After this: demo works\n`);
|
|
578
|
+
writeFileSync(join(dtSDir, "S01-PLAN.md"), `# S01: Demo Slice\n\n**Goal:** Demo\n**Demo:** Demo\n\n## Tasks\n- [ ] **T01: Implement** \`est:10m\`\n Task.\n`);
|
|
579
|
+
writeFileSync(join(dtTDir, "T01-PLAN.md"), `# T01: Implement\n\n## Steps\n\n1. Do the thing.\n`);
|
|
580
|
+
|
|
581
|
+
const report = await runGSDDoctor(dtBase, { fix: false });
|
|
582
|
+
const dtIssues = report.issues.filter(i => i.code === "delimiter_in_title");
|
|
583
|
+
assertEq(dtIssues.length, 0, "no delimiter_in_title issues for clean titles");
|
|
584
|
+
|
|
585
|
+
rmSync(dtBase, { recursive: true, force: true });
|
|
586
|
+
}
|
|
587
|
+
|
|
474
588
|
report();
|
|
475
589
|
}
|
|
476
590
|
|
|
@@ -2,8 +2,8 @@ import { mkdtempSync, mkdirSync, rmSync, writeFileSync, existsSync } from "node:
|
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { tmpdir } from "node:os";
|
|
4
4
|
|
|
5
|
-
import { deriveState } from "../state.js";
|
|
6
|
-
import { resolveMilestoneFile } from "../paths.js";
|
|
5
|
+
import { deriveState, invalidateStateCache } from "../state.js";
|
|
6
|
+
import { resolveMilestoneFile, clearPathCache } from "../paths.js";
|
|
7
7
|
|
|
8
8
|
let passed = 0;
|
|
9
9
|
let failed = 0;
|
|
@@ -40,6 +40,8 @@ assert(
|
|
|
40
40
|
const contextPath = join(gsd, "milestones", "M001", "M001-CONTEXT.md");
|
|
41
41
|
writeFileSync(contextPath, "# M001: Full Context\n\nDeep discussion output.\n");
|
|
42
42
|
|
|
43
|
+
clearPathCache();
|
|
44
|
+
invalidateStateCache();
|
|
43
45
|
const state2 = await deriveState(tmpBase);
|
|
44
46
|
assert(
|
|
45
47
|
state2.phase === "pre-planning",
|
|
@@ -65,6 +67,8 @@ assert(
|
|
|
65
67
|
);
|
|
66
68
|
|
|
67
69
|
// Step 4: After cleanup, state is still pre-planning (CONTEXT.md exists)
|
|
70
|
+
clearPathCache();
|
|
71
|
+
invalidateStateCache();
|
|
68
72
|
const state3 = await deriveState(tmpBase);
|
|
69
73
|
assert(
|
|
70
74
|
state3.phase === "pre-planning",
|