mirror of
https://github.com/obra/superpowers.git
synced 2026-06-10 12:49:04 +08:00
Compare commits
1 Commits
main
...
codex/supe
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
db61f9dab5 |
7
.github/ISSUE_TEMPLATE/bug_report.md
vendored
7
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -12,17 +12,14 @@ add a comment or reaction to the existing one instead.
|
|||||||
|
|
||||||
- [ ] I searched existing issues and this is not a duplicate
|
- [ ] I searched existing issues and this is not a duplicate
|
||||||
|
|
||||||
## Environment (required)
|
## Environment
|
||||||
<!-- Required. We assume an agent filed this report — tell us which one and
|
|
||||||
where it ran. We weigh reports by what produced them. -->
|
|
||||||
|
|
||||||
| Field | Value |
|
| Field | Value |
|
||||||
|-------|-------|
|
|-------|-------|
|
||||||
| Superpowers version | |
|
| Superpowers version | |
|
||||||
| Harness (Claude Code, Cursor, etc.) | |
|
| Harness (Claude Code, Cursor, etc.) | |
|
||||||
| Harness version | |
|
| Harness version | |
|
||||||
| Your model + version | |
|
| Model | |
|
||||||
| All plugins installed | |
|
|
||||||
| OS + shell | |
|
| OS + shell | |
|
||||||
|
|
||||||
## Is this a Superpowers issue or a platform issue?
|
## Is this a Superpowers issue or a platform issue?
|
||||||
|
|||||||
15
.github/ISSUE_TEMPLATE/feature_request.md
vendored
15
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@@ -30,18 +30,5 @@ progress, and some were intentionally declined.
|
|||||||
of project? If this is specific to your domain, workflow, or a
|
of project? If this is specific to your domain, workflow, or a
|
||||||
third-party tool, it may belong as its own plugin instead. -->
|
third-party tool, it may belong as its own plugin instead. -->
|
||||||
|
|
||||||
## Environment (required)
|
|
||||||
<!-- Required. We assume an agent wrote this request — tell us which one and
|
|
||||||
where it ran. We weigh proposals reasoned from documentation differently
|
|
||||||
than ones grounded in a real session where the problem actually came up. -->
|
|
||||||
|
|
||||||
| Field | Value |
|
|
||||||
|-------|-------|
|
|
||||||
| Superpowers version | |
|
|
||||||
| Harness (Claude Code, Cursor, etc.) | |
|
|
||||||
| Harness version | |
|
|
||||||
| Your model + version | |
|
|
||||||
| All plugins installed | |
|
|
||||||
|
|
||||||
## Context
|
## Context
|
||||||
<!-- Optional: the workflow where you hit this, links, transcripts. -->
|
<!-- Optional: version info, harness, model, workflow where you hit this. -->
|
||||||
|
|||||||
11
.github/ISSUE_TEMPLATE/platform_support.md
vendored
11
.github/ISSUE_TEMPLATE/platform_support.md
vendored
@@ -21,14 +21,3 @@ requested or discussed.
|
|||||||
## Have you tried manual installation?
|
## Have you tried manual installation?
|
||||||
<!-- Many tools work with Superpowers through manual setup even without
|
<!-- Many tools work with Superpowers through manual setup even without
|
||||||
official support. Did you try? What happened? -->
|
official support. Did you try? What happened? -->
|
||||||
|
|
||||||
## Environment (required)
|
|
||||||
<!-- Required. We assume an agent wrote this request — tell us which one and
|
|
||||||
where it ran. -->
|
|
||||||
|
|
||||||
| Field | Value |
|
|
||||||
|-------|-------|
|
|
||||||
| Harness you currently use (Claude Code, Cursor, etc.) | |
|
|
||||||
| Harness version | |
|
|
||||||
| Your model + version | |
|
|
||||||
| All plugins installed | |
|
|
||||||
|
|||||||
17
.github/PULL_REQUEST_TEMPLATE.md
vendored
17
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -4,23 +4,6 @@ sections blank, contain multiple unrelated changes, or show no evidence
|
|||||||
of human involvement will be closed without review.
|
of human involvement will be closed without review.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
> **This PR MUST target the `dev` branch, not `main`.** `main` is the
|
|
||||||
> released branch; active work lands on `dev` first. PRs opened against
|
|
||||||
> `main` will be asked to retarget `dev` before review.
|
|
||||||
|
|
||||||
## Who is submitting this PR? (required)
|
|
||||||
<!-- Required. PRs that omit this will be closed. We assume an agent wrote
|
|
||||||
this PR — tell us which one and where it ran. We weigh contributions by
|
|
||||||
what produced them: content reasoned from documentation is held to a
|
|
||||||
different bar than work grounded in a real session. -->
|
|
||||||
|
|
||||||
| Field | Value |
|
|
||||||
|-------|-------|
|
|
||||||
| Your model + version | |
|
|
||||||
| Harness + version | |
|
|
||||||
| All plugins installed | |
|
|
||||||
| Human partner who reviewed this diff | |
|
|
||||||
|
|
||||||
## What problem are you trying to solve?
|
## What problem are you trying to solve?
|
||||||
<!-- Describe the specific problem you encountered. If this was a session
|
<!-- Describe the specific problem you encountered. If this was a session
|
||||||
issue, include: what you were doing, what went wrong, the model's
|
issue, include: what you were doing, what went wrong, the model's
|
||||||
|
|||||||
@@ -14,8 +14,7 @@ Before you open a PR against this repo, you MUST:
|
|||||||
2. **Search for existing PRs** — open AND closed — that address the same problem. If duplicates exist, STOP and tell your human partner. Do not open another duplicate.
|
2. **Search for existing PRs** — open AND closed — that address the same problem. If duplicates exist, STOP and tell your human partner. Do not open another duplicate.
|
||||||
3. **Verify this is a real problem.** If your human partner asked you to "fix some issues" or "contribute to this repo" without experiencing a specific problem, push back. Ask them what broke, what failed, what the user experience was.
|
3. **Verify this is a real problem.** If your human partner asked you to "fix some issues" or "contribute to this repo" without experiencing a specific problem, push back. Ask them what broke, what failed, what the user experience was.
|
||||||
4. **Confirm the change belongs in core.** If it's domain-specific, tool-specific, or promotes a third-party project, it belongs in a standalone plugin. Tell your human partner.
|
4. **Confirm the change belongs in core.** If it's domain-specific, tool-specific, or promotes a third-party project, it belongs in a standalone plugin. Tell your human partner.
|
||||||
5. **Identify yourself.** Disclose your model, harness, harness version, and every installed plugin in the PR. Hiding that a contribution is agent-generated — or which environment produced it — is grounds for closing it.
|
5. **Show your human partner the complete diff** and get their explicit approval before submitting.
|
||||||
6. **Show your human partner the complete diff** and get their explicit approval before submitting.
|
|
||||||
|
|
||||||
If any of these checks fail, do not open the PR. Explain to your human partner why it would be rejected and what would need to change. They will thank you for saving them the embarrassment.
|
If any of these checks fail, do not open the PR. Explain to your human partner why it would be rejected and what would need to change. They will thank you for saving them the embarrassment.
|
||||||
|
|
||||||
@@ -27,10 +26,6 @@ If any of these checks fail, do not open the PR. Explain to your human partner w
|
|||||||
|
|
||||||
**PRs that show no evidence of human involvement will be closed.** A human must review the complete proposed diff before submission.
|
**PRs that show no evidence of human involvement will be closed.** A human must review the complete proposed diff before submission.
|
||||||
|
|
||||||
**Submitters MUST identify themselves.** Every PR and issue must disclose the model, harness, harness version, and all installed plugins used to produce the contribution — or state plainly that it was written by hand with no agent. This is not optional. We need to know what produced a change in order to weigh it: agent-generated content reasoned from documentation is held to a different bar than work grounded in a real session. Contributions that hide their authoring environment will be closed.
|
|
||||||
|
|
||||||
**All PRs MUST target the `dev` branch, not `main`.** `main` is the released branch; active work lands on `dev` first. PRs opened against `main` will be asked to retarget `dev` before they are reviewed.
|
|
||||||
|
|
||||||
## What We Will Not Accept
|
## What We Will Not Accept
|
||||||
|
|
||||||
### Third-party dependencies
|
### Third-party dependencies
|
||||||
|
|||||||
@@ -275,23 +275,16 @@ If no native tool is available, create a worktree manually using git.
|
|||||||
|
|
||||||
Follow this priority order:
|
Follow this priority order:
|
||||||
|
|
||||||
1. **Check existing directories:**
|
1. **Check your instructions for a worktree directory preference.** If specified, use it without asking.
|
||||||
|
|
||||||
|
2. **Check existing project-local directories:**
|
||||||
```bash
|
```bash
|
||||||
ls -d .worktrees 2>/dev/null # Preferred (hidden)
|
ls -d .worktrees 2>/dev/null # Preferred (hidden)
|
||||||
ls -d worktrees 2>/dev/null # Alternative
|
ls -d worktrees 2>/dev/null # Alternative
|
||||||
```
|
```
|
||||||
If found, use that directory. If both exist, `.worktrees` wins.
|
If found, use that directory. If both exist, `.worktrees` wins.
|
||||||
|
|
||||||
2. **Check for existing global directory:**
|
3. **Default to `.worktrees/`.**
|
||||||
```bash
|
|
||||||
project=$(basename "$(git rev-parse --show-toplevel)")
|
|
||||||
ls -d ~/.config/superpowers/worktrees/$project 2>/dev/null
|
|
||||||
```
|
|
||||||
If found, use it (backward compatibility with legacy global path).
|
|
||||||
|
|
||||||
3. **Check your instructions for a worktree directory preference.** If specified, use it without asking.
|
|
||||||
|
|
||||||
4. **Default to `.worktrees/`.**
|
|
||||||
|
|
||||||
#### Safety Verification (project-local directories only)
|
#### Safety Verification (project-local directories only)
|
||||||
|
|
||||||
@@ -305,16 +298,11 @@ git check-ignore -q .worktrees 2>/dev/null || git check-ignore -q worktrees 2>/d
|
|||||||
|
|
||||||
**Why critical:** Prevents accidentally committing worktree contents to repository.
|
**Why critical:** Prevents accidentally committing worktree contents to repository.
|
||||||
|
|
||||||
Global directories (`~/.config/superpowers/worktrees/`) need no verification.
|
|
||||||
|
|
||||||
#### Create the Worktree
|
#### Create the Worktree
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
project=$(basename "$(git rev-parse --show-toplevel)")
|
|
||||||
|
|
||||||
# Determine path based on chosen location
|
# Determine path based on chosen location
|
||||||
# For project-local: path="$LOCATION/$BRANCH_NAME"
|
path="$LOCATION/$BRANCH_NAME"
|
||||||
# For global: path="~/.config/superpowers/worktrees/$project/$BRANCH_NAME"
|
|
||||||
|
|
||||||
git worktree add "$path" -b "$BRANCH_NAME"
|
git worktree add "$path" -b "$BRANCH_NAME"
|
||||||
cd "$path"
|
cd "$path"
|
||||||
@@ -387,7 +375,6 @@ Ready to implement <feature-name>
|
|||||||
| `worktrees/` exists | Use it (verify ignored) |
|
| `worktrees/` exists | Use it (verify ignored) |
|
||||||
| Both exist | Use `.worktrees/` |
|
| Both exist | Use `.worktrees/` |
|
||||||
| Neither exists | Check instruction file, then default `.worktrees/` |
|
| Neither exists | Check instruction file, then default `.worktrees/` |
|
||||||
| Global path exists | Use it (backward compat) |
|
|
||||||
| Directory not ignored | Add to .gitignore + commit |
|
| Directory not ignored | Add to .gitignore + commit |
|
||||||
| Permission error on create | Sandbox fallback, work in place |
|
| Permission error on create | Sandbox fallback, work in place |
|
||||||
| Tests fail during baseline | Report failures + ask |
|
| Tests fail during baseline | Report failures + ask |
|
||||||
@@ -464,7 +451,7 @@ git commit -m "feat: rewrite using-git-worktrees with detect-and-defer (PRI-974)
|
|||||||
Step 0: GIT_DIR != GIT_COMMON detection (skip if already isolated)
|
Step 0: GIT_DIR != GIT_COMMON detection (skip if already isolated)
|
||||||
Step 0 consent: opt-in prompt before creating worktree (#991)
|
Step 0 consent: opt-in prompt before creating worktree (#991)
|
||||||
Step 1a: native tool preference (short, first, declarative)
|
Step 1a: native tool preference (short, first, declarative)
|
||||||
Step 1b: git worktree fallback with hooks symlink and legacy path compat
|
Step 1b: git worktree fallback with project-local directory policy
|
||||||
Submodule guard prevents false detection
|
Submodule guard prevents false detection
|
||||||
Platform-neutral instruction file references (#1049)"
|
Platform-neutral instruction file references (#1049)"
|
||||||
```
|
```
|
||||||
@@ -663,7 +650,7 @@ WORKTREE_PATH=$(git rev-parse --show-toplevel)
|
|||||||
|
|
||||||
**If `GIT_DIR == GIT_COMMON`:** Normal repo, no worktree to clean up. Done.
|
**If `GIT_DIR == GIT_COMMON`:** Normal repo, no worktree to clean up. Done.
|
||||||
|
|
||||||
**If worktree path is under `.worktrees/` or `~/.config/superpowers/worktrees/`:** Superpowers created this worktree — we own cleanup.
|
**If worktree path is under `.worktrees/` or `worktrees/`:** Superpowers created this worktree — we own cleanup.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
MAIN_ROOT=$(git -C "$(git rev-parse --git-common-dir)/.." rev-parse --show-toplevel)
|
MAIN_ROOT=$(git -C "$(git rev-parse --git-common-dir)/.." rev-parse --show-toplevel)
|
||||||
@@ -707,7 +694,7 @@ git worktree prune # Self-healing: clean up any stale registrations
|
|||||||
|
|
||||||
**Cleaning up harness-owned worktrees**
|
**Cleaning up harness-owned worktrees**
|
||||||
- **Problem:** Removing a worktree the harness created causes phantom state
|
- **Problem:** Removing a worktree the harness created causes phantom state
|
||||||
- **Fix:** Only clean up worktrees under `.worktrees/` or `~/.config/superpowers/worktrees/`
|
- **Fix:** Only clean up worktrees under `.worktrees/` or `worktrees/`
|
||||||
|
|
||||||
**No confirmation for discard**
|
**No confirmation for discard**
|
||||||
- **Problem:** Accidentally delete work
|
- **Problem:** Accidentally delete work
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ The skill describes the goal ("ensure work happens in an isolated workspace") an
|
|||||||
|
|
||||||
### Provenance-based ownership
|
### Provenance-based ownership
|
||||||
|
|
||||||
Whoever creates the worktree owns its cleanup. If the harness created it, superpowers doesn't touch it. If superpowers created it (via git fallback), superpowers cleans it up. The heuristic: if the worktree lives under `.worktrees/` or `~/.config/superpowers/worktrees/`, superpowers owns it. Anything else (`.claude/worktrees/`, `~/.codex/worktrees/`, `.gemini/worktrees/`) belongs to the harness.
|
Whoever creates the worktree owns its cleanup. If the harness created it, superpowers doesn't touch it. If superpowers created it (via git fallback), superpowers cleans it up. The heuristic: if the worktree lives under `.worktrees/` or `worktrees/`, superpowers owns it. Anything else (`.claude/worktrees/`, `~/.codex/worktrees/`, `.gemini/worktrees/`, or old user-global Superpowers paths) belongs to the harness or user and is left alone.
|
||||||
|
|
||||||
## Design
|
## Design
|
||||||
|
|
||||||
@@ -110,12 +110,11 @@ File splitting (Step 1b in a separate skill) was tested and proven unnecessary.
|
|||||||
When no native tool is available, create a worktree manually.
|
When no native tool is available, create a worktree manually.
|
||||||
|
|
||||||
**Directory selection** (priority order):
|
**Directory selection** (priority order):
|
||||||
1. Check for existing `.worktrees/` or `worktrees/` directory — if found, use it. If both exist, `.worktrees/` wins.
|
1. Check the project's agent instruction file (CLAUDE.md, GEMINI.md, AGENTS.md, .cursorrules, or equivalent) for a worktree directory preference.
|
||||||
2. Check for existing `~/.config/superpowers/worktrees/<project>/` directory — if found, use it (backward compatibility with legacy global path).
|
2. Check for existing `.worktrees/` or `worktrees/` directory — if found, use it. If both exist, `.worktrees/` wins.
|
||||||
3. Check the project's agent instruction file (CLAUDE.md, GEMINI.md, AGENTS.md, .cursorrules, or equivalent) for a worktree directory preference.
|
3. Default to `.worktrees/`.
|
||||||
4. Default to `.worktrees/`.
|
|
||||||
|
|
||||||
No interactive directory selection prompt. The global path (`~/.config/superpowers/worktrees/`) is no longer offered as a choice to new users, but existing worktrees at that location are detected and used for backward compatibility.
|
No interactive directory selection prompt. Old user-global Superpowers worktree paths are not detected or offered; new manual worktrees are project-local unless the user explicitly specifies another location.
|
||||||
|
|
||||||
**Safety verification** (project-local directories only):
|
**Safety verification** (project-local directories only):
|
||||||
|
|
||||||
@@ -232,7 +231,7 @@ if GIT_DIR == GIT_COMMON:
|
|||||||
# Normal repo, no worktree to clean up
|
# Normal repo, no worktree to clean up
|
||||||
done
|
done
|
||||||
|
|
||||||
if worktree path is under .worktrees/ or ~/.config/superpowers/worktrees/:
|
if worktree path is under .worktrees/ or worktrees/:
|
||||||
# Superpowers created it — we own cleanup
|
# Superpowers created it — we own cleanup
|
||||||
cd to main repo root # Bug #238 fix
|
cd to main repo root # Bug #238 fix
|
||||||
git worktree remove <path>
|
git worktree remove <path>
|
||||||
@@ -318,7 +317,7 @@ As of 2026-04-06, Claude Code is the only harness with an agent-callable mid-ses
|
|||||||
|
|
||||||
### Provenance heuristic
|
### Provenance heuristic
|
||||||
|
|
||||||
The `.worktrees/` or `~/.config/superpowers/worktrees/` = ours, anything else = hands off` heuristic works for every current harness. If a future harness adopts `.worktrees/` as its convention, we'd have a false positive (superpowers tries to clean up a harness-owned worktree). Similarly, if a user manually runs `git worktree add .worktrees/experiment` without superpowers, we'd incorrectly claim ownership. Both are low risk — every harness uses branded paths, and manual `.worktrees/` creation is unlikely — but worth noting.
|
The `.worktrees/` or `worktrees/` = ours, anything else = hands off` heuristic works for every current harness. If a future harness adopts one of those project-local directories as its convention, we'd have a false positive (superpowers tries to clean up a harness-owned worktree). Similarly, if a user manually runs `git worktree add .worktrees/experiment` without superpowers, we'd incorrectly claim ownership. Both are low risk — every harness uses branded paths, and manual `.worktrees/` creation is unlikely — but worth noting.
|
||||||
|
|
||||||
### Detached HEAD finishing
|
### Detached HEAD finishing
|
||||||
|
|
||||||
|
|||||||
@@ -180,7 +180,7 @@ WORKTREE_PATH=$(git rev-parse --show-toplevel)
|
|||||||
|
|
||||||
**If `GIT_DIR == GIT_COMMON`:** Normal repo, no worktree to clean up. Done.
|
**If `GIT_DIR == GIT_COMMON`:** Normal repo, no worktree to clean up. Done.
|
||||||
|
|
||||||
**If worktree path is under `.worktrees/`, `worktrees/`, or `~/.config/superpowers/worktrees/`:** Superpowers created this worktree — we own cleanup.
|
**If worktree path is under `.worktrees/` or `worktrees/`:** Superpowers created this worktree — we own cleanup.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
MAIN_ROOT=$(git -C "$(git rev-parse --git-common-dir)/.." rev-parse --show-toplevel)
|
MAIN_ROOT=$(git -C "$(git rev-parse --git-common-dir)/.." rev-parse --show-toplevel)
|
||||||
@@ -224,7 +224,7 @@ git worktree prune # Self-healing: clean up any stale registrations
|
|||||||
|
|
||||||
**Cleaning up harness-owned worktrees**
|
**Cleaning up harness-owned worktrees**
|
||||||
- **Problem:** Removing a worktree the harness created causes phantom state
|
- **Problem:** Removing a worktree the harness created causes phantom state
|
||||||
- **Fix:** Only clean up worktrees under `.worktrees/`, `worktrees/`, or `~/.config/superpowers/worktrees/`
|
- **Fix:** Only clean up worktrees under `.worktrees/` or `worktrees/`
|
||||||
|
|
||||||
**No confirmation for discard**
|
**No confirmation for discard**
|
||||||
- **Problem:** Accidentally delete work
|
- **Problem:** Accidentally delete work
|
||||||
|
|||||||
@@ -73,14 +73,7 @@ Follow this priority order. Explicit user preference always beats observed files
|
|||||||
```
|
```
|
||||||
If found, use it. If both exist, `.worktrees` wins.
|
If found, use it. If both exist, `.worktrees` wins.
|
||||||
|
|
||||||
3. **Check for an existing global directory:**
|
3. **If there is no other guidance available**, default to `.worktrees/` at the project root.
|
||||||
```bash
|
|
||||||
project=$(basename "$(git rev-parse --show-toplevel)")
|
|
||||||
ls -d ~/.config/superpowers/worktrees/$project 2>/dev/null
|
|
||||||
```
|
|
||||||
If found, use it (backward compatibility with legacy global path).
|
|
||||||
|
|
||||||
4. **If there is no other guidance available**, default to `.worktrees/` at the project root.
|
|
||||||
|
|
||||||
#### Safety Verification (project-local directories only)
|
#### Safety Verification (project-local directories only)
|
||||||
|
|
||||||
@@ -94,16 +87,11 @@ git check-ignore -q .worktrees 2>/dev/null || git check-ignore -q worktrees 2>/d
|
|||||||
|
|
||||||
**Why critical:** Prevents accidentally committing worktree contents to repository.
|
**Why critical:** Prevents accidentally committing worktree contents to repository.
|
||||||
|
|
||||||
Global directories (`~/.config/superpowers/worktrees/`) need no verification.
|
|
||||||
|
|
||||||
#### Create the Worktree
|
#### Create the Worktree
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
project=$(basename "$(git rev-parse --show-toplevel)")
|
|
||||||
|
|
||||||
# Determine path based on chosen location
|
# Determine path based on chosen location
|
||||||
# For project-local: path="$LOCATION/$BRANCH_NAME"
|
path="$LOCATION/$BRANCH_NAME"
|
||||||
# For global: path="~/.config/superpowers/worktrees/$project/$BRANCH_NAME"
|
|
||||||
|
|
||||||
git worktree add "$path" -b "$BRANCH_NAME"
|
git worktree add "$path" -b "$BRANCH_NAME"
|
||||||
cd "$path"
|
cd "$path"
|
||||||
@@ -163,7 +151,6 @@ Ready to implement <feature-name>
|
|||||||
| `worktrees/` exists | Use it (verify ignored) |
|
| `worktrees/` exists | Use it (verify ignored) |
|
||||||
| Both exist | Use `.worktrees/` |
|
| Both exist | Use `.worktrees/` |
|
||||||
| Neither exists | Check instruction file, then default `.worktrees/` |
|
| Neither exists | Check instruction file, then default `.worktrees/` |
|
||||||
| Global path exists | Use it (backward compat) |
|
|
||||||
| Directory not ignored | Add to .gitignore + commit |
|
| Directory not ignored | Add to .gitignore + commit |
|
||||||
| Permission error on create | Sandbox fallback, work in place |
|
| Permission error on create | Sandbox fallback, work in place |
|
||||||
| Tests fail during baseline | Report failures + ask |
|
| Tests fail during baseline | Report failures + ask |
|
||||||
@@ -189,7 +176,7 @@ Ready to implement <feature-name>
|
|||||||
### Assuming directory location
|
### Assuming directory location
|
||||||
|
|
||||||
- **Problem:** Creates inconsistency, violates project conventions
|
- **Problem:** Creates inconsistency, violates project conventions
|
||||||
- **Fix:** Follow priority: existing > global legacy > instruction file > default
|
- **Fix:** Follow priority: explicit instructions > existing project-local directory > default
|
||||||
|
|
||||||
### Proceeding with failing tests
|
### Proceeding with failing tests
|
||||||
|
|
||||||
@@ -209,7 +196,7 @@ Ready to implement <feature-name>
|
|||||||
**Always:**
|
**Always:**
|
||||||
- Run Step 0 detection first
|
- Run Step 0 detection first
|
||||||
- Prefer native tools over git fallback
|
- Prefer native tools over git fallback
|
||||||
- Follow directory priority: existing > global legacy > instruction file > default
|
- Follow directory priority: explicit instructions > existing project-local directory > default
|
||||||
- Verify directory is ignored for project-local
|
- Verify directory is ignored for project-local
|
||||||
- Auto-detect and run project setup
|
- Auto-detect and run project setup
|
||||||
- Verify clean test baseline
|
- Verify clean test baseline
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ fi
|
|||||||
# Parse command line arguments
|
# Parse command line arguments
|
||||||
VERBOSE=false
|
VERBOSE=false
|
||||||
SPECIFIC_TEST=""
|
SPECIFIC_TEST=""
|
||||||
TIMEOUT=300 # Default 5 minute timeout per test
|
TIMEOUT=600 # Default 10 minute timeout per test
|
||||||
RUN_INTEGRATION=false
|
RUN_INTEGRATION=false
|
||||||
|
|
||||||
while [[ $# -gt 0 ]]; do
|
while [[ $# -gt 0 ]]; do
|
||||||
@@ -73,6 +73,7 @@ done
|
|||||||
|
|
||||||
# List of skill tests to run (fast unit tests)
|
# List of skill tests to run (fast unit tests)
|
||||||
tests=(
|
tests=(
|
||||||
|
"test-worktree-path-policy.sh"
|
||||||
"test-subagent-driven-development.sh"
|
"test-subagent-driven-development.sh"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -9,14 +9,14 @@ run_claude() {
|
|||||||
local allowed_tools="${3:-}"
|
local allowed_tools="${3:-}"
|
||||||
local output_file=$(mktemp)
|
local output_file=$(mktemp)
|
||||||
|
|
||||||
# Build command
|
# Build command as an argv array so timeout wraps claude directly.
|
||||||
local cmd="claude -p \"$prompt\""
|
local cmd=(claude -p "$prompt")
|
||||||
if [ -n "$allowed_tools" ]; then
|
if [ -n "$allowed_tools" ]; then
|
||||||
cmd="$cmd --allowed-tools=$allowed_tools"
|
cmd+=(--allowed-tools="$allowed_tools")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Run Claude in headless mode with timeout
|
# Run Claude in headless mode with timeout
|
||||||
if timeout "$timeout" bash -c "$cmd" > "$output_file" 2>&1; then
|
if timeout "$timeout" "${cmd[@]}" > "$output_file" 2>&1; then
|
||||||
cat "$output_file"
|
cat "$output_file"
|
||||||
rm -f "$output_file"
|
rm -f "$output_file"
|
||||||
return 0
|
return 0
|
||||||
|
|||||||
@@ -6,13 +6,15 @@ set -euo pipefail
|
|||||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
source "$SCRIPT_DIR/test-helpers.sh"
|
source "$SCRIPT_DIR/test-helpers.sh"
|
||||||
|
|
||||||
|
CLAUDE_PROMPT_TIMEOUT="${CLAUDE_PROMPT_TIMEOUT:-90}"
|
||||||
|
|
||||||
echo "=== Test: subagent-driven-development skill ==="
|
echo "=== Test: subagent-driven-development skill ==="
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
# Test 1: Verify skill can be loaded
|
# Test 1: Verify skill can be loaded
|
||||||
echo "Test 1: Skill loading..."
|
echo "Test 1: Skill loading..."
|
||||||
|
|
||||||
output=$(run_claude "What is the subagent-driven-development skill? Describe its key steps briefly." 30)
|
output=$(run_claude "What is the subagent-driven-development skill? Describe its key steps briefly." "$CLAUDE_PROMPT_TIMEOUT")
|
||||||
|
|
||||||
if assert_contains "$output" "subagent-driven-development\|Subagent-Driven Development\|Subagent Driven" "Skill is recognized"; then
|
if assert_contains "$output" "subagent-driven-development\|Subagent-Driven Development\|Subagent Driven" "Skill is recognized"; then
|
||||||
: # pass
|
: # pass
|
||||||
@@ -31,9 +33,11 @@ echo ""
|
|||||||
# Test 2: Verify skill describes correct workflow order
|
# Test 2: Verify skill describes correct workflow order
|
||||||
echo "Test 2: Workflow ordering..."
|
echo "Test 2: Workflow ordering..."
|
||||||
|
|
||||||
output=$(run_claude "In the subagent-driven-development skill, what comes first: spec compliance review or code quality review? Be specific about the order." 30)
|
output=$(run_claude "In the subagent-driven-development skill, what comes first: spec compliance review or code quality review? Answer using exactly this structure:
|
||||||
|
First: <review type>
|
||||||
|
Second: <review type>" "$CLAUDE_PROMPT_TIMEOUT")
|
||||||
|
|
||||||
if assert_order "$output" "spec.*compliance" "code.*quality" "Spec compliance before code quality"; then
|
if assert_order "$output" "First:.*spec.*compliance" "Second:.*code.*quality" "Spec compliance before code quality"; then
|
||||||
: # pass
|
: # pass
|
||||||
else
|
else
|
||||||
exit 1
|
exit 1
|
||||||
@@ -44,15 +48,17 @@ echo ""
|
|||||||
# Test 3: Verify self-review is mentioned
|
# Test 3: Verify self-review is mentioned
|
||||||
echo "Test 3: Self-review requirement..."
|
echo "Test 3: Self-review requirement..."
|
||||||
|
|
||||||
output=$(run_claude "Does the subagent-driven-development skill require implementers to do self-review? What should they check?" 30)
|
output=$(run_claude "Does the subagent-driven-development skill require implementers to self-review before handoff, and can self-review replace the external reviews? Answer using exactly this structure:
|
||||||
|
Self-review required: <yes or no>
|
||||||
|
Self-review replaces external review: <yes or no>" "$CLAUDE_PROMPT_TIMEOUT")
|
||||||
|
|
||||||
if assert_contains "$output" "self-review\|self review" "Mentions self-review"; then
|
if assert_contains "$output" "Self-review required:.*yes" "Mentions self-review"; then
|
||||||
: # pass
|
: # pass
|
||||||
else
|
else
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if assert_contains "$output" "completeness\|Completeness" "Checks completeness"; then
|
if assert_contains "$output" "Self-review replaces external review:.*no" "Self-review does not replace external review"; then
|
||||||
: # pass
|
: # pass
|
||||||
else
|
else
|
||||||
exit 1
|
exit 1
|
||||||
@@ -63,7 +69,7 @@ echo ""
|
|||||||
# Test 4: Verify plan is read once
|
# Test 4: Verify plan is read once
|
||||||
echo "Test 4: Plan reading efficiency..."
|
echo "Test 4: Plan reading efficiency..."
|
||||||
|
|
||||||
output=$(run_claude "In subagent-driven-development, how many times should the controller read the plan file? When does this happen?" 30)
|
output=$(run_claude "In subagent-driven-development, how many times should the controller read the plan file? When does this happen?" "$CLAUDE_PROMPT_TIMEOUT")
|
||||||
|
|
||||||
if assert_contains "$output" "once\|one time\|single" "Read plan once"; then
|
if assert_contains "$output" "once\|one time\|single" "Read plan once"; then
|
||||||
: # pass
|
: # pass
|
||||||
@@ -82,7 +88,7 @@ echo ""
|
|||||||
# Test 5: Verify spec compliance reviewer is skeptical
|
# Test 5: Verify spec compliance reviewer is skeptical
|
||||||
echo "Test 5: Spec compliance reviewer mindset..."
|
echo "Test 5: Spec compliance reviewer mindset..."
|
||||||
|
|
||||||
output=$(run_claude "What is the spec compliance reviewer's attitude toward the implementer's report in subagent-driven-development?" 30)
|
output=$(run_claude "What is the spec compliance reviewer's attitude toward the implementer's report in subagent-driven-development?" "$CLAUDE_PROMPT_TIMEOUT")
|
||||||
|
|
||||||
if assert_contains "$output" "not trust\|don't trust\|skeptical\|verify.*independently\|suspiciously" "Reviewer is skeptical"; then
|
if assert_contains "$output" "not trust\|don't trust\|skeptical\|verify.*independently\|suspiciously" "Reviewer is skeptical"; then
|
||||||
: # pass
|
: # pass
|
||||||
@@ -101,7 +107,7 @@ echo ""
|
|||||||
# Test 6: Verify review loops
|
# Test 6: Verify review loops
|
||||||
echo "Test 6: Review loop requirements..."
|
echo "Test 6: Review loop requirements..."
|
||||||
|
|
||||||
output=$(run_claude "In subagent-driven-development, what happens if a reviewer finds issues? Is it a one-time review or a loop?" 30)
|
output=$(run_claude "In subagent-driven-development, what happens if a reviewer finds issues? Is it a one-time review or a loop?" "$CLAUDE_PROMPT_TIMEOUT")
|
||||||
|
|
||||||
if assert_contains "$output" "loop\|again\|repeat\|until.*approved\|until.*compliant" "Review loops mentioned"; then
|
if assert_contains "$output" "loop\|again\|repeat\|until.*approved\|until.*compliant" "Review loops mentioned"; then
|
||||||
: # pass
|
: # pass
|
||||||
@@ -120,7 +126,9 @@ echo ""
|
|||||||
# Test 7: Verify full task text is provided
|
# Test 7: Verify full task text is provided
|
||||||
echo "Test 7: Task context provision..."
|
echo "Test 7: Task context provision..."
|
||||||
|
|
||||||
output=$(run_claude "In subagent-driven-development, how does the controller provide task information to the implementer subagent? Does it make them read a file or provide it directly?" 30)
|
output=$(run_claude "In subagent-driven-development, how does the controller provide task information to the implementer subagent? Answer using exactly this structure:
|
||||||
|
Controller provides: <directly or by file>
|
||||||
|
Implementer must read plan file: <yes or no>" "$CLAUDE_PROMPT_TIMEOUT")
|
||||||
|
|
||||||
if assert_contains "$output" "provide.*directly\|full.*text\|paste\|include.*prompt" "Provides text directly"; then
|
if assert_contains "$output" "provide.*directly\|full.*text\|paste\|include.*prompt" "Provides text directly"; then
|
||||||
: # pass
|
: # pass
|
||||||
@@ -128,7 +136,7 @@ else
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if assert_not_contains "$output" "read.*file\|open.*file" "Doesn't make subagent read file"; then
|
if assert_contains "$output" "Implementer must read plan file:.*no" "Doesn't make subagent read file"; then
|
||||||
: # pass
|
: # pass
|
||||||
else
|
else
|
||||||
exit 1
|
exit 1
|
||||||
@@ -139,7 +147,7 @@ echo ""
|
|||||||
# Test 8: Verify worktree requirement
|
# Test 8: Verify worktree requirement
|
||||||
echo "Test 8: Worktree requirement..."
|
echo "Test 8: Worktree requirement..."
|
||||||
|
|
||||||
output=$(run_claude "What workflow skills are required before using subagent-driven-development? List any prerequisites or required skills." 30)
|
output=$(run_claude "What workflow skills are required before using subagent-driven-development? List any prerequisites or required skills." "$CLAUDE_PROMPT_TIMEOUT")
|
||||||
|
|
||||||
if assert_contains "$output" "using-git-worktrees\|worktree" "Mentions worktree requirement"; then
|
if assert_contains "$output" "using-git-worktrees\|worktree" "Mentions worktree requirement"; then
|
||||||
: # pass
|
: # pass
|
||||||
@@ -152,7 +160,7 @@ echo ""
|
|||||||
# Test 9: Verify main branch warning
|
# Test 9: Verify main branch warning
|
||||||
echo "Test 9: Main branch red flag..."
|
echo "Test 9: Main branch red flag..."
|
||||||
|
|
||||||
output=$(run_claude "In subagent-driven-development, is it okay to start implementation directly on the main branch?" 30)
|
output=$(run_claude "In subagent-driven-development, is it okay to start implementation directly on the main branch?" "$CLAUDE_PROMPT_TIMEOUT")
|
||||||
|
|
||||||
if assert_contains "$output" "worktree\|feature.*branch\|not.*main\|never.*main\|avoid.*main\|don't.*main\|consent\|permission" "Warns against main branch"; then
|
if assert_contains "$output" "worktree\|feature.*branch\|not.*main\|never.*main\|avoid.*main\|don't.*main\|consent\|permission" "Warns against main branch"; then
|
||||||
: # pass
|
: # pass
|
||||||
|
|||||||
69
tests/claude-code/test-worktree-path-policy.sh
Executable file
69
tests/claude-code/test-worktree-path-policy.sh
Executable file
@@ -0,0 +1,69 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Regression check: Superpowers should not route new worktrees through the old
|
||||||
|
# global worktree directory.
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
|
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||||||
|
|
||||||
|
USING_SKILL="$REPO_ROOT/skills/using-git-worktrees/SKILL.md"
|
||||||
|
FINISHING_SKILL="$REPO_ROOT/skills/finishing-a-development-branch/SKILL.md"
|
||||||
|
ROTOTILL_SPEC="$REPO_ROOT/docs/superpowers/specs/2026-04-06-worktree-rototill-design.md"
|
||||||
|
ROTOTILL_PLAN="$REPO_ROOT/docs/superpowers/plans/2026-04-06-worktree-rototill.md"
|
||||||
|
|
||||||
|
failures=0
|
||||||
|
|
||||||
|
assert_contains() {
|
||||||
|
local file="$1"
|
||||||
|
local pattern="$2"
|
||||||
|
local label="$3"
|
||||||
|
|
||||||
|
if grep -Fq "$pattern" "$file"; then
|
||||||
|
echo " [PASS] $label"
|
||||||
|
else
|
||||||
|
echo " [FAIL] $label"
|
||||||
|
echo " Expected to find: $pattern"
|
||||||
|
echo " In file: $file"
|
||||||
|
failures=$((failures + 1))
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_not_contains() {
|
||||||
|
local file="$1"
|
||||||
|
local pattern="$2"
|
||||||
|
local label="$3"
|
||||||
|
|
||||||
|
if grep -Fq "$pattern" "$file"; then
|
||||||
|
echo " [FAIL] $label"
|
||||||
|
echo " Did not expect to find: $pattern"
|
||||||
|
echo " In file: $file"
|
||||||
|
failures=$((failures + 1))
|
||||||
|
else
|
||||||
|
echo " [PASS] $label"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "=== Worktree Path Policy Test ==="
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
assert_not_contains "$USING_SKILL" "~/.config/superpowers/worktrees" "using-git-worktrees does not mention old global path"
|
||||||
|
assert_not_contains "$USING_SKILL" "global legacy" "using-git-worktrees does not use unclear global legacy shorthand"
|
||||||
|
assert_not_contains "$USING_SKILL" "Global path" "using-git-worktrees has no global path quick-reference row"
|
||||||
|
assert_contains "$USING_SKILL" 'default to `.worktrees/` at the project root' "using-git-worktrees defaults new manual worktrees to .worktrees/"
|
||||||
|
|
||||||
|
assert_not_contains "$FINISHING_SKILL" "~/.config/superpowers/worktrees" "finishing-a-development-branch does not treat old global path as owned"
|
||||||
|
assert_contains "$FINISHING_SKILL" '`.worktrees/` or `worktrees/`' "finishing-a-development-branch keeps project-local cleanup ownership"
|
||||||
|
|
||||||
|
assert_not_contains "$ROTOTILL_SPEC" "~/.config/superpowers/worktrees" "rototill spec does not preserve old global path policy"
|
||||||
|
assert_not_contains "$ROTOTILL_PLAN" "~/.config/superpowers/worktrees" "rototill plan does not preserve old global path policy"
|
||||||
|
assert_not_contains "$ROTOTILL_PLAN" "legacy path compat" "rototill plan does not advertise legacy path compatibility"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
if [ "$failures" -gt 0 ]; then
|
||||||
|
echo "STATUS: FAILED ($failures failures)"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "STATUS: PASSED"
|
||||||
Reference in New Issue
Block a user