mirror of
https://github.com/glittercowboy/get-shit-done
synced 2026-04-25 17:25:23 +02:00
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:
6
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
6
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@@ -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
|
||||||
|
|||||||
6
.github/ISSUE_TEMPLATE/enhancement.yml
vendored
6
.github/ISSUE_TEMPLATE/enhancement.yml
vendored
@@ -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"
|
||||||
```
|
```
|
||||||
|
|||||||
12
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
12
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
@@ -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
|
||||||
|
|||||||
@@ -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 |
@@ -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';
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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. |
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|
||||||
|
|||||||
384
get-shit-done/workflows/inbox.md
Normal file
384
get-shit-done/workflows/inbox.md
Normal 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>
|
||||||
@@ -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>
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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 ''
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
112
tests/stale-colon-refs.test.cjs
Normal file
112
tests/stale-colon-refs.test.cjs
Normal 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')}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -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.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user