refactor(implement-issue): replace @{prompt} placeholder with {prompt} and remove deprecated --agent flag
Replace the `@{prompt}` placeholder with `{prompt}` across all skill docs and
agent-cli configs, remove the deprecated `--agent` flag from the invocation
syntax, delete the now-obsolete agent-cli test file, clarify that only one
triage label should be active at a time, and defer prompt-file cleanup to the
OS/child instead of removing it immediately after tmux launch.
This commit is contained in:
@@ -13,11 +13,10 @@ The issue tracker conventions live in [`docs/agents/issue-tracker.md`](../../../
|
||||
## Invocation
|
||||
|
||||
```
|
||||
/skill:implement-issue <N> [--agent <name>] [--base <branch>] [--force]
|
||||
/skill:implement-issue <N> [--base <branch>] [--force]
|
||||
```
|
||||
|
||||
- `<N>` — required, the issue number
|
||||
- `--agent <name>` — **DEPRECATED**: this argument is ignored. The agent CLI is read from `docs/agents/agent-cli.md`, which is set up by `/setup-skills` Section E. Rerun `/setup-skills` to change the agent.
|
||||
- `--base <branch>` — optional, target base branch (default: repo default branch).
|
||||
- `--force` — optional, allow overwriting an existing worktree.
|
||||
|
||||
@@ -119,7 +118,7 @@ Stop.
|
||||
|
||||
#### 2a. Label the issue `in-progress`
|
||||
|
||||
Apply the `in-progress` triage label.
|
||||
Change the issue triage labels to `in-progress`
|
||||
|
||||
#### 2b. Create the worktree
|
||||
|
||||
@@ -131,7 +130,7 @@ git worktree add -b <branch-name> ../<repo-name>-issue-<N> <base>
|
||||
|
||||
Assemble a single prompt that the child agent will receive. Include:
|
||||
|
||||
- **Issue body** — the full markdown body from `tea issue <N> -o json`
|
||||
- **Issue body** — the full markdown body of the issue.
|
||||
- **Comments** — all comments, if any
|
||||
- **Standing instruction**: "Implement using TDD: write a failing test first, make it pass, refactor. Explore the codebase before writing code. Respect ADRs and the project domain glossary. Set up the project (install dependencies, build) before starting. The issue body may contain Implementation Decisions and Testing Decisions sections — treat these as constraints."
|
||||
- **Context**: "Base branch: `<base>`. Target your PR at `<base>`. Branch name: `<branch-name>`."
|
||||
@@ -143,9 +142,10 @@ Assemble a single prompt that the child agent will receive. Include:
|
||||
5. Commit with conventional commits (`feat:` for enhancement, `fix:` for bug) referencing `(#<N>)`
|
||||
6. Push the branch: `git push origin <branch-name>`
|
||||
7. Create a PR with: link to the issue, one-sentence summary, short key-changes list
|
||||
8. Comment on the issue with the PR link: `tea comment <N> "PR opened: <url>"`
|
||||
9. Change the issue label to `needs-review`: `tea issues edit <N> --add-labels "needs-review" --remove-labels "in-progress"`
|
||||
10. Print `DONE — issue #<N>`
|
||||
8. Comment on the issue with the PR link: `"PR opened: <url>"`
|
||||
9. Change the issue triage label to `needs-review`
|
||||
10. remove the prompt file from `/tmp` (the child may have already read it)
|
||||
11. Print `DONE — issue #<N>`
|
||||
- **Failure instruction**: "If any step fails, report where you stopped and what remains for manual recovery. Print the exact commands needed."
|
||||
|
||||
Write the full prompt to a temp file:
|
||||
@@ -170,46 +170,49 @@ If available, use `mise x --allow-env='*' --` as the runner prefix. Otherwise, f
|
||||
|
||||
#### 4b. Compose the agent command
|
||||
|
||||
Substitute `@{prompt}` in the configured `args` with the absolute path to the temp prompt file:
|
||||
Substitute `{prompt}` in the configured `args` with the absolute path to the temp prompt file. The prompt file path is `/tmp/issue-<N>-prompt.md`:
|
||||
|
||||
- If `args` is non-empty: the agent command is `<binary> <substituted-args>`
|
||||
- If `args` is empty (stdin-piping agents): the agent command is `cat <prompt-file> | <binary>`
|
||||
```bash
|
||||
prompt_file="/tmp/issue-<N>-prompt.md"
|
||||
substituted_args="${args//\{prompt\}/$prompt_file}"
|
||||
```
|
||||
|
||||
- If `args` was non-empty: the agent command is `<binary> $substituted_args`
|
||||
- If `args` was empty (stdin-piping agents): the agent command is `cat $prompt_file | <binary>`
|
||||
|
||||
#### 4c. Compose the full tmux command
|
||||
|
||||
Use `$substituted_args` from step 4b:
|
||||
|
||||
```bash
|
||||
tmux new-window -n "issue-<N>-<repo-slug>" -c <absolute-worktree-path> "<runner-prefix> <agent-command>"
|
||||
tmux new-window -n "issue-<N>-<repo-slug>" -c <absolute-worktree-path> "<runner-prefix> <binary> $substituted_args"
|
||||
```
|
||||
|
||||
**With mise:**
|
||||
```bash
|
||||
tmux new-window -n "issue-<N>-<repo>" -c /path/to/worktree "mise x --allow-env='*' -- <binary> <args-with-prompt-subbed>"
|
||||
tmux new-window -n "issue-<N>-<repo>" -c /path/to/worktree "mise x --allow-env='*' -- $binary $substituted_args"
|
||||
```
|
||||
|
||||
**Without mise (fallback):**
|
||||
```bash
|
||||
tmux new-window -n "issue-<N>-<repo>" -c /path/to/worktree "$SHELL -c '<binary> <args-with-prompt-subbed>'"
|
||||
tmux new-window -n "issue-<N>-<repo>" -c /path/to/worktree "$SHELL -c '$binary $substituted_args'"
|
||||
```
|
||||
|
||||
For stdin-piping agents (empty args), wrap the pipe command:
|
||||
For stdin-piping agents (empty args), use the pipe form:
|
||||
|
||||
**With mise:**
|
||||
```bash
|
||||
tmux new-window -n "issue-<N>-<repo>" -c /path/to/worktree "mise x --allow-env='*' -- sh -c 'cat <prompt-file> | <binary>'"
|
||||
tmux new-window -n "issue-<N>-<repo>" -c /path/to/worktree "mise x --allow-env='*' -- sh -c 'cat $prompt_file | $binary'"
|
||||
```
|
||||
|
||||
**Without mise:**
|
||||
```bash
|
||||
tmux new-window -n "issue-<N>-<repo>" -c /path/to/worktree "$SHELL -c 'cat <prompt-file> | <binary>'"
|
||||
tmux new-window -n "issue-<N>-<repo>" -c /path/to/worktree "$SHELL -c 'cat $prompt_file | $binary'"
|
||||
```
|
||||
|
||||
The window stays open after the child completes so the user can review the output.
|
||||
|
||||
After tmux launches, clean up the temp file:
|
||||
|
||||
```bash
|
||||
rm /tmp/issue-<N>-prompt.md
|
||||
```
|
||||
Do not remove the prompt file immediately — the child agent may not have read it yet. The file will be read from `/tmp` and cleaned up by the OS or the child after use.
|
||||
|
||||
### 5. Print summary
|
||||
|
||||
|
||||
@@ -1,161 +0,0 @@
|
||||
# Agent CLI Tests for implement-issue
|
||||
|
||||
These tests verify the tmux command composition logic in `implement-issue`. They intercept the generated shell command string rather than the tmux invocation itself.
|
||||
|
||||
The seam being tested: given a `docs/agents/agent-cli.md` config and a `mise` availability state, `implement-issue` must compose the correct tmux launch command.
|
||||
|
||||
## Test fixtures
|
||||
|
||||
### Fixture: pi agent config (stdin-piped via @{prompt})
|
||||
|
||||
```yaml
|
||||
# docs/agents/agent-cli.md
|
||||
selected: pi
|
||||
binary: pi
|
||||
args: "-p @{prompt}"
|
||||
```
|
||||
|
||||
### Fixture: opencode agent config
|
||||
|
||||
```yaml
|
||||
# docs/agents/agent-cli.md
|
||||
selected: opencode
|
||||
binary: opencode
|
||||
args: "run -f @{prompt}"
|
||||
```
|
||||
|
||||
### Fixture: codex agent config (empty args = stdin pipe)
|
||||
|
||||
```yaml
|
||||
# docs/agents/agent-cli.md
|
||||
selected: codex
|
||||
binary: codex
|
||||
args: ""
|
||||
```
|
||||
|
||||
### Fixture: missing binary config
|
||||
|
||||
```yaml
|
||||
# docs/agents/agent-cli.md
|
||||
selected: missing-agent
|
||||
binary: totally-not-on-path
|
||||
args: ""
|
||||
```
|
||||
|
||||
## Test cases
|
||||
|
||||
### Test: composes correct tmux command for pi with mise available
|
||||
|
||||
**Given:**
|
||||
- `docs/agents/agent-cli.md` contains the pi fixture
|
||||
- `command -v mise` succeeds
|
||||
|
||||
**When:** `implement-issue` composes the tmux launch command
|
||||
|
||||
**Then:** the generated command string is:
|
||||
|
||||
```
|
||||
tmux new-window -n "issue-42-ws-sjb-skills" -c /home/sjb/Projects/personal/ws-sjb-skills/ws-sjb-skills-issue-42 "mise x --allow-env='*' -- pi -p /tmp/issue-42-prompt.md"
|
||||
```
|
||||
|
||||
**Notes:**
|
||||
- `@{prompt}` is substituted with the actual temp file path
|
||||
- Window name includes issue number and repo slug
|
||||
- Worktree path is absolute
|
||||
- `mise x --allow-env='*'` is prepended when mise is available
|
||||
|
||||
---
|
||||
|
||||
### Test: composes correct tmux command for pi without mise (fallback to $SHELL -c)
|
||||
|
||||
**Given:**
|
||||
- `docs/agents/agent-cli.md` contains the pi fixture
|
||||
- `command -v mise` fails (no mise on PATH)
|
||||
|
||||
**When:** `implement-issue` composes the tmux launch command
|
||||
|
||||
**Then:** the generated command string is:
|
||||
|
||||
```
|
||||
tmux new-window -n "issue-42-ws-sjb-skills" -c /home/sjb/Projects/personal/ws-sjb-skills/ws-sjb-skills-issue-42 "$SHELL -c 'pi -p /tmp/issue-42-prompt.md'"
|
||||
```
|
||||
|
||||
**Notes:**
|
||||
- Falls back to `$SHELL -c` when mise is absent
|
||||
- The agent command is wrapped inside `$SHELL -c '...'`
|
||||
|
||||
---
|
||||
|
||||
### Test: composes correct tmux command for codex (stdin piping, no @{prompt})
|
||||
|
||||
**Given:**
|
||||
- `docs/agents/agent-cli.md` contains the codex fixture (args: "")
|
||||
- `command -v mise` succeeds
|
||||
|
||||
**When:** `implement-issue` composes the tmux launch command
|
||||
|
||||
**Then:** the generated command string is:
|
||||
|
||||
```
|
||||
tmux new-window -n "issue-42-ws-sjb-skills" -c /home/sjb/Projects/personal/ws-sjb-skills/ws-sjb-skills-issue-42 "mise x --allow-env='*' -- sh -c 'cat /tmp/issue-42-prompt.md | codex'"
|
||||
```
|
||||
|
||||
**Notes:**
|
||||
- When args is empty, prompt is piped via `cat <prompt> | <binary>`
|
||||
- The pipe syntax is always `cat <prompt> | <binary>` for stdin-based agents
|
||||
|
||||
---
|
||||
|
||||
### Test: fails fast with clear message when binary not on PATH
|
||||
|
||||
**Given:**
|
||||
- `docs/agents/agent-cli.md` contains the missing binary fixture
|
||||
- `command -v totally-not-on-path` fails
|
||||
|
||||
**When:** `implement-issue` validates the binary at invocation time
|
||||
|
||||
**Then:** it fails immediately with:
|
||||
|
||||
```
|
||||
Agent 'totally-not-on-path' not found on PATH — rerun /setup-skills to reconfigure.
|
||||
```
|
||||
|
||||
**Notes:**
|
||||
- Validation happens before any tmux launch
|
||||
- Error message directs user to re-run setup-skills
|
||||
|
||||
---
|
||||
|
||||
### Test: reads selected agent from docs/agents/agent-cli.md
|
||||
|
||||
**Given:**
|
||||
- `docs/agents/agent-cli.md` exists and contains valid YAML with `selected`, `binary`, and `args` fields
|
||||
|
||||
**When:** `implement-issue` reads the config at invocation time
|
||||
|
||||
**Then:** it parses the three fields correctly and uses them for dispatch
|
||||
|
||||
**Notes:**
|
||||
- Does not use hardcoded dispatch table
|
||||
- Does not run detection scripts
|
||||
- Reads directly from the repo-side config file
|
||||
|
||||
---
|
||||
|
||||
### Test: @{prompt} placeholder substitution
|
||||
|
||||
**Given:**
|
||||
- `docs/agents/agent-cli.md` contains opencode fixture (args: "run -f @{prompt}")
|
||||
- `command -v mise` succeeds
|
||||
|
||||
**When:** `implement-issue` composes the tmux launch command with prompt file at `/tmp/issue-99-prompt.md`
|
||||
|
||||
**Then:** the generated command contains:
|
||||
|
||||
```
|
||||
opencode run -f /tmp/issue-99-prompt.md
|
||||
```
|
||||
|
||||
**Notes:**
|
||||
- `@{prompt}` in args is replaced with the absolute path to the temp prompt file
|
||||
- Works regardless of where `@{prompt}` appears in the args string
|
||||
Reference in New Issue
Block a user