test: add stale /gsd: colon reference regression guard (#1753)

* test: add stale /gsd: colon reference regression guard

Fixes #1748

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: replace 39 stale /gsd: colon references with /gsd- hyphen format

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Tom Boucher
2026-04-05 10:23:41 -04:00
committed by GitHub
parent b34da909a3
commit 6bd786bf88
21 changed files with 535 additions and 39 deletions

View File

@@ -90,7 +90,7 @@ body:
label: What happened? label: What happened?
description: Describe what went wrong. Be specific about which GSD command you were running. description: Describe what went wrong. Be specific about which GSD command you were running.
placeholder: | placeholder: |
When I ran `/gsd:plan`, the system... When I ran `/gsd-plan`, the system...
validations: validations:
required: true required: true
@@ -111,8 +111,8 @@ body:
placeholder: | placeholder: |
1. Install GSD with `npx get-shit-done-cc@latest` 1. Install GSD with `npx get-shit-done-cc@latest`
2. Select runtime: Claude Code 2. Select runtime: Claude Code
3. Run `/gsd:init` with a new project 3. Run `/gsd-init` with a new project
4. Run `/gsd:plan` 4. Run `/gsd-plan`
5. Error appears at step... 5. Error appears at step...
validations: validations:
required: true required: true

View File

@@ -39,7 +39,7 @@ body:
attributes: attributes:
label: What existing feature or behavior does this improve? label: What existing feature or behavior does this improve?
description: Name the specific command, workflow, output, or behavior you are enhancing. description: Name the specific command, workflow, output, or behavior you are enhancing.
placeholder: "e.g., `/gsd:plan` output, phase status display in statusline, context summary format" placeholder: "e.g., `/gsd-plan` output, phase status display in statusline, context summary format"
validations: validations:
required: true required: true
@@ -50,7 +50,7 @@ body:
description: | description: |
Describe exactly how the thing works today. Be specific. Include example output or commands if helpful. Describe exactly how the thing works today. Be specific. Include example output or commands if helpful.
placeholder: | placeholder: |
Currently, `/gsd:status` shows: Currently, `/gsd-status` shows:
``` ```
Phase 2/5 — In Progress Phase 2/5 — In Progress
``` ```
@@ -66,7 +66,7 @@ body:
description: | description: |
Describe exactly how it should work after the enhancement. Be specific. Include example output or commands. Describe exactly how it should work after the enhancement. Be specific. Include example output or commands.
placeholder: | placeholder: |
After the enhancement, `/gsd:status` would show: After the enhancement, `/gsd-status` would show:
``` ```
Phase 2/5 — In Progress — "Implement core auth module" Phase 2/5 — In Progress — "Implement core auth module"
``` ```

View File

@@ -83,14 +83,14 @@ body:
Describe exactly what is being added. Be specific about commands, output, behavior, and user interaction. Describe exactly what is being added. Be specific about commands, output, behavior, and user interaction.
Include example commands or example output where possible. Include example commands or example output where possible.
placeholder: | placeholder: |
A new command `/gsd:rollback` that: A new command `/gsd-rollback` that:
1. Reads the current phase from STATE.md 1. Reads the current phase from STATE.md
2. Reverts STATE.md to the previous phase's snapshot 2. Reverts STATE.md to the previous phase's snapshot
3. Outputs a confirmation with the rolled-back state 3. Outputs a confirmation with the rolled-back state
Example usage: Example usage:
``` ```
/gsd:rollback /gsd-rollback
> Rolled back from Phase 3 (failed) to Phase 2 (completed) > Rolled back from Phase 3 (failed) to Phase 2 (completed)
``` ```
validations: validations:
@@ -139,9 +139,9 @@ body:
List the specific, testable conditions that must be true for this feature to be considered complete. List the specific, testable conditions that must be true for this feature to be considered complete.
These become the basis for reviewer sign-off. Vague criteria ("it works") are not acceptable. These become the basis for reviewer sign-off. Vague criteria ("it works") are not acceptable.
placeholder: | placeholder: |
- [ ] `/gsd:rollback` reverts STATE.md to the previous phase when current phase status is `failed` - [ ] `/gsd-rollback` reverts STATE.md to the previous phase when current phase status is `failed`
- [ ] `/gsd:rollback` exits with an error if there is no previous phase to roll back to - [ ] `/gsd-rollback` exits with an error if there is no previous phase to roll back to
- [ ] `/gsd:rollback` outputs the before/after phase names in its confirmation message - [ ] `/gsd-rollback` outputs the before/after phase names in its confirmation message
- [ ] Rollback is logged in the phase history so the AI agent can see it happened - [ ] Rollback is logged in the phase history so the AI agent can see it happened
- [ ] All existing tests still pass - [ ] All existing tests still pass
- [ ] New tests cover the happy path, no-previous-phase case, and STATE.md corruption case - [ ] New tests cover the happy path, no-previous-phase case, and STATE.md corruption case
@@ -226,7 +226,7 @@ body:
placeholder: | placeholder: |
1. Manual STATE.md editing — rejected because it requires the developer to understand the schema 1. Manual STATE.md editing — rejected because it requires the developer to understand the schema
and is error-prone. The AI agent cannot reliably guide this. and is error-prone. The AI agent cannot reliably guide this.
2. A `/gsd:reset` command that wipes all state — rejected because it is too destructive and 2. A `/gsd-reset` command that wipes all state — rejected because it is too destructive and
loses all completed phase history. loses all completed phase history.
validations: validations:
required: true required: true

View File

@@ -58,7 +58,7 @@
<text class="text" font-size="15" y="304"><tspan class="green"></tspan><tspan class="white"> Installed get-shit-done</tspan></text> <text class="text" font-size="15" y="304"><tspan class="green"></tspan><tspan class="white"> Installed get-shit-done</tspan></text>
<!-- Done message --> <!-- Done message -->
<text class="text" font-size="15" y="352"><tspan class="green"> Done!</tspan><tspan class="white"> Run </tspan><tspan class="cyan">/gsd:help</tspan><tspan class="white"> to get started.</tspan></text> <text class="text" font-size="15" y="352"><tspan class="green"> Done!</tspan><tspan class="white"> Run </tspan><tspan class="cyan">/gsd-help</tspan><tspan class="white"> to get started.</tspan></text>
<!-- New prompt --> <!-- New prompt -->
<text class="text prompt" font-size="15" y="400">~</text> <text class="text prompt" font-size="15" y="400">~</text>

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@@ -2990,7 +2990,7 @@ function convertClaudeToOpencodeFrontmatter(content, { isAgent = false } = {}) {
convertedContent = convertedContent.replace(/\bAskUserQuestion\b/g, 'question'); convertedContent = convertedContent.replace(/\bAskUserQuestion\b/g, 'question');
convertedContent = convertedContent.replace(/\bSlashCommand\b/g, 'skill'); convertedContent = convertedContent.replace(/\bSlashCommand\b/g, 'skill');
convertedContent = convertedContent.replace(/\bTodoWrite\b/g, 'todowrite'); convertedContent = convertedContent.replace(/\bTodoWrite\b/g, 'todowrite');
// Replace /gsd:command with /gsd-command for opencode (flat command structure) // Replace /gsd-command colon variant with /gsd-command for opencode (flat command structure)
convertedContent = convertedContent.replace(/\/gsd:/g, '/gsd-'); convertedContent = convertedContent.replace(/\/gsd:/g, '/gsd-');
// Replace ~/.claude and $HOME/.claude with OpenCode's config location // Replace ~/.claude and $HOME/.claude with OpenCode's config location
convertedContent = convertedContent.replace(/~\/\.claude\b/g, '~/.config/opencode'); convertedContent = convertedContent.replace(/~\/\.claude\b/g, '~/.config/opencode');
@@ -3141,7 +3141,7 @@ function convertClaudeToKiloFrontmatter(content, { isAgent = false } = {}) {
convertedContent = convertedContent.replace(/\bAskUserQuestion\b/g, 'question'); convertedContent = convertedContent.replace(/\bAskUserQuestion\b/g, 'question');
convertedContent = convertedContent.replace(/\bSlashCommand\b/g, 'skill'); convertedContent = convertedContent.replace(/\bSlashCommand\b/g, 'skill');
convertedContent = convertedContent.replace(/\bTodoWrite\b/g, 'todowrite'); convertedContent = convertedContent.replace(/\bTodoWrite\b/g, 'todowrite');
// Replace /gsd:command with /gsd-command for Kilo (flat command structure) // Replace /gsd-command colon variant with /gsd-command for Kilo (flat command structure)
convertedContent = convertedContent.replace(/\/gsd:/g, '/gsd-'); convertedContent = convertedContent.replace(/\/gsd:/g, '/gsd-');
// Replace ~/.claude and $HOME/.claude with Kilo's config location // Replace ~/.claude and $HOME/.claude with Kilo's config location
convertedContent = convertedContent.replace(/~\/\.claude\b/g, '~/.config/kilo'); convertedContent = convertedContent.replace(/~\/\.claude\b/g, '~/.config/kilo');
@@ -5824,7 +5824,7 @@ function finishInstall(settingsPath, settings, statuslineCommand, shouldInstallS
if (runtime === 'augment') program = 'Augment'; if (runtime === 'augment') program = 'Augment';
if (runtime === 'trae') program = 'Trae'; if (runtime === 'trae') program = 'Trae';
let command = '/gsd:new-project'; let command = '/gsd-new-project';
if (runtime === 'opencode') command = '/gsd-new-project'; if (runtime === 'opencode') command = '/gsd-new-project';
if (runtime === 'kilo') command = '/gsd-new-project'; if (runtime === 'kilo') command = '/gsd-new-project';
if (runtime === 'codex') command = '$gsd-new-project'; if (runtime === 'codex') command = '$gsd-new-project';

View File

@@ -25,7 +25,7 @@ Then suggest `Depends on` updates to ROADMAP.md.
<context> <context>
No arguments required. Requires an active milestone with ROADMAP.md. No arguments required. Requires an active milestone with ROADMAP.md.
Run this command BEFORE `/gsd:manager` to fill in missing `Depends on` fields and prevent merge conflicts from unordered parallel execution. Run this command BEFORE `/gsd-manager` to fill in missing `Depends on` fields and prevent merge conflicts from unordered parallel execution.
</context> </context>
<process> <process>

View File

@@ -59,4 +59,4 @@ The installer performs a clean wipe-and-replace of GSD-managed directories only:
- Your `CLAUDE.md` files - Your `CLAUDE.md` files
- Custom hooks - Custom hooks
Locally modified GSD files are automatically backed up to `gsd-local-patches/` before the install. Run `/gsd:reapply-patches` after updating to merge your modifications back in. Locally modified GSD files are automatically backed up to `gsd-local-patches/` before the install. Run `/gsd-reapply-patches` after updating to merge your modifications back in.

View File

@@ -777,7 +777,7 @@ function cmdValidateHealth(cwd, options, raw) {
if (statusVal !== 'complete' && statusVal !== 'done') { if (statusVal !== 'complete' && statusVal !== 'done') {
addIssue('warning', 'W011', addIssue('warning', 'W011',
`STATE.md says current phase is ${statePhase} (status: ${statusVal || 'unknown'}) but ROADMAP.md shows it as [x] complete — state files may be out of sync`, `STATE.md says current phase is ${statePhase} (status: ${statusVal || 'unknown'}) but ROADMAP.md shows it as [x] complete — state files may be out of sync`,
'Run /gsd:progress to re-derive current position, or manually update STATE.md'); 'Run /gsd-progress to re-derive current position, or manually update STATE.md');
} }
} }
} }

View File

@@ -35,7 +35,7 @@ Configuration options for `.planning/` directory behavior.
| `git.quick_branch_template` | `null` | Optional branch template for quick-task runs | | `git.quick_branch_template` | `null` | Optional branch template for quick-task runs |
| `workflow.use_worktrees` | `true` | Whether executor agents run in isolated git worktrees. Set to `false` to disable worktrees — agents execute sequentially on the main working tree instead. Recommended for solo developers or when worktree merges cause issues. | | `workflow.use_worktrees` | `true` | Whether executor agents run in isolated git worktrees. Set to `false` to disable worktrees — agents execute sequentially on the main working tree instead. Recommended for solo developers or when worktree merges cause issues. |
| `workflow.subagent_timeout` | `300000` | Timeout in milliseconds for parallel subagent tasks (e.g. codebase mapping). Increase for large codebases or slower models. Default: 300000 (5 minutes). | | `workflow.subagent_timeout` | `300000` | Timeout in milliseconds for parallel subagent tasks (e.g. codebase mapping). Increase for large codebases or slower models. Default: 300000 (5 minutes). |
| `manager.flags.discuss` | `""` | Flags passed to `/gsd:discuss-phase` when dispatched from manager (e.g. `"--auto --analyze"`) | | `manager.flags.discuss` | `""` | Flags passed to `/gsd-discuss-phase` when dispatched from manager (e.g. `"--auto --analyze"`) |
| `manager.flags.plan` | `""` | Flags passed to plan workflow when dispatched from manager | | `manager.flags.plan` | `""` | Flags passed to plan workflow when dispatched from manager |
| `manager.flags.execute` | `""` | Flags passed to execute workflow when dispatched from manager | | `manager.flags.execute` | `""` | Flags passed to execute workflow when dispatched from manager |
| `response_language` | `null` | Language for user-facing questions and prompts across all phases/subagents (e.g. `"Portuguese"`, `"Japanese"`, `"Spanish"`). When set, all spawned agents include a directive to respond in this language. | | `response_language` | `null` | Language for user-facing questions and prompts across all phases/subagents (e.g. `"Portuguese"`, `"Japanese"`, `"Spanish"`). When set, all spawned agents include a directive to respond in this language. |

View File

@@ -1,12 +1,12 @@
<purpose> <purpose>
Analyze ROADMAP.md phases for dependency relationships before execution. Detect file overlap between phases, semantic API/data-flow dependencies, and suggest `Depends on` entries to prevent merge conflicts during parallel execution by `/gsd:manager`. Analyze ROADMAP.md phases for dependency relationships before execution. Detect file overlap between phases, semantic API/data-flow dependencies, and suggest `Depends on` entries to prevent merge conflicts during parallel execution by `/gsd-manager`.
</purpose> </purpose>
<process> <process>
## 1. Load ROADMAP.md ## 1. Load ROADMAP.md
Read `.planning/ROADMAP.md`. If it does not exist, error: "No ROADMAP.md found — run `/gsd:new-project` first." Read `.planning/ROADMAP.md`. If it does not exist, error: "No ROADMAP.md found — run `/gsd-new-project` first."
Extract all phases. For each phase capture: Extract all phases. For each phase capture:
- Phase number and name - Phase number and name
@@ -91,6 +91,6 @@ When writing to ROADMAP.md:
- Preserve all other phase content unchanged - Preserve all other phase content unchanged
- Do not reorder phases - Do not reorder phases
After applying: "ROADMAP.md updated. Run `/gsd:manager` to execute phases in the correct order." After applying: "ROADMAP.md updated. Run `/gsd-manager` to execute phases in the correct order."
</process> </process>

View File

@@ -784,7 +784,7 @@ Decisions captured: {count} across {area_count} areas
Completed through phase ${TO_PHASE} as requested. Completed through phase ${TO_PHASE} as requested.
Remaining phases were not executed. Remaining phases were not executed.
Resume with: /gsd:autonomous --from ${next_incomplete_phase} Resume with: /gsd-autonomous --from ${next_incomplete_phase}
``` ```
Proceed directly to lifecycle step (which handles partial completion — skips audit/complete/cleanup since not all phases are done). Exit cleanly. Proceed directly to lifecycle step (which handles partial completion — skips audit/complete/cleanup since not all phases are done). Exit cleanly.

View File

@@ -5,7 +5,7 @@ Power user mode for discuss-phase. Generates ALL questions upfront into a JSON s
</purpose> </purpose>
<trigger> <trigger>
This workflow executes when `--power` flag is present in ARGUMENTS to `/gsd:discuss-phase`. This workflow executes when `--power` flag is present in ARGUMENTS to `/gsd-discuss-phase`.
The caller (discuss-phase.md) has already: The caller (discuss-phase.md) has already:
- Validated the phase exists - Validated the phase exists
@@ -265,7 +265,7 @@ Process all answered questions from the JSON file and generate CONTEXT.md.
``` ```
Warning: Only {answered}/{total} questions answered ({pct}%). Warning: Only {answered}/{total} questions answered ({pct}%).
CONTEXT.md generated with available decisions. Unanswered questions listed as deferred. CONTEXT.md generated with available decisions. Unanswered questions listed as deferred.
Consider running /gsd:discuss-phase {N} again to refine before planning. Consider running /gsd-discuss-phase {N} again to refine before planning.
``` ```
7. Print completion message: 7. Print completion message:
@@ -275,7 +275,7 @@ CONTEXT.md written: {phase_dir}/{padded_phase}-CONTEXT.md
Decisions captured: {answered} Decisions captured: {answered}
Deferred: {remaining} Deferred: {remaining}
Next step: /gsd:plan-phase {N} Next step: /gsd-plan-phase {N}
``` ```
</step> </step>

View File

@@ -0,0 +1,384 @@
<purpose>
Triage and review all open GitHub issues and PRs against project contribution templates.
Produces a structured report showing compliance status for each item, flags missing
required fields, identifies label gaps, and optionally takes action (label, comment, close).
</purpose>
<required_reading>
Before starting, read these project files to understand the review criteria:
- `.github/ISSUE_TEMPLATE/feature_request.yml` — required fields for feature issues
- `.github/ISSUE_TEMPLATE/enhancement.yml` — required fields for enhancement issues
- `.github/ISSUE_TEMPLATE/chore.yml` — required fields for chore issues
- `.github/ISSUE_TEMPLATE/bug_report.yml` — required fields for bug reports
- `.github/PULL_REQUEST_TEMPLATE/feature.md` — required checklist for feature PRs
- `.github/PULL_REQUEST_TEMPLATE/enhancement.md` — required checklist for enhancement PRs
- `.github/PULL_REQUEST_TEMPLATE/fix.md` — required checklist for fix PRs
- `CONTRIBUTING.md` — the issue-first rule and approval gates
</required_reading>
<process>
<step name="preflight">
Verify prerequisites:
1. **`gh` CLI available and authenticated?**
```bash
which gh && gh auth status 2>&1
```
If not available: print setup instructions and exit.
2. **Detect repository:**
If `--repo` flag provided, use that. Otherwise:
```bash
gh repo view --json nameWithOwner -q '.nameWithOwner' 2>/dev/null
```
If no repo detected: error — must be in a git repo with a GitHub remote.
3. **Parse flags:**
- `--issues` → set REVIEW_ISSUES=true, REVIEW_PRS=false
- `--prs` → set REVIEW_ISSUES=false, REVIEW_PRS=true
- `--label` → set AUTO_LABEL=true
- `--close-incomplete` → set AUTO_CLOSE=true
- Default (no flags): review both issues and PRs, report only (no auto-actions)
</step>
<step name="fetch_issues">
Skip if REVIEW_ISSUES=false.
Fetch all open issues:
```bash
gh issue list --state open --json number,title,labels,body,author,createdAt,updatedAt --limit 100
```
For each issue, classify by labels and body content:
| Label/Pattern | Type | Template |
|---|---|---|
| `feature-request` | Feature | feature_request.yml |
| `enhancement` | Enhancement | enhancement.yml |
| `bug` | Bug | bug_report.yml |
| `type: chore` | Chore | chore.yml |
| No matching label | Unknown | Flag for manual triage |
If an issue has no type label, attempt to classify from the body content:
- Contains "### Feature name" → likely Feature
- Contains "### What existing feature" → likely Enhancement
- Contains "### What happened?" → likely Bug
- Contains "### What is the maintenance task?" → likely Chore
- Cannot determine → mark as `needs-triage`
</step>
<step name="review_issues">
Skip if REVIEW_ISSUES=false.
For each classified issue, review against its template requirements.
**Feature Request Review Checklist:**
- [ ] Pre-submission checklist present (4 checkboxes)
- [ ] Feature name provided
- [ ] Type of addition selected
- [ ] Problem statement filled (not placeholder text)
- [ ] What is being added described with examples
- [ ] Full scope of changes listed (files created/modified/systems)
- [ ] User stories present (minimum 2)
- [ ] Acceptance criteria present (testable conditions)
- [ ] Applicable runtimes selected
- [ ] Breaking changes assessment present
- [ ] Maintenance burden described
- [ ] Alternatives considered (not empty)
- **Label check:** Has `needs-review` label? Has `approved-feature` label?
- **Gate check:** If PR exists linking this issue, does issue have `approved-feature`?
**Enhancement Review Checklist:**
- [ ] Pre-submission checklist present (4 checkboxes)
- [ ] What is being improved identified
- [ ] Current behavior described with examples
- [ ] Proposed behavior described with examples
- [ ] Reason and benefit articulated (not vague)
- [ ] Scope of changes listed
- [ ] Breaking changes assessed
- [ ] Alternatives considered
- [ ] Area affected selected
- **Label check:** Has `needs-review` label? Has `approved-enhancement` label?
- **Gate check:** If PR exists linking this issue, does issue have `approved-enhancement`?
**Bug Report Review Checklist:**
- [ ] GSD Version provided
- [ ] Runtime selected
- [ ] OS selected
- [ ] Node.js version provided
- [ ] Description of what happened
- [ ] Expected behavior described
- [ ] Steps to reproduce provided
- [ ] Frequency selected
- [ ] Severity/impact selected
- [ ] PII checklist confirmed
- **Label check:** Has `needs-triage` or `confirmed-bug` label?
**Chore Review Checklist:**
- [ ] Pre-submission checklist confirmed (no user-facing changes)
- [ ] Maintenance task described
- [ ] Type of maintenance selected
- [ ] Current state described with specifics
- [ ] Proposed work listed
- [ ] Acceptance criteria present
- [ ] Area affected selected
- **Label check:** Has `needs-triage` label?
**Scoring:** For each issue, calculate a completeness percentage:
- Count required fields present vs. total required fields
- Score = (present / total) * 100
- Status: COMPLETE (100%), MOSTLY COMPLETE (75-99%), INCOMPLETE (50-74%), REJECT (<50%)
</step>
<step name="fetch_prs">
Skip if REVIEW_PRS=false.
Fetch all open PRs:
```bash
gh pr list --state open --json number,title,labels,body,author,headRefName,baseRefName,isDraft,createdAt,reviewDecision,statusCheckRollup --limit 100
```
For each PR, classify by body content and linked issue:
| Body Pattern | Type | Template |
|---|---|---|
| Contains "## Feature PR" or "## Feature summary" | Feature PR | feature.md |
| Contains "## Enhancement PR" or "## What this enhancement improves" | Enhancement PR | enhancement.md |
| Contains "## Fix PR" or "## What was broken" | Fix PR | fix.md |
| Uses default template | Wrong Template | Flag — must use typed template |
| Cannot determine | Unknown | Flag for manual review |
Also check for linked issues:
```bash
gh pr view {number} --json body -q '.body' | grep -oE '(Closes|Fixes|Resolves) #[0-9]+'
```
</step>
<step name="review_prs">
Skip if REVIEW_PRS=false.
For each classified PR, review against its template requirements.
**Feature PR Review Checklist:**
- [ ] Uses feature PR template (not default)
- [ ] Issue linked with `Closes #NNN`
- [ ] Linked issue exists and has `approved-feature` label
- [ ] Feature summary present
- [ ] New files table filled
- [ ] Modified files table filled
- [ ] Implementation notes present
- [ ] Spec compliance checklist present (acceptance criteria from issue)
- [ ] Test coverage described
- [ ] Platforms tested checked (macOS, Windows, Linux)
- [ ] Runtimes tested checked
- [ ] Scope confirmation checked
- [ ] Full checklist completed
- [ ] Breaking changes section filled
- **CI check:** All status checks passing?
- **Review check:** Has review approval?
**Enhancement PR Review Checklist:**
- [ ] Uses enhancement PR template (not default)
- [ ] Issue linked with `Closes #NNN`
- [ ] Linked issue exists and has `approved-enhancement` label
- [ ] What is improved described
- [ ] Before/after provided
- [ ] Implementation approach described
- [ ] Verification method described
- [ ] Platforms tested checked
- [ ] Runtimes tested checked
- [ ] Scope confirmation checked
- [ ] Full checklist completed
- [ ] Breaking changes section filled
- **CI check:** All status checks passing?
**Fix PR Review Checklist:**
- [ ] Uses fix PR template (not default)
- [ ] Issue linked with `Fixes #NNN`
- [ ] Linked issue exists and has `confirmed-bug` label
- [ ] What was broken described
- [ ] What the fix does described
- [ ] Root cause explained
- [ ] Verification method described
- [ ] Regression test added (or explained why not)
- [ ] Platforms tested checked
- [ ] Runtimes tested checked
- [ ] Full checklist completed
- [ ] Breaking changes section filled
- **CI check:** All status checks passing?
**Cross-cutting PR Checks (all types):**
- [ ] PR title is descriptive (not just "fix" or "update")
- [ ] One concern per PR (not mixing fix + enhancement)
- [ ] No unrelated formatting changes visible in diff
- [ ] CHANGELOG.md updated
- [ ] Not using `--no-verify` or skipping hooks
**Scoring:** Same as issues — completeness percentage per PR.
</step>
<step name="check_gates">
Cross-reference issues and PRs to enforce the issue-first rule:
For each open PR:
1. Extract linked issue number from body
2. If no linked issue: **GATE VIOLATION** — PR has no issue
3. If linked issue exists, check its labels:
- Feature PR → issue must have `approved-feature`
- Enhancement PR → issue must have `approved-enhancement`
- Fix PR → issue must have `confirmed-bug`
4. If label is missing: **GATE VIOLATION** — PR opened before approval
Report gate violations prominently — these are the most important findings because
the project auto-closes PRs without proper approval gates.
</step>
<step name="generate_report">
Produce a structured triage report:
```
===================================================================
GSD INBOX TRIAGE — {repo} — {date}
===================================================================
SUMMARY
-------
Open issues: {count} Open PRs: {count}
Features: {n} Feature PRs: {n}
Enhancements:{n} Enhancement PRs: {n}
Bugs: {n} Fix PRs: {n}
Chores: {n} Wrong template: {n}
Unclassified:{n} No linked issue: {n}
GATE VIOLATIONS (action required)
---------------------------------
{For each violation:}
PR #{number}: {title}
Problem: {description — e.g., "No approved-feature label on linked issue #45"}
Action: {what to do — e.g., "Close PR or approve issue #45 first"}
ISSUES NEEDING ATTENTION
------------------------
{For each issue sorted by completeness score, lowest first:}
#{number} [{type}] {title}
Score: {percentage}% complete
Missing: {list of missing required fields}
Labels: {current labels} → Suggested: {recommended labels}
Age: {days since created}
PRS NEEDING ATTENTION
---------------------
{For each PR sorted by completeness score, lowest first:}
#{number} [{type}] {title}
Score: {percentage}% complete
Missing: {list of missing checklist items}
CI: {passing/failing/pending}
Review: {approved/changes_requested/none}
Linked issue: #{issue_number} ({issue_status})
Age: {days since created}
READY TO MERGE
--------------
{PRs that are 100% complete, CI passing, approved:}
#{number} {title} — ready
STALE ITEMS (>30 days, no activity)
------------------------------------
{Issues and PRs with no updates in 30+ days}
===================================================================
```
Write this report to `.planning/INBOX-TRIAGE.md` if a `.planning/` directory exists,
otherwise print to console only.
</step>
<step name="auto_actions">
Only execute if `--label` or `--close-incomplete` flags were set.
**If --label:**
For each issue/PR where labels are missing or incorrect:
```bash
gh issue edit {number} --add-label "{label}"
```
Or:
```bash
gh pr edit {number} --add-label "{label}"
```
Label recommendations:
- Unclassified issues → add `needs-triage`
- Feature issues without review → add `needs-review`
- Enhancement issues without review → add `needs-review`
- Bug reports without triage → add `needs-triage`
- PRs with gate violations → add `gate-violation`
**If --close-incomplete:**
For issues scoring below 50% completeness:
```bash
gh issue close {number} --comment "Closed by GSD inbox triage: this issue is missing required fields per the issue template. Missing: {list}. Please reopen with a complete submission. See CONTRIBUTING.md for requirements."
```
For PRs with gate violations:
```bash
gh pr close {number} --comment "Closed by GSD inbox triage: this PR does not meet the issue-first requirement. {specific violation}. See CONTRIBUTING.md for the correct process."
```
Always confirm with the user before closing anything:
```
AskUserQuestion:
question: "Found {N} items to close. Review the list above — proceed with closing?"
options:
- label: "Close all"
description: "Close all {N} non-compliant items with explanation comments"
- label: "Let me pick"
description: "I'll choose which ones to close"
- label: "Skip"
description: "Don't close anything — report only"
```
</step>
<step name="report">
```
───────────────────────────────────────────────────────────────
## Inbox Triage Complete
Reviewed: {issue_count} issues, {pr_count} PRs
Gate violations: {violation_count}
Ready to merge: {ready_count}
Needing attention: {attention_count}
Stale (30+ days): {stale_count}
{If report saved: "Report saved to .planning/INBOX-TRIAGE.md"}
Next steps:
- Review gate violations first — these block the contribution pipeline
- Address incomplete submissions (comment or close)
- Merge ready PRs
- Triage unclassified issues
───────────────────────────────────────────────────────────────
```
</step>
</process>
<offer_next>
After triage:
- /gsd-review — Run cross-AI peer review on a specific phase plan
- /gsd-ship — Create a PR from completed work
- /gsd-progress — See overall project state
- /gsd-inbox --label — Re-run with auto-labeling enabled
</offer_next>
<success_criteria>
- [ ] All open issues fetched and classified by type
- [ ] Each issue reviewed against its template requirements
- [ ] All open PRs fetched and classified by type
- [ ] Each PR reviewed against its template checklist
- [ ] Issue-first gate violations identified
- [ ] Structured report generated with scores and action items
- [ ] Auto-actions executed only when flagged and user-confirmed
</success_criteria>

View File

@@ -26,7 +26,7 @@ if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
Parse JSON for: `milestone_version`, `milestone_name`, `phase_count`, `completed_count`, `in_progress_count`, `phases`, `recommended_actions`, `all_complete`, `waiting_signal`, `manager_flags`. Parse JSON for: `milestone_version`, `milestone_name`, `phase_count`, `completed_count`, `in_progress_count`, `phases`, `recommended_actions`, `all_complete`, `waiting_signal`, `manager_flags`.
`manager_flags` contains per-step passthrough flags from config: `manager_flags` contains per-step passthrough flags from config:
- `manager_flags.discuss` — appended to `/gsd:discuss-phase` args (e.g. `"--auto --analyze"`) - `manager_flags.discuss` — appended to `/gsd-discuss-phase` args (e.g. `"--auto --analyze"`)
- `manager_flags.plan` — appended to plan agent init command - `manager_flags.plan` — appended to plan agent init command
- `manager_flags.execute` — appended to execute agent init command - `manager_flags.execute` — appended to execute agent init command
@@ -113,8 +113,8 @@ If `all_complete` is true:
╚══════════════════════════════════════════════════════════════╝ ╚══════════════════════════════════════════════════════════════╝
All {phase_count} phases done. Ready for final steps: All {phase_count} phases done. Ready for final steps:
→ /gsd:verify-work — run acceptance testing → /gsd-verify-work — run acceptance testing
→ /gsd:complete-milestone — archive and wrap up → /gsd-complete-milestone — archive and wrap up
``` ```
Ask user via AskUserQuestion: Ask user via AskUserQuestion:
@@ -335,11 +335,11 @@ Display final status with progress bar:
{milestone_version} — {milestone_name} {milestone_version} — {milestone_name}
{PROGRESS_BAR} {progress_pct}% ({completed_count}/{phase_count} phases) {PROGRESS_BAR} {progress_pct}% ({completed_count}/{phase_count} phases)
Resume anytime: /gsd:manager Resume anytime: /gsd-manager
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
``` ```
**Note:** Any background agents still running will continue to completion. Their results will be visible on next `/gsd:manager` or `/gsd:progress` invocation. **Note:** Any background agents still running will continue to completion. Their results will be visible on next `/gsd-manager` or `/gsd-progress` invocation.
</step> </step>

View File

@@ -140,8 +140,8 @@ Full review: {path to UI-REVIEW.md}
`/clear` then one of: `/clear` then one of:
- `/gsd:verify-work {N}` — UAT testing - `/gsd-verify-work {N}` — UAT testing
- `/gsd:plan-phase {N+1}` — plan next phase - `/gsd-plan-phase {N+1}` — plan next phase
- `/gsd-verify-work {N}` — UAT testing - `/gsd-verify-work {N}` — UAT testing
- `/gsd-plan-phase {N+1}` — plan next phase - `/gsd-plan-phase {N+1}` — plan next phase

View File

@@ -20,7 +20,7 @@ if [ -f .planning/STATE.md ]; then
echo 'STATE.md exists - check for blockers and current phase.' echo 'STATE.md exists - check for blockers and current phase.'
head -20 .planning/STATE.md head -20 .planning/STATE.md
else else
echo 'No .planning/ found - suggest /gsd:new-project if starting new work.' echo 'No .planning/ found - suggest /gsd-new-project if starting new work.'
fi fi
echo '' echo ''

View File

@@ -1,7 +1,7 @@
/** /**
* Execute-phase wave filter tests * Execute-phase wave filter tests
* *
* Validates the /gsd:execute-phase --wave feature contract: * Validates the /gsd-execute-phase --wave feature contract:
* - Command frontmatter advertises --wave * - Command frontmatter advertises --wave
* - Workflow parses WAVE_FILTER * - Workflow parses WAVE_FILTER
* - Workflow enforces lower-wave safety * - Workflow enforces lower-wave safety

View File

@@ -1,7 +1,7 @@
/** /**
* Quick task branching tests * Quick task branching tests
* *
* Validates that /gsd:quick exposes branch_name from init and that the * Validates that /gsd-quick exposes branch_name from init and that the
* workflow checks out a dedicated quick-task branch when configured. * workflow checks out a dedicated quick-task branch when configured.
*/ */

View File

@@ -1,7 +1,7 @@
/** /**
* GSD Quick Research Flag Tests * GSD Quick Research Flag Tests
* *
* Validates the --research flag for /gsd:quick: * Validates the --research flag for /gsd-quick:
* - Command frontmatter advertises --research * - Command frontmatter advertises --research
* - Workflow includes research step (Step 4.75) * - Workflow includes research step (Step 4.75)
* - Research artifacts work within quick task directories * - Research artifacts work within quick task directories

View File

@@ -0,0 +1,112 @@
/**
* Stale /gsd: colon reference detection test
*
* Guards against regression of bug #1748: after the command naming migration
* from colon to hyphen format, no stale colon references should remain in
* source, workflows, commands, docs, issue templates, or hooks.
*
* Test input strings that deliberately test colon-to-hyphen conversion are
* allowed (they are the INPUT to a converter function). Everything else is stale.
*
* Uses node:test and node:assert/strict (NOT Jest).
*/
const { test, describe } = require('node:test');
const assert = require('node:assert/strict');
const fs = require('fs');
const path = require('path');
const ROOT = path.resolve(__dirname, '..');
/**
* Recursively collect files matching the given extensions, excluding
* CHANGELOG.md, node_modules/, .git/, and dist/.
*/
function collectFiles(dir, extensions, results = []) {
const EXCLUDED_DIRS = new Set(['node_modules', '.git', 'dist', '.claude', '.worktrees']);
let entries;
try {
entries = fs.readdirSync(dir, { withFileTypes: true });
} catch {
return results;
}
for (const entry of entries) {
if (EXCLUDED_DIRS.has(entry.name)) continue;
const full = path.join(dir, entry.name);
if (entry.isDirectory()) {
collectFiles(full, extensions, results);
} else if (entry.isFile()) {
const ext = path.extname(entry.name);
if (extensions.has(ext) && entry.name !== 'CHANGELOG.md') {
results.push(full);
}
}
}
return results;
}
/**
* Determine whether a /gsd: match in a test file is a legitimate test input
* (i.e., the input string fed to a colon-to-hyphen converter).
*/
function isTestInput(filePath, line) {
const rel = path.relative(ROOT, filePath).replace(/\\/g, '/');
// SDK test files (.ts) that test sanitizer stripping of /gsd: patterns
if (rel === 'sdk/src/prompt-sanitizer.test.ts') return true;
if (rel === 'sdk/src/init-runner.test.ts') return true;
if (rel === 'sdk/src/phase-prompt.test.ts') return true;
// Conversion test files: input strings to convert* functions contain /gsd:
const conversionTestFiles = [
'tests/windsurf-conversion.test.cjs',
'tests/augment-conversion.test.cjs',
'tests/cursor-conversion.test.cjs',
'tests/antigravity-install.test.cjs',
'tests/copilot-install.test.cjs',
'tests/codex-config.test.cjs',
'tests/trae-install.test.cjs',
];
if (conversionTestFiles.includes(rel)) {
const trimmed = line.trim();
// JSDoc block-comment lines with /gsd: in description are stale
if (/^\*/.test(trimmed)) return false;
// Everything else in conversion test files is a test input
return true;
}
return false;
}
describe('No stale /gsd: colon references (#1748)', () => {
test('all /gsd: references should be hyphenated except test inputs', () => {
const extensions = new Set(['.md', '.js', '.cjs', '.ts', '.yml', '.sh', '.svg']);
const files = collectFiles(ROOT, extensions);
const staleRefs = [];
const pattern = /\/gsd:[a-z]/g;
for (const filePath of files) {
const content = fs.readFileSync(filePath, 'utf8');
const lines = content.split('\n');
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
if (!pattern.test(line)) continue;
pattern.lastIndex = 0;
if (!isTestInput(filePath, line)) {
const rel = path.relative(ROOT, filePath).replace(/\\/g, '/');
staleRefs.push(` ${rel}:${i + 1}: ${line.trim()}`);
}
}
}
if (staleRefs.length > 0) {
assert.fail(
`Found ${staleRefs.length} stale /gsd: colon reference(s) that should use /gsd- hyphen format:\n${staleRefs.join('\n')}`
);
}
});
});

View File

@@ -1,7 +1,7 @@
/** /**
* GSD Workspace Tests * GSD Workspace Tests
* *
* Tests for /gsd:new-workspace, /gsd:list-workspaces, /gsd:remove-workspace * Tests for /gsd-new-workspace, /gsd-list-workspaces, /gsd-remove-workspace
* init functions and integration with gsd-tools routing. * init functions and integration with gsd-tools routing.
*/ */