mirror of
https://github.com/cexll/myclaude.git
synced 2026-02-14 03:31:58 +08:00
feat: add worktree support and refactor do skill to Python
- Add worktree module for git worktree management - Refactor do skill scripts from shell to Python for better maintainability - Add install.py for do skill installation - Update stop-hook to Python implementation - Enhance executor with additional configuration options - Update CLAUDE.md with first-principles thinking guidelines Generated with SWE-Agent.ai Co-Authored-By: SWE-Agent.ai <noreply@swe-agent.ai>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# do - Feature Development Orchestrator
|
||||
|
||||
7-phase feature development workflow orchestrating multiple agents via codeagent-wrapper.
|
||||
5-phase feature development workflow orchestrating multiple agents via codeagent-wrapper.
|
||||
|
||||
## Installation
|
||||
|
||||
@@ -24,17 +24,15 @@ Examples:
|
||||
/do implement order export to CSV
|
||||
```
|
||||
|
||||
## 7-Phase Workflow
|
||||
## 5-Phase Workflow
|
||||
|
||||
| Phase | Name | Goal | Key Actions |
|
||||
|-------|------|------|-------------|
|
||||
| 1 | Discovery | Understand requirements | AskUserQuestion + code-architect draft |
|
||||
| 2 | Exploration | Map codebase patterns | 2-3 parallel code-explorer tasks |
|
||||
| 3 | Clarification | Resolve ambiguities | **MANDATORY** - must answer before proceeding |
|
||||
| 4 | Architecture | Design implementation | 2 parallel code-architect approaches |
|
||||
| 5 | Implementation | Build the feature | **Requires approval** - develop agent |
|
||||
| 6 | Review | Catch defects | 2-3 parallel code-reviewer tasks |
|
||||
| 7 | Summary | Document results | code-reviewer summary |
|
||||
| 1 | Understand | Gather requirements | AskUserQuestion + code-explorer analysis |
|
||||
| 2 | Clarify | Resolve ambiguities | **MANDATORY** - must answer before proceeding |
|
||||
| 3 | Design | Plan implementation | code-architect approaches |
|
||||
| 4 | Implement | Build the feature | **Requires approval** - develop agent |
|
||||
| 5 | Complete | Finalize and document | code-reviewer summary |
|
||||
|
||||
## Agents
|
||||
|
||||
@@ -50,8 +48,8 @@ To customize agents, create same-named files in `~/.codeagent/agents/` to overri
|
||||
## Hard Constraints
|
||||
|
||||
1. **Never write code directly** - delegate all changes to codeagent-wrapper agents
|
||||
2. **Phase 3 is mandatory** - do not proceed until questions are answered
|
||||
3. **Phase 5 requires approval** - stop after Phase 4 if not approved
|
||||
2. **Phase 2 is mandatory** - do not proceed until questions are answered
|
||||
3. **Phase 4 requires approval** - stop after Phase 3 if not approved
|
||||
4. **Pass complete context forward** - every agent gets the Context Pack
|
||||
5. **Parallel-first** - run independent tasks via `codeagent-wrapper --parallel`
|
||||
6. **Update state after each phase** - keep `.claude/do.{task_id}.local.md` current
|
||||
@@ -63,7 +61,7 @@ To customize agents, create same-named files in `~/.codeagent/agents/` to overri
|
||||
<verbatim request>
|
||||
|
||||
## Context Pack
|
||||
- Phase: <1-7 name>
|
||||
- Phase: <1-5 name>
|
||||
- Decisions: <requirements/constraints/choices>
|
||||
- Code-explorer output: <paste or "None">
|
||||
- Code-architect output: <paste or "None">
|
||||
@@ -83,7 +81,7 @@ To customize agents, create same-named files in `~/.codeagent/agents/` to overri
|
||||
When triggered via `/do <task>`, initializes `.claude/do.{task_id}.local.md` with:
|
||||
- `active: true`
|
||||
- `current_phase: 1`
|
||||
- `max_phases: 7`
|
||||
- `max_phases: 5`
|
||||
- `completion_promise: "<promise>DO_COMPLETE</promise>"`
|
||||
|
||||
After each phase, update frontmatter:
|
||||
@@ -92,7 +90,7 @@ current_phase: <next phase number>
|
||||
phase_name: "<next phase name>"
|
||||
```
|
||||
|
||||
When all 7 phases complete, output:
|
||||
When all 5 phases complete, output:
|
||||
```
|
||||
<promise>DO_COMPLETE</promise>
|
||||
```
|
||||
@@ -184,3 +182,29 @@ Required when using `agent:` in parallel tasks or `--agent`. Create `~/.codeagen
|
||||
```bash
|
||||
python install.py --uninstall --module do
|
||||
```
|
||||
|
||||
## Worktree Mode
|
||||
|
||||
Use `--worktree` to execute tasks in an isolated git worktree, preventing changes to your main branch:
|
||||
|
||||
```bash
|
||||
codeagent-wrapper --worktree --agent develop "implement feature X" .
|
||||
```
|
||||
|
||||
This automatically:
|
||||
1. Generates a unique task ID (format: `YYYYMMDD-xxxxxx`)
|
||||
2. Creates a new worktree at `.worktrees/do-{task_id}/`
|
||||
3. Creates a new branch `do/{task_id}`
|
||||
4. Executes the task in the isolated worktree
|
||||
|
||||
Output includes: `Using worktree: .worktrees/do-{task_id}/ (task_id: {id}, branch: do/{id})`
|
||||
|
||||
In parallel mode, add `worktree: true` to task blocks:
|
||||
```
|
||||
---TASK---
|
||||
id: feature_impl
|
||||
agent: develop
|
||||
worktree: true
|
||||
---CONTENT---
|
||||
Implement the feature
|
||||
```
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
name: do
|
||||
description: This skill should be used for structured feature development with codebase understanding. Triggers on /do command. Provides a 7-phase workflow (Discovery, Exploration, Clarification, Architecture, Implementation, Review, Summary) using codeagent-wrapper to orchestrate code-explorer, code-architect, code-reviewer, and develop agents in parallel.
|
||||
allowed-tools: ["Bash(${SKILL_DIR}/scripts/setup-do.sh:*)"]
|
||||
description: This skill should be used for structured feature development with codebase understanding. Triggers on /do command. Provides a 5-phase workflow (Understand, Clarify, Design, Implement, Complete) using codeagent-wrapper to orchestrate code-explorer, code-architect, code-reviewer, and develop agents in parallel.
|
||||
allowed-tools: ["Bash(${SKILL_DIR}/scripts/setup-do.py:*)"]
|
||||
---
|
||||
|
||||
# do - Feature Development Orchestrator
|
||||
@@ -10,17 +10,57 @@ An orchestrator for systematic feature development. Invoke agents via `codeagent
|
||||
|
||||
## Loop Initialization (REQUIRED)
|
||||
|
||||
When triggered via `/do <task>`, **first** initialize the loop state:
|
||||
When triggered via `/do <task>`, follow these steps:
|
||||
|
||||
### Step 1: Ask about worktree mode
|
||||
|
||||
Use AskUserQuestion to ask:
|
||||
|
||||
```
|
||||
Develop in a separate worktree? (Isolates changes from main branch)
|
||||
- Yes (Recommended for larger changes)
|
||||
- No (Work directly in current directory)
|
||||
```
|
||||
|
||||
### Step 2: Initialize state
|
||||
|
||||
```bash
|
||||
"${SKILL_DIR}/scripts/setup-do.sh" "<task description>"
|
||||
# If worktree mode selected:
|
||||
python3 "${SKILL_DIR}/scripts/setup-do.py" --worktree "<task description>"
|
||||
|
||||
# If no worktree:
|
||||
python3 "${SKILL_DIR}/scripts/setup-do.py" "<task description>"
|
||||
```
|
||||
|
||||
This creates `.claude/do.{task_id}.local.md` with:
|
||||
- `active: true`
|
||||
- `current_phase: 1`
|
||||
- `max_phases: 7`
|
||||
- `max_phases: 5`
|
||||
- `completion_promise: "<promise>DO_COMPLETE</promise>"`
|
||||
- `use_worktree: true/false`
|
||||
|
||||
## Worktree Mode
|
||||
|
||||
When `use_worktree: true` in state file, ALL `codeagent-wrapper` calls that modify code MUST include `--worktree`:
|
||||
|
||||
```bash
|
||||
# With worktree mode enabled
|
||||
codeagent-wrapper --worktree --agent develop - . <<'EOF'
|
||||
...
|
||||
EOF
|
||||
|
||||
# Parallel tasks with worktree
|
||||
codeagent-wrapper --worktree --parallel <<'EOF'
|
||||
---TASK---
|
||||
id: task1
|
||||
agent: develop
|
||||
workdir: .
|
||||
---CONTENT---
|
||||
...
|
||||
EOF
|
||||
```
|
||||
|
||||
The `--worktree` flag tells codeagent-wrapper to create/use a worktree internally. Read-only agents (code-explorer, code-architect, code-reviewer) do NOT need `--worktree`.
|
||||
|
||||
## Loop State Management
|
||||
|
||||
@@ -30,7 +70,7 @@ current_phase: <next phase number>
|
||||
phase_name: "<next phase name>"
|
||||
```
|
||||
|
||||
When all 7 phases complete, output the completion signal:
|
||||
When all 5 phases complete, output the completion signal:
|
||||
```
|
||||
<promise>DO_COMPLETE</promise>
|
||||
```
|
||||
@@ -40,22 +80,35 @@ To abort early, set `active: false` in the state file.
|
||||
## Hard Constraints
|
||||
|
||||
1. **Never write code directly.** Delegate all code changes to `codeagent-wrapper` agents.
|
||||
2. **Phase 3 (Clarification) is mandatory.** Do not proceed until questions are answered.
|
||||
3. **Phase 5 (Implementation) requires explicit approval.** Stop after Phase 4 if not approved.
|
||||
4. **Pass complete context forward.** Every agent invocation includes the Context Pack.
|
||||
5. **Parallel-first.** Run independent tasks via `codeagent-wrapper --parallel`.
|
||||
6. **Update state after each phase.** Keep `.claude/do.{task_id}.local.md` current.
|
||||
7. **Expect long-running `codeagent-wrapper` calls.** High-reasoning modes (e.g. `xhigh`) can take a long time; stay in the orchestrator role and wait for agents to complete.
|
||||
8. **Timeouts are not an escape hatch.** If a `codeagent-wrapper` invocation times out/errors, retry `codeagent-wrapper` (split/narrow the task if needed); never switch to direct implementation.
|
||||
2. **Pass complete context forward.** Every agent invocation includes the Context Pack.
|
||||
3. **Parallel-first.** Run independent tasks via `codeagent-wrapper --parallel`.
|
||||
4. **Update state after each phase.** Keep `.claude/do.{task_id}.local.md` current.
|
||||
5. **Expect long-running `codeagent-wrapper` calls.** High-reasoning modes can take a long time; stay in the orchestrator role and wait for agents to complete.
|
||||
6. **Timeouts are not an escape hatch.** If a `codeagent-wrapper` invocation times out/errors, retry (split/narrow the task if needed); never switch to direct implementation.
|
||||
7. **Respect worktree setting.** If `use_worktree: true`, always pass `--worktree` to develop agent calls.
|
||||
|
||||
## Agents
|
||||
|
||||
| Agent | Purpose | Prompt |
|
||||
|-------|---------|--------|
|
||||
| `code-explorer` | Trace code, map architecture, find patterns | `agents/code-explorer.md` |
|
||||
| `code-architect` | Design approaches, file plans, build sequences | `agents/code-architect.md` |
|
||||
| `code-reviewer` | Review for bugs, simplicity, conventions | `agents/code-reviewer.md` |
|
||||
| `develop` | Implement code, run tests | (uses global config) |
|
||||
| Agent | Purpose | Needs --worktree |
|
||||
|-------|---------|------------------|
|
||||
| `code-explorer` | Trace code, map architecture, find patterns | No (read-only) |
|
||||
| `code-architect` | Design approaches, file plans, build sequences | No (read-only) |
|
||||
| `code-reviewer` | Review for bugs, simplicity, conventions | No (read-only) |
|
||||
| `develop` | Implement code, run tests | **Yes** (if worktree enabled) |
|
||||
|
||||
## Issue Severity Definitions
|
||||
|
||||
**Blocking issues** (require user input):
|
||||
- Impacts core functionality or correctness
|
||||
- Security vulnerabilities
|
||||
- Architectural conflicts with existing patterns
|
||||
- Ambiguous requirements with multiple valid interpretations
|
||||
|
||||
**Minor issues** (auto-fix without asking):
|
||||
- Code style inconsistencies
|
||||
- Naming improvements
|
||||
- Missing documentation
|
||||
- Non-critical test coverage gaps
|
||||
|
||||
## Context Pack Template
|
||||
|
||||
@@ -64,7 +117,7 @@ To abort early, set `active: false` in the state file.
|
||||
<verbatim request>
|
||||
|
||||
## Context Pack
|
||||
- Phase: <1-7 name>
|
||||
- Phase: <1-5 name>
|
||||
- Decisions: <requirements/constraints/choices>
|
||||
- Code-explorer output: <paste or "None">
|
||||
- Code-architect output: <paste or "None">
|
||||
@@ -79,18 +132,21 @@ To abort early, set `active: false` in the state file.
|
||||
<checkable outputs>
|
||||
```
|
||||
|
||||
## 7-Phase Workflow
|
||||
## 5-Phase Workflow
|
||||
|
||||
### Phase 1: Discovery
|
||||
### Phase 1: Understand (Parallel, No Interaction)
|
||||
|
||||
**Goal:** Understand what to build.
|
||||
**Goal:** Understand requirements and map codebase simultaneously.
|
||||
|
||||
**Actions:**
|
||||
1. Use AskUserQuestion for: user-visible behavior, scope, constraints, acceptance criteria
|
||||
2. Invoke `code-architect` to draft requirements checklist and clarifying questions
|
||||
**Actions:** Run `code-architect` and 2-3 `code-explorer` tasks in parallel.
|
||||
|
||||
```bash
|
||||
codeagent-wrapper --agent code-architect - . <<'EOF'
|
||||
codeagent-wrapper --parallel <<'EOF'
|
||||
---TASK---
|
||||
id: p1_requirements
|
||||
agent: code-architect
|
||||
workdir: .
|
||||
---CONTENT---
|
||||
## Original User Request
|
||||
/do <request>
|
||||
|
||||
@@ -99,33 +155,29 @@ codeagent-wrapper --agent code-architect - . <<'EOF'
|
||||
- Code-architect output: None
|
||||
|
||||
## Current Task
|
||||
Produce requirements checklist and identify missing information.
|
||||
Output: Requirements, Non-goals, Risks, Acceptance criteria, Questions (<= 10)
|
||||
1. Analyze requirements completeness (score 1-10)
|
||||
2. Extract explicit requirements, constraints, acceptance criteria
|
||||
3. Identify blocking questions (issues that prevent implementation)
|
||||
4. Identify minor clarifications (nice-to-have but can proceed without)
|
||||
|
||||
Output format:
|
||||
- Completeness score: X/10
|
||||
- Requirements: [list]
|
||||
- Non-goals: [list]
|
||||
- Blocking questions: [list, if any]
|
||||
- Minor clarifications: [list, if any]
|
||||
|
||||
## Acceptance Criteria
|
||||
Concrete, testable checklist; specific questions; no implementation.
|
||||
EOF
|
||||
```
|
||||
Concrete checklist; blocking vs minor questions clearly separated.
|
||||
|
||||
### Phase 2: Exploration
|
||||
|
||||
**Goal:** Map codebase patterns and extension points.
|
||||
|
||||
**Actions:** Run 2-3 `code-explorer` tasks in parallel (similar features, architecture, tests/conventions).
|
||||
|
||||
```bash
|
||||
codeagent-wrapper --parallel <<'EOF'
|
||||
---TASK---
|
||||
id: p2_similar_features
|
||||
id: p1_similar_features
|
||||
agent: code-explorer
|
||||
workdir: .
|
||||
---CONTENT---
|
||||
## Original User Request
|
||||
/do <request>
|
||||
|
||||
## Context Pack
|
||||
- Code-architect output: <Phase 1 output>
|
||||
|
||||
## Current Task
|
||||
Find 1-3 similar features, trace end-to-end. Return: key files with line numbers, call flow, extension points.
|
||||
|
||||
@@ -133,16 +185,13 @@ Find 1-3 similar features, trace end-to-end. Return: key files with line numbers
|
||||
Concrete file:line map + reuse points.
|
||||
|
||||
---TASK---
|
||||
id: p2_architecture
|
||||
id: p1_architecture
|
||||
agent: code-explorer
|
||||
workdir: .
|
||||
---CONTENT---
|
||||
## Original User Request
|
||||
/do <request>
|
||||
|
||||
## Context Pack
|
||||
- Code-architect output: <Phase 1 output>
|
||||
|
||||
## Current Task
|
||||
Map architecture for relevant subsystem. Return: module map + 5-10 key files.
|
||||
|
||||
@@ -150,16 +199,13 @@ Map architecture for relevant subsystem. Return: module map + 5-10 key files.
|
||||
Clear boundaries; file:line references.
|
||||
|
||||
---TASK---
|
||||
id: p2_conventions
|
||||
id: p1_conventions
|
||||
agent: code-explorer
|
||||
workdir: .
|
||||
---CONTENT---
|
||||
## Original User Request
|
||||
/do <request>
|
||||
|
||||
## Context Pack
|
||||
- Code-architect output: <Phase 1 output>
|
||||
|
||||
## Current Task
|
||||
Identify testing patterns, conventions, config. Return: test commands + file locations.
|
||||
|
||||
@@ -168,86 +214,74 @@ Test commands + relevant test file paths.
|
||||
EOF
|
||||
```
|
||||
|
||||
### Phase 3: Clarification (MANDATORY)
|
||||
### Phase 2: Clarify (Conditional)
|
||||
|
||||
**Goal:** Resolve all ambiguities before design.
|
||||
**Goal:** Resolve blocking ambiguities only.
|
||||
|
||||
**Actions:**
|
||||
1. Invoke `code-architect` to generate prioritized questions from Phase 1+2 outputs
|
||||
2. Use AskUserQuestion to present questions and wait for answers
|
||||
3. **Do not proceed until answered or defaults accepted**
|
||||
|
||||
### Phase 4: Architecture
|
||||
|
||||
**Goal:** Produce implementation plan fitting existing patterns.
|
||||
|
||||
**Actions:** Run 2 `code-architect` tasks in parallel (minimal-change vs pragmatic-clean).
|
||||
1. Review `p1_requirements` output for blocking questions
|
||||
2. **IF blocking questions exist** → Use AskUserQuestion
|
||||
3. **IF no blocking questions (completeness >= 8)** → Skip to Phase 3, log "Requirements clear, proceeding"
|
||||
|
||||
```bash
|
||||
codeagent-wrapper --parallel <<'EOF'
|
||||
---TASK---
|
||||
id: p4_minimal
|
||||
agent: code-architect
|
||||
workdir: .
|
||||
---CONTENT---
|
||||
# Only if blocking questions exist:
|
||||
# Use AskUserQuestion with the blocking questions from Phase 1
|
||||
```
|
||||
|
||||
### Phase 3: Design (No Interaction)
|
||||
|
||||
**Goal:** Produce minimal-change implementation plan.
|
||||
|
||||
**Actions:** Invoke `code-architect` with all Phase 1 context to generate a single implementation plan.
|
||||
|
||||
```bash
|
||||
codeagent-wrapper --agent code-architect - . <<'EOF'
|
||||
## Original User Request
|
||||
/do <request>
|
||||
|
||||
## Context Pack
|
||||
- Code-explorer output: <ALL Phase 2 outputs>
|
||||
- Code-architect output: <Phase 1 + Phase 3 answers>
|
||||
- Code-explorer output: <ALL Phase 1 explorer outputs>
|
||||
- Code-architect output: <Phase 1 requirements + Phase 2 answers if any>
|
||||
|
||||
## Current Task
|
||||
Propose minimal-change architecture: reuse existing abstractions, minimize new files.
|
||||
Output: file touch list, risks, edge cases.
|
||||
Design minimal-change implementation:
|
||||
- Reuse existing abstractions
|
||||
- Minimize new files
|
||||
- Follow established patterns from code-explorer output
|
||||
|
||||
Output:
|
||||
- File touch list with specific changes
|
||||
- Build sequence
|
||||
- Test plan
|
||||
- Risks and mitigations
|
||||
|
||||
## Acceptance Criteria
|
||||
Concrete blueprint; minimal moving parts.
|
||||
|
||||
---TASK---
|
||||
id: p4_pragmatic
|
||||
agent: code-architect
|
||||
workdir: .
|
||||
---CONTENT---
|
||||
## Original User Request
|
||||
/do <request>
|
||||
|
||||
## Context Pack
|
||||
- Code-explorer output: <ALL Phase 2 outputs>
|
||||
- Code-architect output: <Phase 1 + Phase 3 answers>
|
||||
|
||||
## Current Task
|
||||
Propose pragmatic-clean architecture: introduce seams for testability.
|
||||
Output: file touch list, testing plan, risks.
|
||||
|
||||
## Acceptance Criteria
|
||||
Implementable blueprint with build sequence and tests.
|
||||
Concrete, implementable blueprint with minimal moving parts.
|
||||
EOF
|
||||
```
|
||||
|
||||
Use AskUserQuestion to let user choose approach.
|
||||
### Phase 4: Implement + Review (Single Interaction Point)
|
||||
|
||||
### Phase 5: Implementation (Approval Required)
|
||||
|
||||
**Goal:** Build the feature.
|
||||
**Goal:** Build feature and review in one phase.
|
||||
|
||||
**Actions:**
|
||||
1. Use AskUserQuestion: "Approve starting implementation?" (Approve / Not yet)
|
||||
2. If approved, invoke `develop`:
|
||||
|
||||
1. Invoke `develop` to implement (add `--worktree` if `use_worktree: true`):
|
||||
|
||||
```bash
|
||||
codeagent-wrapper --agent develop - . <<'EOF'
|
||||
# Check use_worktree from state file, add --worktree if true
|
||||
codeagent-wrapper --worktree --agent develop - . <<'EOF'
|
||||
## Original User Request
|
||||
/do <request>
|
||||
|
||||
## Context Pack
|
||||
- Code-explorer output: <ALL Phase 2 outputs>
|
||||
- Code-architect output: <selected Phase 4 blueprint + Phase 3 answers>
|
||||
- Code-explorer output: <ALL Phase 1 outputs>
|
||||
- Code-architect output: <Phase 3 blueprint>
|
||||
|
||||
## Current Task
|
||||
Implement with minimal change set following chosen architecture.
|
||||
- Follow Phase 2 patterns
|
||||
- Add/adjust tests per Phase 4 plan
|
||||
Implement with minimal change set following the blueprint.
|
||||
- Follow Phase 1 patterns
|
||||
- Add/adjust tests per Phase 3 plan
|
||||
- Run narrowest relevant tests
|
||||
|
||||
## Acceptance Criteria
|
||||
@@ -255,16 +289,12 @@ Feature works end-to-end; tests pass; diff is minimal.
|
||||
EOF
|
||||
```
|
||||
|
||||
### Phase 6: Review
|
||||
|
||||
**Goal:** Catch defects and unnecessary complexity.
|
||||
|
||||
**Actions:** Run 2-3 `code-reviewer` tasks in parallel (correctness, simplicity).
|
||||
2. Run parallel reviews (no --worktree needed, read-only):
|
||||
|
||||
```bash
|
||||
codeagent-wrapper --parallel <<'EOF'
|
||||
---TASK---
|
||||
id: p6_correctness
|
||||
id: p4_correctness
|
||||
agent: code-reviewer
|
||||
workdir: .
|
||||
---CONTENT---
|
||||
@@ -272,17 +302,18 @@ workdir: .
|
||||
/do <request>
|
||||
|
||||
## Context Pack
|
||||
- Code-architect output: <Phase 4 blueprint>
|
||||
- Develop output: <Phase 5 output>
|
||||
- Code-architect output: <Phase 3 blueprint>
|
||||
- Develop output: <implementation output>
|
||||
|
||||
## Current Task
|
||||
Review for correctness, edge cases, failure modes. Assume adversarial inputs.
|
||||
Review for correctness, edge cases, failure modes.
|
||||
Classify each issue as BLOCKING or MINOR.
|
||||
|
||||
## Acceptance Criteria
|
||||
Issues with file:line references and concrete fixes.
|
||||
Issues with file:line references, severity, and concrete fixes.
|
||||
|
||||
---TASK---
|
||||
id: p6_simplicity
|
||||
id: p4_simplicity
|
||||
agent: code-reviewer
|
||||
workdir: .
|
||||
---CONTENT---
|
||||
@@ -290,20 +321,23 @@ workdir: .
|
||||
/do <request>
|
||||
|
||||
## Context Pack
|
||||
- Code-architect output: <Phase 4 blueprint>
|
||||
- Develop output: <Phase 5 output>
|
||||
- Code-architect output: <Phase 3 blueprint>
|
||||
- Develop output: <implementation output>
|
||||
|
||||
## Current Task
|
||||
Review for KISS: remove bloat, collapse needless abstractions.
|
||||
Classify each issue as BLOCKING or MINOR.
|
||||
|
||||
## Acceptance Criteria
|
||||
Actionable simplifications with justification.
|
||||
Actionable simplifications with severity and justification.
|
||||
EOF
|
||||
```
|
||||
|
||||
Use AskUserQuestion: Fix now / Fix later / Proceed as-is.
|
||||
3. Handle review results:
|
||||
- **MINOR issues only** → Auto-fix via `develop` (with `--worktree` if enabled), no user interaction
|
||||
- **BLOCKING issues** → Use AskUserQuestion: "Fix now / Proceed as-is"
|
||||
|
||||
### Phase 7: Summary
|
||||
### Phase 5: Complete (No Interaction)
|
||||
|
||||
**Goal:** Document what was built.
|
||||
|
||||
@@ -315,9 +349,9 @@ codeagent-wrapper --agent code-reviewer - . <<'EOF'
|
||||
/do <request>
|
||||
|
||||
## Context Pack
|
||||
- Code-architect output: <Phase 4 blueprint>
|
||||
- Code-reviewer output: <Phase 6 outcomes>
|
||||
- Develop output: <Phase 5 output + fixes>
|
||||
- Code-architect output: <Phase 3 blueprint>
|
||||
- Code-reviewer output: <Phase 4 review outcomes>
|
||||
- Develop output: <Phase 4 implementation + fixes>
|
||||
|
||||
## Current Task
|
||||
Write completion summary:
|
||||
@@ -331,3 +365,8 @@ Write completion summary:
|
||||
Short, technical, actionable summary.
|
||||
EOF
|
||||
```
|
||||
|
||||
Output the completion signal:
|
||||
```
|
||||
<promise>DO_COMPLETE</promise>
|
||||
```
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"description": "do loop hook for 7-phase workflow",
|
||||
"description": "do loop hook for 5-phase workflow",
|
||||
"hooks": {
|
||||
"Stop": [
|
||||
{
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/stop-hook.sh"
|
||||
"command": "python3 ${CLAUDE_PLUGIN_ROOT}/hooks/stop-hook.py"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
144
skills/do/hooks/stop-hook.py
Executable file
144
skills/do/hooks/stop-hook.py
Executable file
@@ -0,0 +1,144 @@
|
||||
#!/usr/bin/env python3
|
||||
import glob
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
|
||||
PHASE_NAMES = {
|
||||
1: "Understand",
|
||||
2: "Clarify",
|
||||
3: "Design",
|
||||
4: "Implement",
|
||||
5: "Complete",
|
||||
}
|
||||
|
||||
def phase_name_for(n: int) -> str:
|
||||
return PHASE_NAMES.get(n, f"Phase {n}")
|
||||
|
||||
def frontmatter_get(file_path: str, key: str) -> str:
|
||||
try:
|
||||
with open(file_path, "r", encoding="utf-8") as f:
|
||||
lines = f.readlines()
|
||||
except Exception:
|
||||
return ""
|
||||
|
||||
if not lines or lines[0].strip() != "---":
|
||||
return ""
|
||||
|
||||
for i, line in enumerate(lines[1:], start=1):
|
||||
if line.strip() == "---":
|
||||
break
|
||||
match = re.match(rf"^{re.escape(key)}:\s*(.*)$", line)
|
||||
if match:
|
||||
value = match.group(1).strip()
|
||||
if value.startswith('"') and value.endswith('"'):
|
||||
value = value[1:-1]
|
||||
return value
|
||||
return ""
|
||||
|
||||
def get_body(file_path: str) -> str:
|
||||
try:
|
||||
with open(file_path, "r", encoding="utf-8") as f:
|
||||
content = f.read()
|
||||
except Exception:
|
||||
return ""
|
||||
|
||||
parts = content.split("---", 2)
|
||||
if len(parts) >= 3:
|
||||
return parts[2]
|
||||
return ""
|
||||
|
||||
def check_state_file(state_file: str, stdin_payload: str) -> str:
|
||||
active_raw = frontmatter_get(state_file, "active")
|
||||
active_lc = active_raw.lower()
|
||||
if active_lc not in ("true", "1", "yes", "on"):
|
||||
return ""
|
||||
|
||||
current_phase_raw = frontmatter_get(state_file, "current_phase")
|
||||
max_phases_raw = frontmatter_get(state_file, "max_phases")
|
||||
phase_name = frontmatter_get(state_file, "phase_name")
|
||||
completion_promise = frontmatter_get(state_file, "completion_promise")
|
||||
|
||||
try:
|
||||
current_phase = int(current_phase_raw)
|
||||
except (ValueError, TypeError):
|
||||
current_phase = 1
|
||||
|
||||
try:
|
||||
max_phases = int(max_phases_raw)
|
||||
except (ValueError, TypeError):
|
||||
max_phases = 5
|
||||
|
||||
if not phase_name:
|
||||
phase_name = phase_name_for(current_phase)
|
||||
|
||||
if not completion_promise:
|
||||
completion_promise = "<promise>DO_COMPLETE</promise>"
|
||||
|
||||
phases_done = current_phase >= max_phases
|
||||
|
||||
promise_met = False
|
||||
if completion_promise:
|
||||
if stdin_payload and completion_promise in stdin_payload:
|
||||
promise_met = True
|
||||
else:
|
||||
body = get_body(state_file)
|
||||
if body and completion_promise in body:
|
||||
promise_met = True
|
||||
|
||||
if phases_done and promise_met:
|
||||
try:
|
||||
os.remove(state_file)
|
||||
except Exception:
|
||||
pass
|
||||
return ""
|
||||
|
||||
if not phases_done:
|
||||
return (f"do loop incomplete: current phase {current_phase}/{max_phases} ({phase_name}). "
|
||||
f"Continue with remaining phases; update {state_file} current_phase/phase_name after each phase. "
|
||||
f"Include completion_promise in final output when done: {completion_promise}. "
|
||||
f"To exit early, set active to false.")
|
||||
else:
|
||||
return (f"do reached final phase (current_phase={current_phase} / max_phases={max_phases}, "
|
||||
f"phase_name={phase_name}), but completion_promise not detected: {completion_promise}. "
|
||||
f"Please include this marker in your final output (or write it to {state_file} body), "
|
||||
f"then finish; to force exit, set active to false.")
|
||||
|
||||
def main():
|
||||
project_dir = os.environ.get("CLAUDE_PROJECT_DIR", os.getcwd())
|
||||
state_dir = os.path.join(project_dir, ".claude")
|
||||
|
||||
do_task_id = os.environ.get("DO_TASK_ID", "")
|
||||
|
||||
if do_task_id:
|
||||
candidate = os.path.join(state_dir, f"do.{do_task_id}.local.md")
|
||||
state_files = [candidate] if os.path.isfile(candidate) else []
|
||||
else:
|
||||
state_files = glob.glob(os.path.join(state_dir, "do.*.local.md"))
|
||||
|
||||
if not state_files:
|
||||
sys.exit(0)
|
||||
|
||||
stdin_payload = ""
|
||||
if not sys.stdin.isatty():
|
||||
try:
|
||||
stdin_payload = sys.stdin.read()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
blocking_reasons = []
|
||||
for state_file in state_files:
|
||||
reason = check_state_file(state_file, stdin_payload)
|
||||
if reason:
|
||||
blocking_reasons.append(reason)
|
||||
|
||||
if not blocking_reasons:
|
||||
sys.exit(0)
|
||||
|
||||
combined_reason = " ".join(blocking_reasons)
|
||||
print(json.dumps({"decision": "block", "reason": combined_reason}))
|
||||
sys.exit(0)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,160 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
phase_name_for() {
|
||||
case "${1:-}" in
|
||||
1) echo "Discovery" ;;
|
||||
2) echo "Exploration" ;;
|
||||
3) echo "Clarification" ;;
|
||||
4) echo "Architecture" ;;
|
||||
5) echo "Implementation" ;;
|
||||
6) echo "Review" ;;
|
||||
7) echo "Summary" ;;
|
||||
*) echo "Phase ${1:-unknown}" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
json_escape() {
|
||||
local s="${1:-}"
|
||||
s=${s//\\/\\\\}
|
||||
s=${s//\"/\\\"}
|
||||
s=${s//$'\n'/\\n}
|
||||
s=${s//$'\r'/\\r}
|
||||
s=${s//$'\t'/\\t}
|
||||
printf "%s" "$s"
|
||||
}
|
||||
|
||||
project_dir="${CLAUDE_PROJECT_DIR:-$PWD}"
|
||||
state_dir="${project_dir}/.claude"
|
||||
|
||||
shopt -s nullglob
|
||||
if [ -n "${DO_TASK_ID:-}" ]; then
|
||||
candidate="${state_dir}/do.${DO_TASK_ID}.local.md"
|
||||
if [ -f "$candidate" ]; then
|
||||
state_files=("$candidate")
|
||||
else
|
||||
state_files=()
|
||||
fi
|
||||
else
|
||||
state_files=("${state_dir}"/do.*.local.md)
|
||||
fi
|
||||
shopt -u nullglob
|
||||
|
||||
if [ ${#state_files[@]} -eq 0 ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
stdin_payload=""
|
||||
if [ ! -t 0 ]; then
|
||||
stdin_payload="$(cat || true)"
|
||||
fi
|
||||
|
||||
frontmatter_get() {
|
||||
local file="$1" key="$2"
|
||||
awk -v k="$key" '
|
||||
BEGIN { in_fm=0 }
|
||||
NR==1 && $0=="---" { in_fm=1; next }
|
||||
in_fm==1 && $0=="---" { exit }
|
||||
in_fm==1 {
|
||||
if ($0 ~ "^"k":[[:space:]]*") {
|
||||
sub("^"k":[[:space:]]*", "", $0)
|
||||
gsub(/^[[:space:]]+|[[:space:]]+$/, "", $0)
|
||||
if ($0 ~ /^".*"$/) { sub(/^"/, "", $0); sub(/"$/, "", $0) }
|
||||
print $0
|
||||
exit
|
||||
}
|
||||
}
|
||||
' "$file"
|
||||
}
|
||||
|
||||
check_state_file() {
|
||||
local state_file="$1"
|
||||
|
||||
local active_raw active_lc
|
||||
active_raw="$(frontmatter_get "$state_file" active || true)"
|
||||
active_lc="$(printf "%s" "$active_raw" | tr '[:upper:]' '[:lower:]')"
|
||||
case "$active_lc" in
|
||||
true|1|yes|on) ;;
|
||||
*) return 0 ;;
|
||||
esac
|
||||
|
||||
local current_phase_raw max_phases_raw phase_name completion_promise
|
||||
current_phase_raw="$(frontmatter_get "$state_file" current_phase || true)"
|
||||
max_phases_raw="$(frontmatter_get "$state_file" max_phases || true)"
|
||||
phase_name="$(frontmatter_get "$state_file" phase_name || true)"
|
||||
completion_promise="$(frontmatter_get "$state_file" completion_promise || true)"
|
||||
|
||||
local current_phase=1
|
||||
if [[ "${current_phase_raw:-}" =~ ^[0-9]+$ ]]; then
|
||||
current_phase="$current_phase_raw"
|
||||
fi
|
||||
|
||||
local max_phases=7
|
||||
if [[ "${max_phases_raw:-}" =~ ^[0-9]+$ ]]; then
|
||||
max_phases="$max_phases_raw"
|
||||
fi
|
||||
|
||||
if [ -z "${phase_name:-}" ]; then
|
||||
phase_name="$(phase_name_for "$current_phase")"
|
||||
fi
|
||||
|
||||
if [ -z "${completion_promise:-}" ]; then
|
||||
completion_promise="<promise>DO_COMPLETE</promise>"
|
||||
fi
|
||||
|
||||
local phases_done=0
|
||||
if [ "$current_phase" -ge "$max_phases" ]; then
|
||||
phases_done=1
|
||||
fi
|
||||
|
||||
local promise_met=0
|
||||
if [ -n "$completion_promise" ]; then
|
||||
if [ -n "$stdin_payload" ] && printf "%s" "$stdin_payload" | grep -Fq -- "$completion_promise"; then
|
||||
promise_met=1
|
||||
else
|
||||
local body
|
||||
body="$(
|
||||
awk '
|
||||
BEGIN { in_fm=0; body=0 }
|
||||
NR==1 && $0=="---" { in_fm=1; next }
|
||||
in_fm==1 && $0=="---" { body=1; in_fm=0; next }
|
||||
body==1 { print }
|
||||
' "$state_file"
|
||||
)"
|
||||
if [ -n "$body" ] && printf "%s" "$body" | grep -Fq -- "$completion_promise"; then
|
||||
promise_met=1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$phases_done" -eq 1 ] && [ "$promise_met" -eq 1 ]; then
|
||||
rm -f "$state_file"
|
||||
return 0
|
||||
fi
|
||||
|
||||
local reason
|
||||
if [ "$phases_done" -eq 0 ]; then
|
||||
reason="do loop incomplete: current phase ${current_phase}/${max_phases} (${phase_name}). Continue with remaining phases; update ${state_file} current_phase/phase_name after each phase. Include completion_promise in final output when done: ${completion_promise}. To exit early, set active to false."
|
||||
else
|
||||
reason="do reached final phase (current_phase=${current_phase} / max_phases=${max_phases}, phase_name=${phase_name}), but completion_promise not detected: ${completion_promise}. Please include this marker in your final output (or write it to ${state_file} body), then finish; to force exit, set active to false."
|
||||
fi
|
||||
|
||||
printf "%s" "$reason"
|
||||
}
|
||||
|
||||
blocking_reasons=()
|
||||
for state_file in "${state_files[@]}"; do
|
||||
reason="$(check_state_file "$state_file")"
|
||||
if [ -n "$reason" ]; then
|
||||
blocking_reasons+=("$reason")
|
||||
fi
|
||||
done
|
||||
|
||||
if [ ${#blocking_reasons[@]} -eq 0 ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
combined_reason="${blocking_reasons[*]}"
|
||||
printf '{"decision":"block","reason":"%s"}\n' "$(json_escape "$combined_reason")"
|
||||
exit 0
|
||||
164
skills/do/install.py
Executable file
164
skills/do/install.py
Executable file
@@ -0,0 +1,164 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Install/uninstall do skill to ~/.claude/skills/do"""
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import shutil
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
SKILL_NAME = "do"
|
||||
HOOK_PATH = "~/.claude/skills/do/hooks/stop-hook.py"
|
||||
|
||||
MODELS_JSON_TEMPLATE = {
|
||||
"agents": {
|
||||
"code-explorer": {
|
||||
"backend": "claude",
|
||||
"model": "claude-sonnet-4-5-20250929"
|
||||
},
|
||||
"code-architect": {
|
||||
"backend": "claude",
|
||||
"model": "claude-sonnet-4-5-20250929"
|
||||
},
|
||||
"code-reviewer": {
|
||||
"backend": "claude",
|
||||
"model": "claude-sonnet-4-5-20250929"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def get_settings_path() -> Path:
|
||||
return Path.home() / ".claude" / "settings.json"
|
||||
|
||||
def load_settings() -> dict:
|
||||
path = get_settings_path()
|
||||
if path.exists():
|
||||
with open(path, "r", encoding="utf-8") as f:
|
||||
return json.load(f)
|
||||
return {}
|
||||
|
||||
def save_settings(settings: dict):
|
||||
path = get_settings_path()
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
with open(path, "w", encoding="utf-8") as f:
|
||||
json.dump(settings, f, indent=2)
|
||||
|
||||
def add_hook(settings: dict) -> dict:
|
||||
hook_command = str(Path(HOOK_PATH).expanduser())
|
||||
hook_entry = {
|
||||
"type": "command",
|
||||
"command": f"python3 {hook_command}"
|
||||
}
|
||||
|
||||
if "hooks" not in settings:
|
||||
settings["hooks"] = {}
|
||||
if "Stop" not in settings["hooks"]:
|
||||
settings["hooks"]["Stop"] = []
|
||||
|
||||
stop_hooks = settings["hooks"]["Stop"]
|
||||
|
||||
for item in stop_hooks:
|
||||
if "hooks" in item:
|
||||
for h in item["hooks"]:
|
||||
if "stop-hook" in h.get("command", "") and "do" in h.get("command", ""):
|
||||
h["command"] = f"python3 {hook_command}"
|
||||
return settings
|
||||
|
||||
stop_hooks.append({"hooks": [hook_entry]})
|
||||
return settings
|
||||
|
||||
def remove_hook(settings: dict) -> dict:
|
||||
if "hooks" not in settings or "Stop" not in settings["hooks"]:
|
||||
return settings
|
||||
|
||||
stop_hooks = settings["hooks"]["Stop"]
|
||||
new_stop_hooks = []
|
||||
|
||||
for item in stop_hooks:
|
||||
if "hooks" in item:
|
||||
filtered = [h for h in item["hooks"]
|
||||
if "stop-hook" not in h.get("command", "")
|
||||
or "do" not in h.get("command", "")]
|
||||
if filtered:
|
||||
item["hooks"] = filtered
|
||||
new_stop_hooks.append(item)
|
||||
else:
|
||||
new_stop_hooks.append(item)
|
||||
|
||||
settings["hooks"]["Stop"] = new_stop_hooks
|
||||
if not settings["hooks"]["Stop"]:
|
||||
del settings["hooks"]["Stop"]
|
||||
if not settings["hooks"]:
|
||||
del settings["hooks"]
|
||||
|
||||
return settings
|
||||
|
||||
def install_models_json():
|
||||
"""Install ~/.codeagent/models.json if not exists"""
|
||||
path = Path.home() / ".codeagent" / "models.json"
|
||||
if path.exists():
|
||||
print(f"⚠ {path} already exists, skipping")
|
||||
return
|
||||
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
with open(path, "w", encoding="utf-8") as f:
|
||||
json.dump(MODELS_JSON_TEMPLATE, f, indent=2)
|
||||
print(f"✓ Created {path}")
|
||||
|
||||
def install():
|
||||
src = Path(__file__).parent.resolve()
|
||||
dest = Path.home() / ".claude" / "skills" / SKILL_NAME
|
||||
|
||||
dest.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
exclude = {".git", "__pycache__", ".DS_Store", "install.py"}
|
||||
|
||||
for item in src.iterdir():
|
||||
if item.name in exclude:
|
||||
continue
|
||||
target = dest / item.name
|
||||
if target.exists():
|
||||
if target.is_dir():
|
||||
shutil.rmtree(target)
|
||||
else:
|
||||
target.unlink()
|
||||
if item.is_dir():
|
||||
shutil.copytree(item, target)
|
||||
else:
|
||||
shutil.copy2(item, target)
|
||||
|
||||
settings = load_settings()
|
||||
settings = add_hook(settings)
|
||||
save_settings(settings)
|
||||
|
||||
install_models_json()
|
||||
|
||||
print(f"✓ Installed to {dest}")
|
||||
print(f"✓ Hook added to settings.json")
|
||||
|
||||
def uninstall():
|
||||
dest = Path.home() / ".claude" / "skills" / SKILL_NAME
|
||||
|
||||
settings = load_settings()
|
||||
settings = remove_hook(settings)
|
||||
save_settings(settings)
|
||||
print(f"✓ Hook removed from settings.json")
|
||||
|
||||
if dest.exists():
|
||||
shutil.rmtree(dest)
|
||||
print(f"✓ Removed {dest}")
|
||||
else:
|
||||
print(f"⚠ {dest} not found")
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Install/uninstall do skill")
|
||||
parser.add_argument("--uninstall", "-u", action="store_true", help="Uninstall the skill")
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.uninstall:
|
||||
uninstall()
|
||||
else:
|
||||
install()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
85
skills/do/scripts/setup-do.py
Executable file
85
skills/do/scripts/setup-do.py
Executable file
@@ -0,0 +1,85 @@
|
||||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
import os
|
||||
import secrets
|
||||
import sys
|
||||
import time
|
||||
|
||||
PHASE_NAMES = {
|
||||
1: "Understand",
|
||||
2: "Clarify",
|
||||
3: "Design",
|
||||
4: "Implement",
|
||||
5: "Complete",
|
||||
}
|
||||
|
||||
def phase_name_for(n: int) -> str:
|
||||
return PHASE_NAMES.get(n, f"Phase {n}")
|
||||
|
||||
def die(msg: str):
|
||||
print(f"❌ {msg}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Creates (or overwrites) project state file: .claude/do.local.md"
|
||||
)
|
||||
parser.add_argument("--max-phases", type=int, default=5, help="Default: 5")
|
||||
parser.add_argument(
|
||||
"--completion-promise",
|
||||
default="<promise>DO_COMPLETE</promise>",
|
||||
help="Default: <promise>DO_COMPLETE</promise>",
|
||||
)
|
||||
parser.add_argument("--worktree", action="store_true", help="Enable worktree mode")
|
||||
parser.add_argument("prompt", nargs="+", help="Task description")
|
||||
args = parser.parse_args()
|
||||
|
||||
max_phases = args.max_phases
|
||||
completion_promise = args.completion_promise
|
||||
use_worktree = args.worktree
|
||||
prompt = " ".join(args.prompt)
|
||||
|
||||
if max_phases < 1:
|
||||
die("--max-phases must be a positive integer")
|
||||
|
||||
project_dir = os.environ.get("CLAUDE_PROJECT_DIR", os.getcwd())
|
||||
state_dir = os.path.join(project_dir, ".claude")
|
||||
|
||||
task_id = f"{int(time.time())}-{os.getpid()}-{secrets.token_hex(4)}"
|
||||
state_file = os.path.join(state_dir, f"do.{task_id}.local.md")
|
||||
|
||||
os.makedirs(state_dir, exist_ok=True)
|
||||
|
||||
phase_name = phase_name_for(1)
|
||||
|
||||
content = f"""---
|
||||
active: true
|
||||
current_phase: 1
|
||||
phase_name: "{phase_name}"
|
||||
max_phases: {max_phases}
|
||||
completion_promise: "{completion_promise}"
|
||||
use_worktree: {str(use_worktree).lower()}
|
||||
---
|
||||
|
||||
# do loop state
|
||||
|
||||
## Prompt
|
||||
{prompt}
|
||||
|
||||
## Notes
|
||||
- Update frontmatter current_phase/phase_name as you progress
|
||||
- When complete, include the frontmatter completion_promise in your final output
|
||||
"""
|
||||
|
||||
with open(state_file, "w", encoding="utf-8") as f:
|
||||
f.write(content)
|
||||
|
||||
print(f"Initialized: {state_file}")
|
||||
print(f"task_id: {task_id}")
|
||||
print(f"phase: 1/{max_phases} ({phase_name})")
|
||||
print(f"completion_promise: {completion_promise}")
|
||||
print(f"use_worktree: {use_worktree}")
|
||||
print(f"export DO_TASK_ID={task_id}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,115 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
Usage: setup-do.sh [options] PROMPT...
|
||||
|
||||
Creates (or overwrites) project state file:
|
||||
.claude/do.local.md
|
||||
|
||||
Options:
|
||||
--max-phases N Default: 7
|
||||
--completion-promise STR Default: <promise>DO_COMPLETE</promise>
|
||||
-h, --help Show this help
|
||||
EOF
|
||||
}
|
||||
|
||||
die() {
|
||||
echo "❌ $*" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
phase_name_for() {
|
||||
case "${1:-}" in
|
||||
1) echo "Discovery" ;;
|
||||
2) echo "Exploration" ;;
|
||||
3) echo "Clarification" ;;
|
||||
4) echo "Architecture" ;;
|
||||
5) echo "Implementation" ;;
|
||||
6) echo "Review" ;;
|
||||
7) echo "Summary" ;;
|
||||
*) echo "Phase ${1:-unknown}" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
max_phases=7
|
||||
completion_promise="<promise>DO_COMPLETE</promise>"
|
||||
declare -a prompt_parts=()
|
||||
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
-h|--help)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
--max-phases)
|
||||
[ $# -ge 2 ] || die "--max-phases requires a value"
|
||||
max_phases="$2"
|
||||
shift 2
|
||||
;;
|
||||
--completion-promise)
|
||||
[ $# -ge 2 ] || die "--completion-promise requires a value"
|
||||
completion_promise="$2"
|
||||
shift 2
|
||||
;;
|
||||
--)
|
||||
shift
|
||||
while [ $# -gt 0 ]; do
|
||||
prompt_parts+=("$1")
|
||||
shift
|
||||
done
|
||||
break
|
||||
;;
|
||||
-*)
|
||||
die "Unknown argument: $1 (use --help)"
|
||||
;;
|
||||
*)
|
||||
prompt_parts+=("$1")
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
prompt="${prompt_parts[*]:-}"
|
||||
[ -n "$prompt" ] || die "PROMPT is required (use --help)"
|
||||
|
||||
if ! [[ "$max_phases" =~ ^[0-9]+$ ]] || [ "$max_phases" -lt 1 ]; then
|
||||
die "--max-phases must be a positive integer"
|
||||
fi
|
||||
|
||||
project_dir="${CLAUDE_PROJECT_DIR:-$PWD}"
|
||||
state_dir="${project_dir}/.claude"
|
||||
|
||||
task_id="$(date +%s)-$$-$(head -c 4 /dev/urandom | od -An -tx1 | tr -d ' \n')"
|
||||
state_file="${state_dir}/do.${task_id}.local.md"
|
||||
|
||||
mkdir -p "$state_dir"
|
||||
|
||||
phase_name="$(phase_name_for 1)"
|
||||
|
||||
cat > "$state_file" << EOF
|
||||
---
|
||||
active: true
|
||||
current_phase: 1
|
||||
phase_name: "$phase_name"
|
||||
max_phases: $max_phases
|
||||
completion_promise: "$completion_promise"
|
||||
---
|
||||
|
||||
# do loop state
|
||||
|
||||
## Prompt
|
||||
$prompt
|
||||
|
||||
## Notes
|
||||
- Update frontmatter current_phase/phase_name as you progress
|
||||
- When complete, include the frontmatter completion_promise in your final output
|
||||
EOF
|
||||
|
||||
echo "Initialized: $state_file"
|
||||
echo "task_id: $task_id"
|
||||
echo "phase: 1/$max_phases ($phase_name)"
|
||||
echo "completion_promise: $completion_promise"
|
||||
echo "export DO_TASK_ID=$task_id"
|
||||
Reference in New Issue
Block a user