gsd-pi 2.29.0-dev.953d788 → 2.29.0-dev.f08b4fe
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/README.md +24 -17
- package/dist/extension-registry.d.ts +63 -0
- package/dist/extension-registry.js +166 -0
- package/dist/headless.js +4 -0
- package/dist/loader.js +10 -1
- package/dist/resource-loader.js +11 -1
- package/dist/resources/extensions/async-jobs/extension-manifest.json +13 -0
- package/dist/resources/extensions/bg-shell/extension-manifest.json +14 -0
- package/dist/resources/extensions/bg-shell/process-manager.ts +13 -0
- package/dist/resources/extensions/browser-tools/extension-manifest.json +37 -0
- package/dist/resources/extensions/context7/extension-manifest.json +12 -0
- package/dist/resources/extensions/google-search/extension-manifest.json +12 -0
- package/dist/resources/extensions/gsd/auto-dashboard.ts +217 -65
- package/dist/resources/extensions/gsd/auto-dispatch.ts +32 -3
- package/dist/resources/extensions/gsd/auto-post-unit.ts +45 -13
- package/dist/resources/extensions/gsd/auto-prompts.ts +40 -17
- package/dist/resources/extensions/gsd/auto-recovery.ts +18 -23
- package/dist/resources/extensions/gsd/auto-start.ts +18 -32
- package/dist/resources/extensions/gsd/auto-worktree.ts +21 -182
- package/dist/resources/extensions/gsd/auto.ts +2 -24
- package/dist/resources/extensions/gsd/captures.ts +4 -10
- package/dist/resources/extensions/gsd/commands-extensions.ts +328 -0
- package/dist/resources/extensions/gsd/commands-handlers.ts +22 -2
- package/dist/resources/extensions/gsd/commands-logs.ts +13 -14
- package/dist/resources/extensions/gsd/commands-prefs-wizard.ts +44 -14
- package/dist/resources/extensions/gsd/commands-workflow-templates.ts +544 -0
- package/dist/resources/extensions/gsd/commands.ts +108 -24
- package/dist/resources/extensions/gsd/dashboard-overlay.ts +2 -1
- package/dist/resources/extensions/gsd/detection.ts +2 -1
- package/dist/resources/extensions/gsd/doctor-checks.ts +49 -1
- package/dist/resources/extensions/gsd/doctor-types.ts +3 -1
- package/dist/resources/extensions/gsd/extension-manifest.json +18 -0
- package/dist/resources/extensions/gsd/forensics.ts +2 -2
- package/dist/resources/extensions/gsd/git-service.ts +3 -2
- package/dist/resources/extensions/gsd/gitignore.ts +9 -63
- package/dist/resources/extensions/gsd/gsd-db.ts +1 -165
- package/dist/resources/extensions/gsd/guided-flow.ts +8 -5
- package/dist/resources/extensions/gsd/index.ts +3 -3
- package/dist/resources/extensions/gsd/json-persistence.ts +16 -1
- package/dist/resources/extensions/gsd/md-importer.ts +3 -2
- package/dist/resources/extensions/gsd/mechanical-completion.ts +430 -0
- package/dist/resources/extensions/gsd/migrate/command.ts +3 -2
- package/dist/resources/extensions/gsd/migrate/writer.ts +2 -1
- package/dist/resources/extensions/gsd/migrate-external.ts +123 -0
- package/dist/resources/extensions/gsd/paths.ts +24 -2
- package/dist/resources/extensions/gsd/post-unit-hooks.ts +6 -5
- package/dist/resources/extensions/gsd/preferences-models.ts +7 -1
- package/dist/resources/extensions/gsd/preferences-validation.ts +2 -1
- package/dist/resources/extensions/gsd/preferences.ts +10 -5
- package/dist/resources/extensions/gsd/prompts/discuss-headless.md +4 -2
- package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/plan-milestone.md +26 -2
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +15 -1
- package/dist/resources/extensions/gsd/prompts/workflow-start.md +28 -0
- package/dist/resources/extensions/gsd/queue-order.ts +10 -11
- package/dist/resources/extensions/gsd/repo-identity.ts +148 -0
- package/dist/resources/extensions/gsd/resource-version.ts +99 -0
- package/dist/resources/extensions/gsd/session-forensics.ts +4 -3
- package/dist/resources/extensions/gsd/session-status-io.ts +23 -41
- package/dist/resources/extensions/gsd/tests/activity-log.test.ts +2 -2
- package/dist/resources/extensions/gsd/tests/auto-budget-alerts.test.ts +1 -1
- package/dist/resources/extensions/gsd/tests/auto-recovery.test.ts +3 -3
- package/dist/resources/extensions/gsd/tests/auto-skip-loop.test.ts +1 -1
- package/dist/resources/extensions/gsd/tests/auto-worktree.test.ts +0 -58
- package/dist/resources/extensions/gsd/tests/doctor-runtime.test.ts +3 -4
- package/dist/resources/extensions/gsd/tests/extension-selector-separator.test.ts +60 -38
- package/dist/resources/extensions/gsd/tests/feature-branch-lifecycle-integration.test.ts +5 -18
- package/dist/resources/extensions/gsd/tests/git-service.test.ts +10 -37
- package/dist/resources/extensions/gsd/tests/knowledge.test.ts +4 -4
- package/dist/resources/extensions/gsd/tests/mechanical-completion.test.ts +356 -0
- package/dist/resources/extensions/gsd/tests/parallel-workers-multi-milestone-e2e.test.ts +1 -1
- package/dist/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +1 -0
- package/dist/resources/extensions/gsd/tests/token-profile.test.ts +14 -16
- package/dist/resources/extensions/gsd/tests/workflow-templates.test.ts +173 -0
- package/dist/resources/extensions/gsd/triage-resolution.ts +2 -1
- package/dist/resources/extensions/gsd/types.ts +2 -0
- package/dist/resources/extensions/gsd/workflow-templates/bugfix.md +87 -0
- package/dist/resources/extensions/gsd/workflow-templates/dep-upgrade.md +74 -0
- package/dist/resources/extensions/gsd/workflow-templates/full-project.md +41 -0
- package/dist/resources/extensions/gsd/workflow-templates/hotfix.md +45 -0
- package/dist/resources/extensions/gsd/workflow-templates/refactor.md +83 -0
- package/dist/resources/extensions/gsd/workflow-templates/registry.json +85 -0
- package/dist/resources/extensions/gsd/workflow-templates/security-audit.md +73 -0
- package/dist/resources/extensions/gsd/workflow-templates/small-feature.md +81 -0
- package/dist/resources/extensions/gsd/workflow-templates/spike.md +69 -0
- package/dist/resources/extensions/gsd/workflow-templates.ts +241 -0
- package/dist/resources/extensions/gsd/worktree-command.ts +1 -11
- package/dist/resources/extensions/gsd/worktree-manager.ts +3 -2
- package/dist/resources/extensions/gsd/worktree.ts +42 -5
- package/dist/resources/extensions/mac-tools/extension-manifest.json +16 -0
- package/dist/resources/extensions/mcp-client/index.ts +459 -0
- package/dist/resources/extensions/mcporter/extension-manifest.json +12 -0
- package/dist/resources/extensions/remote-questions/discord-adapter.ts +8 -19
- package/dist/resources/extensions/remote-questions/extension-manifest.json +11 -0
- package/dist/resources/extensions/remote-questions/http-client.ts +76 -0
- package/dist/resources/extensions/remote-questions/slack-adapter.ts +11 -17
- package/dist/resources/extensions/remote-questions/telegram-adapter.ts +8 -19
- package/dist/resources/extensions/search-the-web/extension-manifest.json +13 -0
- package/dist/resources/extensions/slash-commands/extension-manifest.json +11 -0
- package/dist/resources/extensions/subagent/extension-manifest.json +13 -0
- package/dist/resources/extensions/ttsr/extension-manifest.json +11 -0
- package/dist/resources/extensions/universal-config/extension-manifest.json +13 -0
- package/dist/resources/extensions/voice/extension-manifest.json +12 -0
- package/dist/resources/skills/create-gsd-extension/SKILL.md +87 -0
- package/dist/resources/skills/create-gsd-extension/references/compaction-session-control.md +77 -0
- package/dist/resources/skills/create-gsd-extension/references/custom-commands.md +139 -0
- package/dist/resources/skills/create-gsd-extension/references/custom-rendering.md +108 -0
- package/dist/resources/skills/create-gsd-extension/references/custom-tools.md +183 -0
- package/dist/resources/skills/create-gsd-extension/references/custom-ui.md +490 -0
- package/dist/resources/skills/create-gsd-extension/references/events-reference.md +126 -0
- package/dist/resources/skills/create-gsd-extension/references/extension-lifecycle.md +64 -0
- package/dist/resources/skills/create-gsd-extension/references/extensionapi-reference.md +75 -0
- package/dist/resources/skills/create-gsd-extension/references/extensioncontext-reference.md +53 -0
- package/dist/resources/skills/create-gsd-extension/references/key-rules-gotchas.md +36 -0
- package/dist/resources/skills/create-gsd-extension/references/mode-behavior.md +32 -0
- package/dist/resources/skills/create-gsd-extension/references/model-provider-management.md +89 -0
- package/dist/resources/skills/create-gsd-extension/references/packaging-distribution.md +55 -0
- package/dist/resources/skills/create-gsd-extension/references/remote-execution-overrides.md +90 -0
- package/dist/resources/skills/create-gsd-extension/references/state-management.md +70 -0
- package/dist/resources/skills/create-gsd-extension/references/system-prompt-modification.md +52 -0
- package/dist/resources/skills/create-gsd-extension/templates/extension-skeleton.ts +51 -0
- package/dist/resources/skills/create-gsd-extension/templates/stateful-tool-skeleton.ts +143 -0
- package/dist/resources/skills/create-gsd-extension/workflows/add-capability.md +57 -0
- package/dist/resources/skills/create-gsd-extension/workflows/create-extension.md +156 -0
- package/dist/resources/skills/create-gsd-extension/workflows/debug-extension.md +74 -0
- package/dist/resources/skills/create-skill/SKILL.md +184 -0
- package/dist/resources/skills/create-skill/references/api-security.md +226 -0
- package/dist/resources/skills/create-skill/references/be-clear-and-direct.md +531 -0
- package/dist/resources/skills/create-skill/references/common-patterns.md +595 -0
- package/dist/resources/skills/create-skill/references/core-principles.md +437 -0
- package/dist/resources/skills/create-skill/references/executable-code.md +175 -0
- package/dist/resources/skills/create-skill/references/gsd-skill-ecosystem.md +68 -0
- package/dist/resources/skills/create-skill/references/iteration-and-testing.md +474 -0
- package/dist/resources/skills/create-skill/references/recommended-structure.md +168 -0
- package/dist/resources/skills/create-skill/references/skill-structure.md +372 -0
- package/dist/resources/skills/create-skill/references/use-xml-tags.md +466 -0
- package/dist/resources/skills/create-skill/references/using-scripts.md +113 -0
- package/dist/resources/skills/create-skill/references/using-templates.md +112 -0
- package/dist/resources/skills/create-skill/references/workflows-and-validation.md +510 -0
- package/dist/resources/skills/create-skill/templates/router-skill.md +73 -0
- package/dist/resources/skills/create-skill/templates/simple-skill.md +33 -0
- package/dist/resources/skills/create-skill/workflows/add-reference.md +96 -0
- package/dist/resources/skills/create-skill/workflows/add-script.md +93 -0
- package/dist/resources/skills/create-skill/workflows/add-template.md +74 -0
- package/dist/resources/skills/create-skill/workflows/add-workflow.md +120 -0
- package/dist/resources/skills/create-skill/workflows/audit-skill.md +148 -0
- package/dist/resources/skills/create-skill/workflows/create-new-skill.md +196 -0
- package/dist/resources/skills/create-skill/workflows/get-guidance.md +121 -0
- package/dist/resources/skills/create-skill/workflows/upgrade-to-router.md +161 -0
- package/dist/resources/skills/create-skill/workflows/verify-skill.md +204 -0
- package/dist/resources/skills/react-best-practices/SKILL.md +1 -1
- package/package.json +1 -1
- package/packages/native/dist/native.d.ts +2 -0
- package/packages/native/dist/native.js +19 -5
- package/packages/native/src/native.ts +23 -9
- package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.js +13 -0
- package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/client.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/client.js +3 -0
- package/packages/pi-coding-agent/dist/core/lsp/client.js.map +1 -1
- package/packages/pi-coding-agent/src/core/extensions/loader.ts +13 -0
- package/packages/pi-coding-agent/src/core/lsp/client.ts +3 -0
- package/src/resources/extensions/async-jobs/extension-manifest.json +13 -0
- package/src/resources/extensions/bg-shell/extension-manifest.json +14 -0
- package/src/resources/extensions/bg-shell/process-manager.ts +13 -0
- package/src/resources/extensions/browser-tools/extension-manifest.json +37 -0
- package/src/resources/extensions/context7/extension-manifest.json +12 -0
- package/src/resources/extensions/google-search/extension-manifest.json +12 -0
- package/src/resources/extensions/gsd/auto-dashboard.ts +217 -65
- package/src/resources/extensions/gsd/auto-dispatch.ts +32 -3
- package/src/resources/extensions/gsd/auto-post-unit.ts +45 -13
- package/src/resources/extensions/gsd/auto-prompts.ts +40 -17
- package/src/resources/extensions/gsd/auto-recovery.ts +18 -23
- package/src/resources/extensions/gsd/auto-start.ts +18 -32
- package/src/resources/extensions/gsd/auto-worktree.ts +21 -182
- package/src/resources/extensions/gsd/auto.ts +2 -24
- package/src/resources/extensions/gsd/captures.ts +4 -10
- package/src/resources/extensions/gsd/commands-extensions.ts +328 -0
- package/src/resources/extensions/gsd/commands-handlers.ts +22 -2
- package/src/resources/extensions/gsd/commands-logs.ts +13 -14
- package/src/resources/extensions/gsd/commands-prefs-wizard.ts +44 -14
- package/src/resources/extensions/gsd/commands-workflow-templates.ts +544 -0
- package/src/resources/extensions/gsd/commands.ts +108 -24
- package/src/resources/extensions/gsd/dashboard-overlay.ts +2 -1
- package/src/resources/extensions/gsd/detection.ts +2 -1
- package/src/resources/extensions/gsd/doctor-checks.ts +49 -1
- package/src/resources/extensions/gsd/doctor-types.ts +3 -1
- package/src/resources/extensions/gsd/extension-manifest.json +18 -0
- package/src/resources/extensions/gsd/forensics.ts +2 -2
- package/src/resources/extensions/gsd/git-service.ts +3 -2
- package/src/resources/extensions/gsd/gitignore.ts +9 -63
- package/src/resources/extensions/gsd/gsd-db.ts +1 -165
- package/src/resources/extensions/gsd/guided-flow.ts +8 -5
- package/src/resources/extensions/gsd/index.ts +3 -3
- package/src/resources/extensions/gsd/json-persistence.ts +16 -1
- package/src/resources/extensions/gsd/md-importer.ts +3 -2
- package/src/resources/extensions/gsd/mechanical-completion.ts +430 -0
- package/src/resources/extensions/gsd/migrate/command.ts +3 -2
- package/src/resources/extensions/gsd/migrate/writer.ts +2 -1
- package/src/resources/extensions/gsd/migrate-external.ts +123 -0
- package/src/resources/extensions/gsd/paths.ts +24 -2
- package/src/resources/extensions/gsd/post-unit-hooks.ts +6 -5
- package/src/resources/extensions/gsd/preferences-models.ts +7 -1
- package/src/resources/extensions/gsd/preferences-validation.ts +2 -1
- package/src/resources/extensions/gsd/preferences.ts +10 -5
- package/src/resources/extensions/gsd/prompts/discuss-headless.md +4 -2
- package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/plan-milestone.md +26 -2
- package/src/resources/extensions/gsd/prompts/plan-slice.md +15 -1
- package/src/resources/extensions/gsd/prompts/workflow-start.md +28 -0
- package/src/resources/extensions/gsd/queue-order.ts +10 -11
- package/src/resources/extensions/gsd/repo-identity.ts +148 -0
- package/src/resources/extensions/gsd/resource-version.ts +99 -0
- package/src/resources/extensions/gsd/session-forensics.ts +4 -3
- package/src/resources/extensions/gsd/session-status-io.ts +23 -41
- package/src/resources/extensions/gsd/tests/activity-log.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/auto-budget-alerts.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +3 -3
- package/src/resources/extensions/gsd/tests/auto-skip-loop.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/auto-worktree.test.ts +0 -58
- package/src/resources/extensions/gsd/tests/doctor-runtime.test.ts +3 -4
- package/src/resources/extensions/gsd/tests/extension-selector-separator.test.ts +60 -38
- package/src/resources/extensions/gsd/tests/feature-branch-lifecycle-integration.test.ts +5 -18
- package/src/resources/extensions/gsd/tests/git-service.test.ts +10 -37
- package/src/resources/extensions/gsd/tests/knowledge.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/mechanical-completion.test.ts +356 -0
- package/src/resources/extensions/gsd/tests/parallel-workers-multi-milestone-e2e.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/token-profile.test.ts +14 -16
- package/src/resources/extensions/gsd/tests/workflow-templates.test.ts +173 -0
- package/src/resources/extensions/gsd/triage-resolution.ts +2 -1
- package/src/resources/extensions/gsd/types.ts +2 -0
- package/src/resources/extensions/gsd/workflow-templates/bugfix.md +87 -0
- package/src/resources/extensions/gsd/workflow-templates/dep-upgrade.md +74 -0
- package/src/resources/extensions/gsd/workflow-templates/full-project.md +41 -0
- package/src/resources/extensions/gsd/workflow-templates/hotfix.md +45 -0
- package/src/resources/extensions/gsd/workflow-templates/refactor.md +83 -0
- package/src/resources/extensions/gsd/workflow-templates/registry.json +85 -0
- package/src/resources/extensions/gsd/workflow-templates/security-audit.md +73 -0
- package/src/resources/extensions/gsd/workflow-templates/small-feature.md +81 -0
- package/src/resources/extensions/gsd/workflow-templates/spike.md +69 -0
- package/src/resources/extensions/gsd/workflow-templates.ts +241 -0
- package/src/resources/extensions/gsd/worktree-command.ts +1 -11
- package/src/resources/extensions/gsd/worktree-manager.ts +3 -2
- package/src/resources/extensions/gsd/worktree.ts +42 -5
- package/src/resources/extensions/mac-tools/extension-manifest.json +16 -0
- package/src/resources/extensions/mcp-client/index.ts +459 -0
- package/src/resources/extensions/mcporter/extension-manifest.json +12 -0
- package/src/resources/extensions/remote-questions/discord-adapter.ts +8 -19
- package/src/resources/extensions/remote-questions/extension-manifest.json +11 -0
- package/src/resources/extensions/remote-questions/http-client.ts +76 -0
- package/src/resources/extensions/remote-questions/slack-adapter.ts +11 -17
- package/src/resources/extensions/remote-questions/telegram-adapter.ts +8 -19
- package/src/resources/extensions/search-the-web/extension-manifest.json +13 -0
- package/src/resources/extensions/slash-commands/extension-manifest.json +11 -0
- package/src/resources/extensions/subagent/extension-manifest.json +13 -0
- package/src/resources/extensions/ttsr/extension-manifest.json +11 -0
- package/src/resources/extensions/universal-config/extension-manifest.json +13 -0
- package/src/resources/extensions/voice/extension-manifest.json +12 -0
- package/src/resources/skills/create-gsd-extension/SKILL.md +87 -0
- package/src/resources/skills/create-gsd-extension/references/compaction-session-control.md +77 -0
- package/src/resources/skills/create-gsd-extension/references/custom-commands.md +139 -0
- package/src/resources/skills/create-gsd-extension/references/custom-rendering.md +108 -0
- package/src/resources/skills/create-gsd-extension/references/custom-tools.md +183 -0
- package/src/resources/skills/create-gsd-extension/references/custom-ui.md +490 -0
- package/src/resources/skills/create-gsd-extension/references/events-reference.md +126 -0
- package/src/resources/skills/create-gsd-extension/references/extension-lifecycle.md +64 -0
- package/src/resources/skills/create-gsd-extension/references/extensionapi-reference.md +75 -0
- package/src/resources/skills/create-gsd-extension/references/extensioncontext-reference.md +53 -0
- package/src/resources/skills/create-gsd-extension/references/key-rules-gotchas.md +36 -0
- package/src/resources/skills/create-gsd-extension/references/mode-behavior.md +32 -0
- package/src/resources/skills/create-gsd-extension/references/model-provider-management.md +89 -0
- package/src/resources/skills/create-gsd-extension/references/packaging-distribution.md +55 -0
- package/src/resources/skills/create-gsd-extension/references/remote-execution-overrides.md +90 -0
- package/src/resources/skills/create-gsd-extension/references/state-management.md +70 -0
- package/src/resources/skills/create-gsd-extension/references/system-prompt-modification.md +52 -0
- package/src/resources/skills/create-gsd-extension/templates/extension-skeleton.ts +51 -0
- package/src/resources/skills/create-gsd-extension/templates/stateful-tool-skeleton.ts +143 -0
- package/src/resources/skills/create-gsd-extension/workflows/add-capability.md +57 -0
- package/src/resources/skills/create-gsd-extension/workflows/create-extension.md +156 -0
- package/src/resources/skills/create-gsd-extension/workflows/debug-extension.md +74 -0
- package/src/resources/skills/create-skill/SKILL.md +184 -0
- package/src/resources/skills/create-skill/references/api-security.md +226 -0
- package/src/resources/skills/create-skill/references/be-clear-and-direct.md +531 -0
- package/src/resources/skills/create-skill/references/common-patterns.md +595 -0
- package/src/resources/skills/create-skill/references/core-principles.md +437 -0
- package/src/resources/skills/create-skill/references/executable-code.md +175 -0
- package/src/resources/skills/create-skill/references/gsd-skill-ecosystem.md +68 -0
- package/src/resources/skills/create-skill/references/iteration-and-testing.md +474 -0
- package/src/resources/skills/create-skill/references/recommended-structure.md +168 -0
- package/src/resources/skills/create-skill/references/skill-structure.md +372 -0
- package/src/resources/skills/create-skill/references/use-xml-tags.md +466 -0
- package/src/resources/skills/create-skill/references/using-scripts.md +113 -0
- package/src/resources/skills/create-skill/references/using-templates.md +112 -0
- package/src/resources/skills/create-skill/references/workflows-and-validation.md +510 -0
- package/src/resources/skills/create-skill/templates/router-skill.md +73 -0
- package/src/resources/skills/create-skill/templates/simple-skill.md +33 -0
- package/src/resources/skills/create-skill/workflows/add-reference.md +96 -0
- package/src/resources/skills/create-skill/workflows/add-script.md +93 -0
- package/src/resources/skills/create-skill/workflows/add-template.md +74 -0
- package/src/resources/skills/create-skill/workflows/add-workflow.md +120 -0
- package/src/resources/skills/create-skill/workflows/audit-skill.md +148 -0
- package/src/resources/skills/create-skill/workflows/create-new-skill.md +196 -0
- package/src/resources/skills/create-skill/workflows/get-guidance.md +121 -0
- package/src/resources/skills/create-skill/workflows/upgrade-to-router.md +161 -0
- package/src/resources/skills/create-skill/workflows/verify-skill.md +204 -0
- package/src/resources/skills/react-best-practices/SKILL.md +1 -1
- package/dist/resources/extensions/gsd/auto-worktree-sync.ts +0 -198
- package/dist/resources/extensions/gsd/tests/worktree-db-integration.test.ts +0 -205
- package/dist/resources/extensions/gsd/tests/worktree-db.test.ts +0 -442
- package/dist/resources/extensions/mcporter/index.ts +0 -525
- package/src/resources/extensions/gsd/auto-worktree-sync.ts +0 -198
- package/src/resources/extensions/gsd/tests/worktree-db-integration.test.ts +0 -205
- package/src/resources/extensions/gsd/tests/worktree-db.test.ts +0 -442
- package/src/resources/extensions/mcporter/index.ts +0 -525
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mechanical Completion — unit tests (ADR-003).
|
|
3
|
+
*
|
|
4
|
+
* Tests deterministic slice/milestone completion using fixture data.
|
|
5
|
+
* Uses node:test + node:assert for consistency with token-profile.test.ts.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import test from "node:test";
|
|
9
|
+
import assert from "node:assert/strict";
|
|
10
|
+
import { mkdirSync, writeFileSync, readFileSync, rmSync, existsSync } from "node:fs";
|
|
11
|
+
import { join } from "node:path";
|
|
12
|
+
import { tmpdir } from "node:os";
|
|
13
|
+
import { randomBytes } from "node:crypto";
|
|
14
|
+
|
|
15
|
+
// ─── Fixture Helpers ──────────────────────────────────────────────────────────
|
|
16
|
+
|
|
17
|
+
function createTmpBase(): string {
|
|
18
|
+
const base = join(tmpdir(), `gsd-mech-test-${randomBytes(4).toString("hex")}`);
|
|
19
|
+
mkdirSync(base, { recursive: true });
|
|
20
|
+
return base;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function scaffold(base: string, mid: string, sid: string, taskSummaries: Array<{ tid: string; content: string }>) {
|
|
24
|
+
const gsdRoot = join(base, ".gsd");
|
|
25
|
+
const mDir = join(gsdRoot, "milestones", mid);
|
|
26
|
+
const sDir = join(mDir, "slices", sid);
|
|
27
|
+
const tDir = join(sDir, "tasks");
|
|
28
|
+
mkdirSync(tDir, { recursive: true });
|
|
29
|
+
|
|
30
|
+
for (const { tid, content } of taskSummaries) {
|
|
31
|
+
writeFileSync(join(tDir, `${tid}-SUMMARY.md`), content, "utf-8");
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return { gsdRoot, mDir, sDir, tDir };
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function makeTaskSummary(tid: string, opts: {
|
|
38
|
+
oneLiner?: string;
|
|
39
|
+
provides?: string[];
|
|
40
|
+
key_files?: string[];
|
|
41
|
+
key_decisions?: string[];
|
|
42
|
+
verification_result?: string;
|
|
43
|
+
}): string {
|
|
44
|
+
const lines: string[] = [
|
|
45
|
+
"---",
|
|
46
|
+
`id: ${tid}`,
|
|
47
|
+
`parent: S01`,
|
|
48
|
+
`milestone: M001`,
|
|
49
|
+
];
|
|
50
|
+
if (opts.provides?.length) lines.push(`provides:\n${opts.provides.map(p => ` - ${p}`).join("\n")}`);
|
|
51
|
+
if (opts.key_files?.length) lines.push(`key_files:\n${opts.key_files.map(f => ` - ${f}`).join("\n")}`);
|
|
52
|
+
if (opts.key_decisions?.length) lines.push(`key_decisions:\n${opts.key_decisions.map(d => ` - ${d}`).join("\n")}`);
|
|
53
|
+
lines.push(`verification_result: ${opts.verification_result ?? "passed"}`);
|
|
54
|
+
lines.push("---");
|
|
55
|
+
lines.push("");
|
|
56
|
+
lines.push(`# ${tid}: Test Task`);
|
|
57
|
+
lines.push("");
|
|
58
|
+
if (opts.oneLiner) lines.push(`**${opts.oneLiner}**`);
|
|
59
|
+
lines.push("");
|
|
60
|
+
lines.push("## What Happened");
|
|
61
|
+
lines.push("");
|
|
62
|
+
lines.push(`Implemented the feature described in ${tid}. This was a significant change that modified multiple files across the codebase to support the new functionality.`);
|
|
63
|
+
lines.push("");
|
|
64
|
+
return lines.join("\n");
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// ─── Source-level structural tests ────────────────────────────────────────────
|
|
68
|
+
|
|
69
|
+
const mechanicalSrc = readFileSync(
|
|
70
|
+
join(import.meta.dirname!, "..", "mechanical-completion.ts"),
|
|
71
|
+
"utf-8",
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
test("mechanical-completion: exports mechanicalSliceCompletion", () => {
|
|
75
|
+
assert.ok(
|
|
76
|
+
mechanicalSrc.includes("export async function mechanicalSliceCompletion"),
|
|
77
|
+
"should export mechanicalSliceCompletion",
|
|
78
|
+
);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
test("mechanical-completion: exports aggregateMilestoneVerification", () => {
|
|
82
|
+
assert.ok(
|
|
83
|
+
mechanicalSrc.includes("export async function aggregateMilestoneVerification"),
|
|
84
|
+
"should export aggregateMilestoneVerification",
|
|
85
|
+
);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
test("mechanical-completion: exports generateMilestoneSummary", () => {
|
|
89
|
+
assert.ok(
|
|
90
|
+
mechanicalSrc.includes("export async function generateMilestoneSummary"),
|
|
91
|
+
"should export generateMilestoneSummary",
|
|
92
|
+
);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
test("mechanical-completion: exports appendNewDecisions", () => {
|
|
96
|
+
assert.ok(
|
|
97
|
+
mechanicalSrc.includes("export async function appendNewDecisions"),
|
|
98
|
+
"should export appendNewDecisions",
|
|
99
|
+
);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
test("mechanical-completion: uses atomicWriteSync for file writes", () => {
|
|
103
|
+
assert.ok(
|
|
104
|
+
mechanicalSrc.includes("atomicWriteSync"),
|
|
105
|
+
"should use atomicWriteSync for safe file writes",
|
|
106
|
+
);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
test("mechanical-completion: quality gate checks summary length for multi-task slices", () => {
|
|
110
|
+
assert.ok(
|
|
111
|
+
mechanicalSrc.includes("totalContent.length < 200"),
|
|
112
|
+
"should have quality gate for summary content length",
|
|
113
|
+
);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
test("mechanical-completion: marks slice [x] in roadmap", () => {
|
|
117
|
+
assert.ok(
|
|
118
|
+
mechanicalSrc.includes("markSliceInRoadmap"),
|
|
119
|
+
"should mark slice done in roadmap",
|
|
120
|
+
);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
test("mechanical-completion: aggregates VERIFY.json files for milestone validation", () => {
|
|
124
|
+
assert.ok(
|
|
125
|
+
mechanicalSrc.includes("resolveTaskJsonFiles") && mechanicalSrc.includes("VERIFY"),
|
|
126
|
+
"should read VERIFY.json files for milestone validation",
|
|
127
|
+
);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
test("mechanical-completion: deduplicates decisions against existing DECISIONS.md", () => {
|
|
131
|
+
assert.ok(
|
|
132
|
+
mechanicalSrc.includes("existing.includes(d.trim())"),
|
|
133
|
+
"should deduplicate decisions against existing content",
|
|
134
|
+
);
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
test("mechanical-completion: produces VALIDATION.md with verdict frontmatter", () => {
|
|
138
|
+
assert.ok(
|
|
139
|
+
mechanicalSrc.includes("verdict:") && mechanicalSrc.includes("remediation_round: 0"),
|
|
140
|
+
"VALIDATION.md should have verdict and remediation_round frontmatter",
|
|
141
|
+
);
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
// ─── Integration tests with fixture data ──────────────────────────────────────
|
|
145
|
+
|
|
146
|
+
test("mechanical: slice completion with 2 task summaries produces SUMMARY.md", async () => {
|
|
147
|
+
const base = createTmpBase();
|
|
148
|
+
try {
|
|
149
|
+
const mid = "M001";
|
|
150
|
+
const sid = "S01";
|
|
151
|
+
|
|
152
|
+
// Scaffold task summaries
|
|
153
|
+
scaffold(base, mid, sid, [
|
|
154
|
+
{
|
|
155
|
+
tid: "T01",
|
|
156
|
+
content: makeTaskSummary("T01", {
|
|
157
|
+
oneLiner: "Set up project structure",
|
|
158
|
+
provides: ["project-scaffold"],
|
|
159
|
+
key_files: ["src/index.ts", "package.json"],
|
|
160
|
+
verification_result: "passed",
|
|
161
|
+
}),
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
tid: "T02",
|
|
165
|
+
content: makeTaskSummary("T02", {
|
|
166
|
+
oneLiner: "Add core API endpoints",
|
|
167
|
+
provides: ["api-endpoints"],
|
|
168
|
+
key_files: ["src/api.ts"],
|
|
169
|
+
key_decisions: ["Used Express over Fastify"],
|
|
170
|
+
verification_result: "passed",
|
|
171
|
+
}),
|
|
172
|
+
},
|
|
173
|
+
]);
|
|
174
|
+
|
|
175
|
+
// Write a roadmap with the slice unchecked
|
|
176
|
+
const roadmapPath = join(base, ".gsd", "milestones", mid, `${mid}-ROADMAP.md`);
|
|
177
|
+
writeFileSync(roadmapPath, `# Roadmap\n\n- [ ] **${sid}: First Slice**\n`, "utf-8");
|
|
178
|
+
|
|
179
|
+
// Write a slice plan with Verification section
|
|
180
|
+
const planPath = join(base, ".gsd", "milestones", mid, "slices", sid, `${sid}-PLAN.md`);
|
|
181
|
+
writeFileSync(planPath, `# Plan\n\n## Verification\n\n- Run \`npm test\`\n- Check output\n`, "utf-8");
|
|
182
|
+
|
|
183
|
+
// Dynamic import to get the actual module
|
|
184
|
+
const { mechanicalSliceCompletion } = await import("../mechanical-completion.js");
|
|
185
|
+
const ok = await mechanicalSliceCompletion(base, mid, sid);
|
|
186
|
+
|
|
187
|
+
assert.ok(ok, "should return true for valid slice completion");
|
|
188
|
+
|
|
189
|
+
// Check SUMMARY.md was written
|
|
190
|
+
const summaryPath = join(base, ".gsd", "milestones", mid, "slices", sid, `${sid}-SUMMARY.md`);
|
|
191
|
+
assert.ok(existsSync(summaryPath), "SUMMARY.md should exist");
|
|
192
|
+
|
|
193
|
+
const summaryContent = readFileSync(summaryPath, "utf-8");
|
|
194
|
+
assert.ok(summaryContent.includes("T01"), "summary should reference T01");
|
|
195
|
+
assert.ok(summaryContent.includes("T02"), "summary should reference T02");
|
|
196
|
+
assert.ok(summaryContent.includes("verification_result: passed"), "should have passed verification");
|
|
197
|
+
|
|
198
|
+
// Check roadmap was updated
|
|
199
|
+
const updatedRoadmap = readFileSync(roadmapPath, "utf-8");
|
|
200
|
+
assert.ok(updatedRoadmap.includes("[x]"), "roadmap should have [x] checkbox");
|
|
201
|
+
|
|
202
|
+
// Check UAT was written
|
|
203
|
+
const uatPath = join(base, ".gsd", "milestones", mid, "slices", sid, `${sid}-UAT.md`);
|
|
204
|
+
assert.ok(existsSync(uatPath), "UAT.md should exist");
|
|
205
|
+
const uatContent = readFileSync(uatPath, "utf-8");
|
|
206
|
+
assert.ok(uatContent.includes("npm test"), "UAT should contain verification content");
|
|
207
|
+
} finally {
|
|
208
|
+
rmSync(base, { recursive: true, force: true });
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
test("mechanical: returns false for empty task summaries", async () => {
|
|
213
|
+
const base = createTmpBase();
|
|
214
|
+
try {
|
|
215
|
+
const mid = "M001";
|
|
216
|
+
const sid = "S01";
|
|
217
|
+
scaffold(base, mid, sid, []);
|
|
218
|
+
|
|
219
|
+
const { mechanicalSliceCompletion } = await import("../mechanical-completion.js");
|
|
220
|
+
const ok = await mechanicalSliceCompletion(base, mid, sid);
|
|
221
|
+
assert.ok(!ok, "should return false when no summaries exist");
|
|
222
|
+
} finally {
|
|
223
|
+
rmSync(base, { recursive: true, force: true });
|
|
224
|
+
}
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
test("mechanical: returns false for insufficient summary content in multi-task slice", async () => {
|
|
228
|
+
const base = createTmpBase();
|
|
229
|
+
try {
|
|
230
|
+
const mid = "M001";
|
|
231
|
+
const sid = "S01";
|
|
232
|
+
|
|
233
|
+
// Two tasks but with very short content (under 200 chars)
|
|
234
|
+
scaffold(base, mid, sid, [
|
|
235
|
+
{ tid: "T01", content: "---\nid: T01\nparent: S01\nmilestone: M001\n---\n\n# T01: A\n\n**Short**\n" },
|
|
236
|
+
{ tid: "T02", content: "---\nid: T02\nparent: S01\nmilestone: M001\n---\n\n# T02: B\n\n**Brief**\n" },
|
|
237
|
+
]);
|
|
238
|
+
|
|
239
|
+
const { mechanicalSliceCompletion } = await import("../mechanical-completion.js");
|
|
240
|
+
const ok = await mechanicalSliceCompletion(base, mid, sid);
|
|
241
|
+
assert.ok(!ok, "should return false when summaries are too short");
|
|
242
|
+
} finally {
|
|
243
|
+
rmSync(base, { recursive: true, force: true });
|
|
244
|
+
}
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
test("mechanical: milestone verification aggregates VERIFY.json files", async () => {
|
|
248
|
+
const base = createTmpBase();
|
|
249
|
+
try {
|
|
250
|
+
const mid = "M001";
|
|
251
|
+
const sid = "S01";
|
|
252
|
+
const { tDir } = scaffold(base, mid, sid, []);
|
|
253
|
+
|
|
254
|
+
// Write VERIFY.json files
|
|
255
|
+
const evidence = {
|
|
256
|
+
schemaVersion: 1,
|
|
257
|
+
taskId: "T01",
|
|
258
|
+
unitId: "M001/S01/T01",
|
|
259
|
+
timestamp: Date.now(),
|
|
260
|
+
passed: true,
|
|
261
|
+
discoverySource: "plan",
|
|
262
|
+
checks: [
|
|
263
|
+
{ command: "npm test", exitCode: 0, durationMs: 1500, verdict: "pass", blocking: true },
|
|
264
|
+
],
|
|
265
|
+
};
|
|
266
|
+
writeFileSync(join(tDir, "T01-VERIFY.json"), JSON.stringify(evidence), "utf-8");
|
|
267
|
+
|
|
268
|
+
const evidence2 = { ...evidence, taskId: "T02", passed: false, checks: [
|
|
269
|
+
{ command: "npm test", exitCode: 1, durationMs: 500, verdict: "fail", blocking: true },
|
|
270
|
+
]};
|
|
271
|
+
writeFileSync(join(tDir, "T02-VERIFY.json"), JSON.stringify(evidence2), "utf-8");
|
|
272
|
+
|
|
273
|
+
const { aggregateMilestoneVerification } = await import("../mechanical-completion.js");
|
|
274
|
+
const result = await aggregateMilestoneVerification(base, mid);
|
|
275
|
+
|
|
276
|
+
assert.equal(result.verdict, "mixed", "should be mixed when some pass and some fail");
|
|
277
|
+
assert.equal(result.checks.length, 2, "should have 2 checks");
|
|
278
|
+
|
|
279
|
+
// Check VALIDATION.md was written
|
|
280
|
+
const validationPath = join(base, ".gsd", "milestones", mid, `${mid}-VALIDATION.md`);
|
|
281
|
+
assert.ok(existsSync(validationPath), "VALIDATION.md should exist");
|
|
282
|
+
const validationContent = readFileSync(validationPath, "utf-8");
|
|
283
|
+
assert.ok(validationContent.includes("verdict: mixed"), "should have mixed verdict in frontmatter");
|
|
284
|
+
} finally {
|
|
285
|
+
rmSync(base, { recursive: true, force: true });
|
|
286
|
+
}
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
test("mechanical: milestone summary aggregates slice summaries", async () => {
|
|
290
|
+
const base = createTmpBase();
|
|
291
|
+
try {
|
|
292
|
+
const mid = "M001";
|
|
293
|
+
|
|
294
|
+
// Create two slices with summaries
|
|
295
|
+
for (const sid of ["S01", "S02"]) {
|
|
296
|
+
const sDir = join(base, ".gsd", "milestones", mid, "slices", sid);
|
|
297
|
+
mkdirSync(sDir, { recursive: true });
|
|
298
|
+
writeFileSync(
|
|
299
|
+
join(sDir, `${sid}-SUMMARY.md`),
|
|
300
|
+
`---\nid: ${sid}\nprovides:\n - feature-${sid.toLowerCase()}\nkey_files:\n - src/${sid.toLowerCase()}.ts\n---\n\n# ${sid}: Slice\n\n**${sid} implemented**\n`,
|
|
301
|
+
"utf-8",
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
const { generateMilestoneSummary } = await import("../mechanical-completion.js");
|
|
306
|
+
const content = await generateMilestoneSummary(base, mid);
|
|
307
|
+
|
|
308
|
+
assert.ok(content.includes("S01"), "should reference S01");
|
|
309
|
+
assert.ok(content.includes("S02"), "should reference S02");
|
|
310
|
+
assert.ok(content.includes("feature-s01"), "should aggregate provides");
|
|
311
|
+
assert.ok(content.includes("feature-s02"), "should aggregate provides");
|
|
312
|
+
|
|
313
|
+
const summaryPath = join(base, ".gsd", "milestones", mid, `${mid}-SUMMARY.md`);
|
|
314
|
+
assert.ok(existsSync(summaryPath), "M##-SUMMARY.md should exist");
|
|
315
|
+
} finally {
|
|
316
|
+
rmSync(base, { recursive: true, force: true });
|
|
317
|
+
}
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
test("mechanical: decision deduplication skips existing decisions", async () => {
|
|
321
|
+
const base = createTmpBase();
|
|
322
|
+
try {
|
|
323
|
+
const gsdRoot = join(base, ".gsd");
|
|
324
|
+
mkdirSync(gsdRoot, { recursive: true });
|
|
325
|
+
|
|
326
|
+
// Write existing decisions
|
|
327
|
+
const decisionsPath = join(gsdRoot, "DECISIONS.md");
|
|
328
|
+
writeFileSync(decisionsPath, "# Decisions\n\n- Used TypeScript for type safety\n", "utf-8");
|
|
329
|
+
|
|
330
|
+
const { appendNewDecisions } = await import("../mechanical-completion.js");
|
|
331
|
+
|
|
332
|
+
// Call with one existing and one new decision
|
|
333
|
+
const mockSummaries = [
|
|
334
|
+
{
|
|
335
|
+
frontmatter: {
|
|
336
|
+
id: "T01", parent: "S01", milestone: "M001",
|
|
337
|
+
provides: [], requires: [], affects: [],
|
|
338
|
+
key_files: [], key_decisions: ["Used TypeScript for type safety", "Chose Express over Koa"],
|
|
339
|
+
patterns_established: [], drill_down_paths: [], observability_surfaces: [],
|
|
340
|
+
duration: "", verification_result: "passed", completed_at: "", blocker_discovered: false,
|
|
341
|
+
},
|
|
342
|
+
title: "T01", oneLiner: "", whatHappened: "", deviations: "", filesModified: [],
|
|
343
|
+
},
|
|
344
|
+
];
|
|
345
|
+
|
|
346
|
+
await appendNewDecisions(base, mockSummaries as any);
|
|
347
|
+
|
|
348
|
+
const updated = readFileSync(decisionsPath, "utf-8");
|
|
349
|
+
assert.ok(updated.includes("Chose Express over Koa"), "should append new decision");
|
|
350
|
+
// The existing decision should not be duplicated
|
|
351
|
+
const matches = updated.match(/Used TypeScript for type safety/g);
|
|
352
|
+
assert.equal(matches?.length, 1, "should not duplicate existing decision");
|
|
353
|
+
} finally {
|
|
354
|
+
rmSync(base, { recursive: true, force: true });
|
|
355
|
+
}
|
|
356
|
+
});
|
|
@@ -25,6 +25,7 @@ const BASE_VARS = {
|
|
|
25
25
|
outputPath: "/tmp/test-project/.gsd/milestones/M001/slices/S01/S01-PLAN.md",
|
|
26
26
|
inlinedContext: "--- test inlined context ---",
|
|
27
27
|
dependencySummaries: "", executorContextConstraints: "",
|
|
28
|
+
sourceFilePaths: "- **Requirements**: `.gsd/REQUIREMENTS.md`",
|
|
28
29
|
};
|
|
29
30
|
|
|
30
31
|
test("plan-slice prompt: commit step present when commit_docs=true", () => {
|
|
@@ -53,6 +53,7 @@ test("types: PhaseSkipPreferences interface exported", () => {
|
|
|
53
53
|
assert.ok(typesSrc.includes("skip_research"), "should include skip_research");
|
|
54
54
|
assert.ok(typesSrc.includes("skip_reassess"), "should include skip_reassess");
|
|
55
55
|
assert.ok(typesSrc.includes("skip_slice_research"), "should include skip_slice_research");
|
|
56
|
+
assert.ok(typesSrc.includes("reassess_after_slice"), "should include reassess_after_slice");
|
|
56
57
|
});
|
|
57
58
|
|
|
58
59
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
@@ -113,24 +114,21 @@ test("profile: budget profile sets phase skips to true", () => {
|
|
|
113
114
|
assert.ok(budgetBlock.includes("skip_slice_research: true"), "budget should skip slice research");
|
|
114
115
|
});
|
|
115
116
|
|
|
116
|
-
test("profile: balanced profile skips
|
|
117
|
+
test("profile: balanced profile skips research, reassess, and slice research (ADR-003)", () => {
|
|
117
118
|
const balancedIdx = preferencesSrc.indexOf('case "balanced":');
|
|
118
119
|
const qualityIdx = preferencesSrc.indexOf('case "quality":');
|
|
119
120
|
const balancedBlock = preferencesSrc.slice(balancedIdx, qualityIdx);
|
|
120
121
|
assert.ok(balancedBlock.includes("skip_slice_research: true"), "balanced should skip slice research");
|
|
121
|
-
assert.ok(
|
|
122
|
-
assert.ok(
|
|
122
|
+
assert.ok(balancedBlock.includes("skip_research: true"), "balanced should skip milestone research");
|
|
123
|
+
assert.ok(balancedBlock.includes("skip_reassess: true"), "balanced should skip reassess");
|
|
123
124
|
});
|
|
124
125
|
|
|
125
|
-
test("profile: quality profile
|
|
126
|
+
test("profile: quality profile skips research, slice research, and reassess (ADR-003)", () => {
|
|
126
127
|
const qualityIdx = preferencesSrc.indexOf('case "quality":');
|
|
127
|
-
const
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
assert.ok(
|
|
131
|
-
qualityReturn.includes("phases: {}"),
|
|
132
|
-
"quality should have empty phases object (no skips)",
|
|
133
|
-
);
|
|
128
|
+
const qualityBlock = preferencesSrc.slice(qualityIdx, qualityIdx + 300);
|
|
129
|
+
assert.ok(qualityBlock.includes("skip_research: true"), "quality should skip research");
|
|
130
|
+
assert.ok(qualityBlock.includes("skip_slice_research: true"), "quality should skip slice research");
|
|
131
|
+
assert.ok(qualityBlock.includes("skip_reassess: true"), "quality should skip reassess");
|
|
134
132
|
});
|
|
135
133
|
|
|
136
134
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
@@ -253,10 +251,10 @@ test("dispatch: research-slice rule has skip guards", () => {
|
|
|
253
251
|
);
|
|
254
252
|
});
|
|
255
253
|
|
|
256
|
-
test("dispatch: reassess-roadmap rule has
|
|
254
|
+
test("dispatch: reassess-roadmap rule has reassess_after_slice opt-in guard (ADR-003)", () => {
|
|
257
255
|
assert.ok(
|
|
258
|
-
dispatchSrc.includes("
|
|
259
|
-
"reassess-roadmap dispatch rule should check phases.
|
|
256
|
+
dispatchSrc.includes("reassess_after_slice") && dispatchSrc.includes("reassess-roadmap"),
|
|
257
|
+
"reassess-roadmap dispatch rule should check phases.reassess_after_slice",
|
|
260
258
|
);
|
|
261
259
|
});
|
|
262
260
|
|
|
@@ -265,6 +263,6 @@ test("dispatch: phase skip guards return null (not stop)", () => {
|
|
|
265
263
|
const researchGuard = dispatchSrc.match(/skip_research\).*?return null/s);
|
|
266
264
|
assert.ok(researchGuard, "skip_research guard should return null (fall-through)");
|
|
267
265
|
|
|
268
|
-
const reassessGuard = dispatchSrc.match(/
|
|
269
|
-
assert.ok(reassessGuard, "
|
|
266
|
+
const reassessGuard = dispatchSrc.match(/reassess_after_slice\).*?return null/s);
|
|
267
|
+
assert.ok(reassessGuard, "reassess_after_slice guard should return null (fall-through)");
|
|
270
268
|
});
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
// GSD Workflow Templates — Unit Tests
|
|
2
|
+
//
|
|
3
|
+
// Tests registry loading, template resolution, auto-detection, and listing.
|
|
4
|
+
|
|
5
|
+
import { createTestContext } from './test-helpers.ts';
|
|
6
|
+
import {
|
|
7
|
+
loadRegistry,
|
|
8
|
+
resolveByName,
|
|
9
|
+
autoDetect,
|
|
10
|
+
listTemplates,
|
|
11
|
+
getTemplateInfo,
|
|
12
|
+
loadWorkflowTemplate,
|
|
13
|
+
} from '../workflow-templates.ts';
|
|
14
|
+
|
|
15
|
+
const { assertEq, assertTrue, assertMatch, report } = createTestContext();
|
|
16
|
+
|
|
17
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
18
|
+
// Registry Loading
|
|
19
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
20
|
+
|
|
21
|
+
console.log('\n── Registry Loading ──');
|
|
22
|
+
|
|
23
|
+
{
|
|
24
|
+
const registry = loadRegistry();
|
|
25
|
+
assertTrue(registry !== null, 'Registry should load');
|
|
26
|
+
assertEq(registry.version, 1, 'Registry version should be 1');
|
|
27
|
+
assertTrue(Object.keys(registry.templates).length >= 8, 'Should have at least 8 templates');
|
|
28
|
+
|
|
29
|
+
// Verify required template keys exist
|
|
30
|
+
const expectedIds = ['full-project', 'bugfix', 'small-feature', 'refactor', 'spike', 'hotfix', 'security-audit', 'dep-upgrade'];
|
|
31
|
+
for (const id of expectedIds) {
|
|
32
|
+
assertTrue(id in registry.templates, `Template "${id}" should exist in registry`);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Verify each template has required fields
|
|
36
|
+
for (const [id, entry] of Object.entries(registry.templates)) {
|
|
37
|
+
assertTrue(typeof entry.name === 'string' && entry.name.length > 0, `${id}: name should be non-empty string`);
|
|
38
|
+
assertTrue(typeof entry.description === 'string' && entry.description.length > 0, `${id}: description should be non-empty`);
|
|
39
|
+
assertTrue(typeof entry.file === 'string' && entry.file.endsWith('.md'), `${id}: file should be a .md path`);
|
|
40
|
+
assertTrue(Array.isArray(entry.phases) && entry.phases.length > 0, `${id}: phases should be non-empty array`);
|
|
41
|
+
assertTrue(Array.isArray(entry.triggers) && entry.triggers.length > 0, `${id}: triggers should be non-empty array`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
46
|
+
// Resolve by Name
|
|
47
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
48
|
+
|
|
49
|
+
console.log('\n── Resolve by Name ──');
|
|
50
|
+
|
|
51
|
+
{
|
|
52
|
+
// Exact match
|
|
53
|
+
const bugfix = resolveByName('bugfix');
|
|
54
|
+
assertTrue(bugfix !== null, 'Should resolve "bugfix"');
|
|
55
|
+
assertEq(bugfix!.id, 'bugfix', 'ID should be "bugfix"');
|
|
56
|
+
assertEq(bugfix!.confidence, 'exact', 'Exact name should have exact confidence');
|
|
57
|
+
|
|
58
|
+
// Case-insensitive name match
|
|
59
|
+
const spike = resolveByName('Research Spike');
|
|
60
|
+
assertTrue(spike !== null, 'Should resolve "Research Spike" by name');
|
|
61
|
+
assertEq(spike!.id, 'spike', 'Should resolve to spike');
|
|
62
|
+
|
|
63
|
+
// Alias match
|
|
64
|
+
const bug = resolveByName('bug');
|
|
65
|
+
assertTrue(bug !== null, 'Should resolve "bug" alias');
|
|
66
|
+
assertEq(bug!.id, 'bugfix', 'Alias "bug" should map to bugfix');
|
|
67
|
+
|
|
68
|
+
const feat = resolveByName('feat');
|
|
69
|
+
assertTrue(feat !== null, 'Should resolve "feat" alias');
|
|
70
|
+
assertEq(feat!.id, 'small-feature', 'Alias "feat" should map to small-feature');
|
|
71
|
+
|
|
72
|
+
const deps = resolveByName('deps');
|
|
73
|
+
assertTrue(deps !== null, 'Should resolve "deps" alias');
|
|
74
|
+
assertEq(deps!.id, 'dep-upgrade', 'Alias "deps" should map to dep-upgrade');
|
|
75
|
+
|
|
76
|
+
// No match
|
|
77
|
+
const missing = resolveByName('nonexistent-template');
|
|
78
|
+
assertTrue(missing === null, 'Should return null for unknown template');
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
82
|
+
// Auto-Detection
|
|
83
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
84
|
+
|
|
85
|
+
console.log('\n── Auto-Detection ──');
|
|
86
|
+
|
|
87
|
+
{
|
|
88
|
+
// Should detect bugfix from "fix" keyword
|
|
89
|
+
const fixMatches = autoDetect('fix the login button');
|
|
90
|
+
assertTrue(fixMatches.length > 0, 'Should detect matches for "fix the login button"');
|
|
91
|
+
assertTrue(fixMatches.some(m => m.id === 'bugfix'), 'Should include bugfix in matches');
|
|
92
|
+
|
|
93
|
+
// Should detect spike from "research" keyword
|
|
94
|
+
const researchMatches = autoDetect('research authentication libraries');
|
|
95
|
+
assertTrue(researchMatches.length > 0, 'Should detect matches for "research"');
|
|
96
|
+
assertTrue(researchMatches.some(m => m.id === 'spike'), 'Should include spike in matches');
|
|
97
|
+
|
|
98
|
+
// Should detect hotfix from "urgent" keyword
|
|
99
|
+
const urgentMatches = autoDetect('urgent production is down');
|
|
100
|
+
assertTrue(urgentMatches.length > 0, 'Should detect matches for "urgent"');
|
|
101
|
+
assertTrue(urgentMatches.some(m => m.id === 'hotfix'), 'Should include hotfix in matches');
|
|
102
|
+
|
|
103
|
+
// Should detect dep-upgrade from "upgrade" keyword
|
|
104
|
+
const upgradeMatches = autoDetect('upgrade react to v19');
|
|
105
|
+
assertTrue(upgradeMatches.length > 0, 'Should detect matches for "upgrade"');
|
|
106
|
+
assertTrue(upgradeMatches.some(m => m.id === 'dep-upgrade'), 'Should include dep-upgrade in matches');
|
|
107
|
+
|
|
108
|
+
// Multi-word triggers should score higher
|
|
109
|
+
const projectMatches = autoDetect('create a new project from scratch');
|
|
110
|
+
const projectMatch = projectMatches.find(m => m.id === 'full-project');
|
|
111
|
+
assertTrue(projectMatch !== undefined, 'Should detect full-project for "from scratch"');
|
|
112
|
+
|
|
113
|
+
// Empty input should return no matches
|
|
114
|
+
const emptyMatches = autoDetect('');
|
|
115
|
+
assertEq(emptyMatches.length, 0, 'Empty input should return no matches');
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
119
|
+
// List Templates
|
|
120
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
121
|
+
|
|
122
|
+
console.log('\n── List Templates ──');
|
|
123
|
+
|
|
124
|
+
{
|
|
125
|
+
const output = listTemplates();
|
|
126
|
+
assertTrue(output.includes('Workflow Templates'), 'Should have header');
|
|
127
|
+
assertTrue(output.includes('bugfix'), 'Should list bugfix');
|
|
128
|
+
assertTrue(output.includes('spike'), 'Should list spike');
|
|
129
|
+
assertTrue(output.includes('hotfix'), 'Should list hotfix');
|
|
130
|
+
assertTrue(output.includes('/gsd start'), 'Should include usage hint');
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
134
|
+
// Template Info
|
|
135
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
136
|
+
|
|
137
|
+
console.log('\n── Template Info ──');
|
|
138
|
+
|
|
139
|
+
{
|
|
140
|
+
const info = getTemplateInfo('bugfix');
|
|
141
|
+
assertTrue(info !== null, 'Should return info for bugfix');
|
|
142
|
+
assertTrue(info!.includes('Bug Fix'), 'Should include template name');
|
|
143
|
+
assertTrue(info!.includes('triage'), 'Should include phase names');
|
|
144
|
+
assertTrue(info!.includes('Triggers'), 'Should include triggers section');
|
|
145
|
+
|
|
146
|
+
const missing = getTemplateInfo('nonexistent');
|
|
147
|
+
assertTrue(missing === null, 'Should return null for unknown template');
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
151
|
+
// Load Workflow Template Content
|
|
152
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
153
|
+
|
|
154
|
+
console.log('\n── Load Workflow Template ──');
|
|
155
|
+
|
|
156
|
+
{
|
|
157
|
+
const content = loadWorkflowTemplate('bugfix');
|
|
158
|
+
assertTrue(content !== null, 'Should load bugfix template');
|
|
159
|
+
assertTrue(content!.includes('Bugfix Workflow'), 'Should contain workflow title');
|
|
160
|
+
assertTrue(content!.includes('Phase 1: Triage'), 'Should contain triage phase');
|
|
161
|
+
assertTrue(content!.includes('Phase 4: Ship'), 'Should contain ship phase');
|
|
162
|
+
|
|
163
|
+
const hotfixContent = loadWorkflowTemplate('hotfix');
|
|
164
|
+
assertTrue(hotfixContent !== null, 'Should load hotfix template');
|
|
165
|
+
assertTrue(hotfixContent!.includes('Hotfix Workflow'), 'Should contain hotfix title');
|
|
166
|
+
|
|
167
|
+
const missingContent = loadWorkflowTemplate('nonexistent');
|
|
168
|
+
assertTrue(missingContent === null, 'Should return null for unknown template');
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
172
|
+
|
|
173
|
+
report();
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
14
14
|
import { join } from "node:path";
|
|
15
|
+
import { gsdRoot } from "./paths.js";
|
|
15
16
|
import type { Classification, CaptureEntry } from "./captures.js";
|
|
16
17
|
import {
|
|
17
18
|
loadPendingCaptures,
|
|
@@ -36,7 +37,7 @@ export function executeInject(
|
|
|
36
37
|
): string | null {
|
|
37
38
|
try {
|
|
38
39
|
// Resolve the plan file path
|
|
39
|
-
const planPath = join(basePath, "
|
|
40
|
+
const planPath = join(gsdRoot(basePath), "milestones", mid, "slices", sid, `${sid}-PLAN.md`);
|
|
40
41
|
if (!existsSync(planPath)) return null;
|
|
41
42
|
|
|
42
43
|
const content = readFileSync(planPath, "utf-8");
|
|
@@ -304,6 +304,8 @@ export interface PhaseSkipPreferences {
|
|
|
304
304
|
skip_reassess?: boolean;
|
|
305
305
|
skip_slice_research?: boolean;
|
|
306
306
|
skip_milestone_validation?: boolean;
|
|
307
|
+
/** When true, reassess-roadmap fires after each slice completion. Opt-in. */
|
|
308
|
+
reassess_after_slice?: boolean;
|
|
307
309
|
/** When true, auto-mode pauses before each slice for discussion (#789). */
|
|
308
310
|
require_slice_discussion?: boolean;
|
|
309
311
|
}
|