diff --git a/workflows/solve-issue.yaml b/workflows/solve-issue.yaml index eed7ff8..638abeb 100644 --- a/workflows/solve-issue.yaml +++ b/workflows/solve-issue.yaml @@ -1,202 +1,324 @@ -name: "solve-issue" -description: "TDD-driven issue resolution adapted for the workflow monorepo with bun + vitest" +name: solve-issue +description: TDD-driven issue resolution adapted for the workflow monorepo with bun + vitest roles: planner: - description: "Analyzes issue and outputs a TDD test spec" - goal: "You are a planning agent. You analyze Gitea issues and produce a TDD test specification that downstream roles will implement and verify." + description: Analyzes issue and outputs a TDD test spec + goal: You are a planning agent. You analyze Gitea issues and produce a TDD test specification that downstream roles will implement and verify. capabilities: - - issue-analysis - - planning - procedure: | - On first run (no previous steps): + - issue-analysis + - planning + procedure: 'On first run (no previous steps): + 1. Read the issue and all comments from Gitea using `tea issues -r ` + 2. Look for project conventions files (CLAUDE.md, CONTRIBUTING.md) in the repo + 3. Assess whether the issue has enough information to produce a test spec + 4. If insufficient info: comment on the issue via `echo "..." | tea comment -r ` (skip if you already commented), then output $status=insufficient_info + 5. If sufficient: produce a detailed TDD test spec in markdown covering all scenarios + On subsequent runs (bounced back by tester with fix_spec): - 1. Read the tester's output from the previous step to understand what's wrong with the spec + + 1. Read the tester''s output from the previous step to understand what''s wrong with the spec + 2. Revise the test spec accordingly + After producing the test spec: + 1. Store it via `uwf cas put-text ""` and capture the returned hash + 2. Put the hash in frontmatter.plan (required when $status=ready) + 3. Set repoPath to the absolute path of the repository root - output: "Output a brief summary of the test spec. Set $status to ready (with plan hash and repoPath) or insufficient_info." + + + + IMPORTANT: Extract the repo remote (owner/repo) from git: + + ```bash + + git remote get-url origin | sed ''s|.*[:/]\([^/]*/[^.]*\).*|\1|'' + + ``` + + Store the result as repoRemote in your frontmatter output so downstream roles can use it for tea/API calls.' + output: Output a brief summary of the test spec. Set $status to ready (with plan hash and repoPath) or insufficient_info. frontmatter: oneOf: - - properties: - $status: { const: "ready" } - plan: { type: string } - repoPath: { type: string } - required: [$status, plan, repoPath] - - properties: - $status: { const: "insufficient_info" } - required: [$status] + - properties: + $status: + const: ready + plan: + type: string + repoPath: + type: string + repoRemote: + type: string + required: + - $status + - plan + - repoPath + - properties: + $status: + const: insufficient_info + required: + - $status developer: - description: "TDD implementation per test spec" - goal: "You are a developer agent. You implement code changes following TDD — write tests first, then implementation." + description: TDD implementation per test spec + goal: You are a developer agent. You implement code changes following TDD — write tests first, then implementation. capabilities: - - coding - procedure: | - IMPORTANT: Always work in a git worktree, NEVER modify the main working directory directly. - The repo path and other details are provided in your task prompt. - - Before starting any work, set up an isolated worktree: - 1. cd into the repo path provided in your task prompt - 2. `git fetch origin` to get latest refs - 3. First time (no existing branch): - - `git worktree add .worktrees/fix/- -b fix/- origin/main` - - `cd .worktrees/fix/- && bun install` - 4. If bounced back from reviewer or tester (branch already exists): - - cd into the existing worktree under `.worktrees/fix/-` - - `git fetch origin && git rebase origin/main` - 5. ALL subsequent work must happen inside the worktree directory. - - Then implement TDD: - 6. Read the test spec from CAS: `uwf cas get ` (find the hash from the planner's output in your task prompt) - 7. If bounced back from reviewer or tester: read the previous role's feedback in your task prompt - 8. Write tests first based on the spec (use vitest) - 9. Implement the code to make tests pass - 10. Ensure `bun run build` passes with no errors - 11. Run `bun test` to verify all tests pass - - If you cannot complete the implementation (e.g. the issue is too complex, blocked by external factors, - or repeated attempts fail), set $status=failed with a reason. - output: "List all files changed and provide a summary. Set $status to done (with branch/worktree), or failed (with reason)." + - coding + procedure: "IMPORTANT: Always work in a git worktree, NEVER modify the main working directory directly.\nThe repo path and other details are provided in your task prompt.\n\nBefore starting any work,\ + \ set up an isolated worktree:\n1. cd into the repo path provided in your task prompt\n2. `git fetch origin` to get latest refs\n3. First time (no existing branch):\n - `git worktree add .worktrees/fix/-\ + \ -b fix/- origin/main`\n - `cd .worktrees/fix/- && bun install`\n4. If bounced back from reviewer or tester (branch already exists):\n - cd\ + \ into the existing worktree under `.worktrees/fix/-`\n - `git fetch origin && git rebase origin/main`\n5. ALL subsequent work must happen inside the worktree directory.\n\ + \nThen implement TDD:\n6. Read the test spec from CAS: `uwf cas get ` (find the hash from the planner's output in your task prompt)\n7. If bounced back from reviewer or tester: read the\ + \ previous role's feedback in your task prompt\n8. Write tests first based on the spec (use vitest)\n9. Implement the code to make tests pass\n10. Ensure `bun run build` passes with no errors\n11.\ + \ Run `bun test` to verify all tests pass\n\nIf you cannot complete the implementation (e.g. the issue is too complex, blocked by external factors,\nor repeated attempts fail), set $status=failed\ + \ with a reason.\n" + output: List all files changed and provide a summary. Set $status to done (with branch/worktree), or failed (with reason). frontmatter: oneOf: - - properties: - $status: { const: "done" } - branch: { type: string } - worktree: { type: string } - required: [$status, branch, worktree] - - properties: - $status: { const: "failed" } - reason: { type: string } - required: [$status, reason] + - properties: + $status: + const: done + branch: + type: string + worktree: + type: string + repoRemote: + type: string + required: + - $status + - branch + - worktree + - properties: + $status: + const: failed + reason: + type: string + repoRemote: + type: string + required: + - $status + - reason reviewer: - description: "Code standards compliance check" - goal: "You are a code reviewer. You verify code standards compliance — NOT functionality (that's the tester's job)." + description: Code standards compliance check + goal: You are a code reviewer. You verify code standards compliance — NOT functionality (that's the tester's job). capabilities: - - code-review - - static-analysis - procedure: | - The worktree path is provided in your task prompt. cd into it first. + - code-review + - static-analysis + procedure: 'The worktree path is provided in your task prompt. cd into it first. + Before reviewing, verify the git branch: + 1. Run `git branch --show-current` — confirm the branch name references the issue number being worked on - 2. If the branch doesn't correspond to the issue, flag it in your output and reject + + 2. If the branch doesn''t correspond to the issue, flag it in your output and reject + Then perform code review: + Hard checks (must all pass): + 3. `bun run build` — no build errors + 4. `bunx biome check` — no lint violations + 5. TypeScript strict mode — no type errors + Soft checks (review against project conventions from CLAUDE.md): + - Functional-first: functions + types, no classes (except for errors or third-party requirements) + - Named exports only, no default exports + - No optional properties (use `T | null` instead of `?:`) + - Folder module discipline: index.ts only re-exports, types in types.ts + - Crockford Base32 log tags (8-char, unique per call site) + - No `console.log` in production code (use createLogger from @uncaged/workflow-util) + - No dynamic imports in production code + Only review standards compliance. Do NOT test functionality. + If rejecting, you MUST explain the specific reason in your output. - output: "Explain your decision with specific file/line references. Set $status to approved (with branch/worktree) or rejected (with comments)." + + ' + output: Explain your decision with specific file/line references. Set $status to approved (with branch/worktree) or rejected (with comments). frontmatter: oneOf: - - properties: - $status: { const: "approved" } - branch: { type: string } - worktree: { type: string } - required: [$status, branch, worktree] - - properties: - $status: { const: "rejected" } - comments: { type: string } - worktree: { type: string } - required: [$status, comments, worktree] + - properties: + $status: + const: approved + branch: + type: string + worktree: + type: string + repoRemote: + type: string + required: + - $status + - branch + - worktree + - properties: + $status: + const: rejected + comments: + type: string + worktree: + type: string + repoRemote: + type: string + required: + - $status + - comments + - worktree tester: - description: "Functional correctness verification" - goal: "You are a tester agent. You verify that the implementation correctly satisfies every scenario in the test spec." + description: Functional correctness verification + goal: You are a tester agent. You verify that the implementation correctly satisfies every scenario in the test spec. capabilities: - - testing - procedure: | - The worktree path is provided in your task prompt. cd into it first. - - 1. Run `bun test` for automated test verification - 2. Read the test spec from CAS: `uwf cas get ` (find the hash from the planner step in the thread history) - 3. Verify each scenario in the spec is covered and passing - 4. Determine outcome: - - passed: all scenarios verified, tests pass - - fix_code: tests fail or implementation doesn't match spec → send back to developer - - fix_spec: the spec itself is wrong or incomplete → send back to planner - output: "Report test results per scenario. Set $status to passed (with branch/worktree), fix_code (with report), or fix_spec (with report)." + - testing + procedure: "The worktree path is provided in your task prompt. cd into it first.\n\n1. Run `bun test` for automated test verification\n2. Read the test spec from CAS: `uwf cas get ` (find\ + \ the hash from the planner step in the thread history)\n3. Verify each scenario in the spec is covered and passing\n4. Determine outcome:\n - passed: all scenarios verified, tests pass\n - fix_code:\ + \ tests fail or implementation doesn't match spec → send back to developer\n - fix_spec: the spec itself is wrong or incomplete → send back to planner\n" + output: Report test results per scenario. Set $status to passed (with branch/worktree), fix_code (with report), or fix_spec (with report). frontmatter: oneOf: - - properties: - $status: { const: "passed" } - branch: { type: string } - worktree: { type: string } - required: [$status, branch, worktree] - - properties: - $status: { const: "fix_code" } - report: { type: string } - required: [$status, report] - - properties: - $status: { const: "fix_spec" } - report: { type: string } - required: [$status, report] + - properties: + $status: + const: passed + branch: + type: string + worktree: + type: string + repoRemote: + type: string + required: + - $status + - branch + - worktree + - properties: + $status: + const: fix_code + report: + type: string + repoRemote: + type: string + worktree: + type: string + branch: + type: string + required: + - $status + - report + - properties: + $status: + const: fix_spec + report: + type: string + repoRemote: + type: string + worktree: + type: string + branch: + type: string + required: + - $status + - report committer: - description: "Commits and creates PR" - goal: "You are a committer agent. You create a clean commit and push a PR linking the original issue." + description: Commits and creates PR + goal: You are a committer agent. You create a clean commit and push a PR linking the original issue. capabilities: [] - procedure: | - The worktree path, branch name, and repo info are provided in your task prompt. - cd into the worktree first. - - Note: You inherit the developer's worktree and branch. Do NOT create a new branch. - 1. Stage all changes: `git add -A` - 2. Commit with a descriptive message referencing the issue: `git commit -m "type: description\n\nFixes #N"` - 3. Push the branch: `git push -u origin ` - - If push hook fails: capture the error log in your output, mark hook_failed - 4. On push success: create a PR via `tea pr create --repo --title "..." --description "..."` - - Extract owner/repo from: `git remote get-url origin | sed 's/.*[:/]\([^/]*\/[^.]*\).*/\1/'` - - PR description must include: What / Why / Changes / Ref sections, with `Fixes #N` in Ref - - On tea failure: capture stderr/stdout, include PR details for manual creation, mark hook_failed - 5. After PR creation, clean up the worktree: - - cd to the repo root (parent of .worktrees) - - `git worktree remove ` - output: "Include PR URL on success or error log on failure. Set $status to committed (with prUrl) or hook_failed (with error)." + procedure: "The worktree path, branch name, and repo remote (owner/repo) are provided in your task prompt.\ncd into the worktree first.\n\nNote: You inherit the developer's worktree and branch. Do NOT\ + \ create a new branch.\n1. Stage all changes: `git add -A`\n2. Commit with a descriptive message referencing the issue: `git commit -m \"type: description\\n\\nFixes #N\"`\n3. Push the branch: `git\ + \ push -u origin `\n - If push hook fails: capture the error log in your output, mark hook_failed\n4. On push success: create a PR via `tea pr create --repo --title \"\ + ...\" --description \"...\"`\n - The repo remote (owner/repo format, e.g. \"uncaged/workflow\") is given in your task prompt — use it directly, do NOT try to parse it from git remote URL.\n -\ + \ PR description must include: What / Why / Changes / Ref sections, with `Fixes #N` in Ref\n - If `tea pr create` fails, try the Gitea API as fallback:\n ```bash\n GITEA_TOKEN=$(cfg get\ + \ GITEA_TOKEN)\n curl -s -X POST -H \"Authorization: token $GITEA_TOKEN\" -H \"Content-Type: application/json\" \\\n \"https://git.shazhou.work/api/v1/repos///pulls\" \\\n \ + \ -d '{\"title\":\"...\",\"body\":\"...\",\"head\":\"\",\"base\":\"main\"}'\n ```\n - On total failure: capture stderr/stdout, include PR details for manual creation, mark hook_failed\n\ + 5. After PR creation, clean up the worktree:\n - cd to the repo root (parent of .worktrees)\n - `git worktree remove `" + output: Include PR URL on success or error log on failure. Set $status to committed (with prUrl) or hook_failed (with error). frontmatter: oneOf: - - properties: - $status: { const: "committed" } - prUrl: { type: string } - required: [$status, prUrl] - - properties: - $status: { const: "hook_failed" } - error: { type: string } - required: [$status, error] + - properties: + $status: + const: committed + prUrl: + type: string + repoRemote: + type: string + worktree: + type: string + branch: + type: string + required: + - $status + - prUrl + - properties: + $status: + const: hook_failed + error: + type: string + repoRemote: + type: string + worktree: + type: string + branch: + type: string + required: + - $status + - error graph: $START: - _: { role: "planner", prompt: "Analyze the issue and produce an implementation plan." } + _: + role: planner + prompt: Analyze the issue and produce an implementation plan. planner: - insufficient_info: { role: "$END", prompt: "Insufficient information to proceed; end the workflow." } - ready: { role: "developer", prompt: "Implement the TDD test spec (CAS hash: {{{plan}}}) in repo {{{repoPath}}}." } + insufficient_info: + role: $END + prompt: Insufficient information to proceed; end the workflow. + ready: + role: developer + prompt: 'Implement the TDD test spec (CAS hash: {{{plan}}}) in repo {{{repoPath}}}. Repo remote: {{{repoRemote}}}.' developer: - done: { role: "reviewer", prompt: "Review branch {{{branch}}} at {{{worktree}}} for code standards compliance." } - failed: { role: "$END", prompt: "Developer failed: {{{reason}}}. Ending workflow." } + done: + role: reviewer + prompt: 'Review branch {{{branch}}} at {{{worktree}}} for code standards compliance. Repo remote: {{{repoRemote}}}.' + failed: + role: $END + prompt: 'Developer failed: {{{reason}}}. Ending workflow.' reviewer: - rejected: { role: "developer", prompt: "Reviewer rejected: {{{comments}}}. Fix the issues in repo {{{worktree}}}." } - approved: { role: "tester", prompt: "Review passed. Run tests on branch {{{branch}}} at {{{worktree}}}." } + rejected: + role: developer + prompt: 'Reviewer rejected: {{{comments}}}. Fix the issues in repo {{{worktree}}}. Repo remote: {{{repoRemote}}}.' + approved: + role: tester + prompt: 'Review passed. Run tests on branch {{{branch}}} at {{{worktree}}}. Repo remote: {{{repoRemote}}}.' tester: - fix_code: { role: "developer", prompt: "Tests found code issues: {{{report}}}. Fix and re-submit." } - fix_spec: { role: "planner", prompt: "Tests found spec issues: {{{report}}}. Revise the test spec." } - passed: { role: "committer", prompt: "All tests passed. Commit and push branch {{{branch}}} from {{{worktree}}}." } + fix_code: + role: developer + prompt: 'Tests found code issues: {{{report}}}. Fix and re-submit. Worktree: {{{worktree}}}. Repo remote: {{{repoRemote}}}.' + fix_spec: + role: planner + prompt: 'Tests found spec issues: {{{report}}}. Revise the test spec. Repo remote: {{{repoRemote}}}.' + passed: + role: committer + prompt: 'All tests passed. Commit and push branch {{{branch}}} from {{{worktree}}}. Repo remote (owner/repo): {{{repoRemote}}}.' committer: - hook_failed: { role: "developer", prompt: "Push hook failed: {{{error}}}. Fix and re-submit." } - committed: { role: "$END", prompt: "PR created: {{{prUrl}}}. Workflow complete." } + hook_failed: + role: developer + prompt: 'Push hook failed: {{{error}}}. Fix and re-submit. Worktree: {{{worktree}}}. Repo remote: {{{repoRemote}}}.' + committed: + role: $END + prompt: 'PR created: {{{prUrl}}}. Workflow complete.'