Compare commits

...

7 Commits

Author SHA1 Message Date
catlog22
b502ebcae1 feat: add workflow-research-agent for targeted external research and update analyze-with-file documentation 2026-03-23 14:12:49 +08:00
catlog22
97ed2ef213 refactor: update agent usage description and streamline planning strategy references 2026-03-23 10:08:26 +08:00
catlog22
fcd0b9a2c4 refactor: split review responsibilities — code review in lite-execute, convergence review in lite-test-review
- lite-plan LP-Phase 4: split single "Review" into two selections (Code Review + Convergence Review)
- lite-execute: add Step 4 Code Review (agent/codex/gemini) with code-review.md artifact, Step 5 passes convergenceReviewTool
- lite-test-review: rename reviewTool → convergenceReviewTool, TR-Phase 2 focused on convergence criteria verification
- All autoYes paths default both reviews to Skip
- Data structures updated across all three files for consistency

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 17:18:20 +08:00
catlog22
fab07c2e97 Remove IDAW run and status commands, consolidating functionality and streamlining task execution and progress tracking. 2026-03-21 16:18:15 +08:00
catlog22
5d0000bcc5 refactor: optimize analyze-with-file explore agent triggering for efficiency
- Split Phase 2 exploration into shared Layer 1 discovery + per-perspective
  Layer 2-3 deep-dives, eliminating redundant file scanning across perspectives
- Make CLI deep analysis single-perspective only; multi-perspective already
  covered by perspective agents, removing double analysis
- Add cumulative context rule for Phase 3 to pass prior findings into each
  round's agent/CLI calls, preventing re-discovery of known information
- Update artifact schemas to reflect new two-phase exploration architecture

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 16:00:38 +08:00
catlog22
c8840847d2 chore: exclude workflow-tune command from git and npm packages
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 12:21:53 +08:00
catlog22
8953795c49 feat: Implement workflow tuning command and remove synthesis prompt template
- Added a new command for workflow tuning that extracts commands from reference documents or natural language, executes them via the ccw CLI, and analyzes the artifacts using Gemini.
- The command includes detailed phases for setup, execution, analysis, synthesis, and reporting, ensuring a structured approach to workflow optimization.
- Removed the synthesis prompt template as it is no longer needed with the new command implementation.
2026-03-20 20:25:41 +08:00
33 changed files with 1295 additions and 7676 deletions

View File

@@ -0,0 +1,112 @@
---
name: workflow-research-agent
description: External research agent — web search for API details, design patterns, best practices, and technology validation. Returns structured markdown, does NOT write files.
tools: Read, WebSearch, WebFetch, Bash
---
# External Research Agent
## Role
You perform targeted external research using web search to gather API details, design patterns, architecture approaches, best practices, and technology evaluations. You synthesize findings into structured, actionable markdown for downstream analysis workflows.
Spawned by: analyze-with-file (Phase 2), brainstorm-with-file, or any workflow needing external context.
**CRITICAL**: Return structured markdown only. Do NOT write any files unless explicitly instructed in the prompt.
## Process
1. **Parse research objective** — Understand the topic, focus area, and what the caller needs
2. **Plan queries** — Design 3-5 focused search queries targeting the objective
3. **Execute searches** — Use `WebSearch` for general research, `WebFetch` for specific documentation pages
4. **Cross-reference** — If codebase files are provided in prompt, `Read` them to ground research in actual code context
5. **Synthesize findings** — Extract key insights, patterns, and recommendations from search results
6. **Return structured output** — Markdown-formatted research findings
## Research Modes
### Detail Verification (default for analyze)
Focus: verify assumptions, check best practices, validate technology choices, confirm patterns.
Queries target: benchmarks, production postmortems, known issues, compatibility matrices, official docs.
### API Research (for implementation planning)
Focus: concrete API details, library versions, integration patterns, configuration options.
Queries target: official documentation, API references, migration guides, changelog entries.
### Design Research (for brainstorm/architecture)
Focus: design alternatives, architecture patterns, competitive analysis, UX patterns.
Queries target: design systems, pattern libraries, case studies, comparison articles.
## Execution
### Query Strategy
```
1. Parse topic → extract key technologies, patterns, concepts
2. Generate 3-5 queries:
- Q1: "{technology} best practices {year}"
- Q2: "{pattern} vs {alternative} comparison"
- Q3: "{technology} known issues production"
- Q4: "{specific API/library} documentation {version}"
- Q5: "{domain} architecture patterns"
3. Execute queries via WebSearch
4. For promising results, WebFetch full content for detail extraction
5. Synthesize across all sources
```
### Codebase Grounding
When the prompt includes `codebase_context` (file paths, patterns, tech stack):
- Read referenced files to understand actual usage
- Compare external best practices against current implementation
- Flag gaps between current code and recommended patterns
## Output Format
Return structured markdown (do NOT write files):
```markdown
## Research: {topic}
### Key Findings
- **{Finding 1}**: {detail} (confidence: HIGH|MEDIUM|LOW, source: {url_or_reference})
- **{Finding 2}**: {detail} (confidence: HIGH|MEDIUM|LOW, source: {url_or_reference})
### Technology / API Details
- **{Library/API}**: version {X}, {key capabilities}
- Integration: {how to integrate}
- Caveats: {known issues or limitations}
### Best Practices
- {Practice 1}: {rationale} (source: {reference})
- {Practice 2}: {rationale} (source: {reference})
### Recommended Approach
{Prescriptive recommendation with rationale — "use X" not "consider X or Y" when evidence is strong}
### Alternatives Considered
| Option | Pros | Cons | Verdict |
|--------|------|------|---------|
| {A} | ... | ... | Recommended / Viable / Avoid |
### Pitfalls & Known Issues
- {Issue 1}: {mitigation} (source: {reference})
### Codebase Gaps (if codebase_context provided)
- {Gap}: current code does {X}, best practice recommends {Y}
### Sources
- {source title}: {url} — {key takeaway}
```
## Error Handling
- If WebSearch returns no results for a query: note "no results" and proceed with remaining queries
- If WebFetch fails for a URL: skip and note the intended lookup
- If all searches fail: return "research unavailable — proceed with codebase-only analysis" and list the queries that were attempted
- If codebase files referenced in prompt don't exist: proceed with external research only
## Constraints
- Be prescriptive ("use X") not exploratory ("consider X or Y") when evidence is strong
- Assign confidence levels (HIGH/MEDIUM/LOW) to all findings
- Cite sources for claims — include URLs
- Keep output under 200 lines
- Do NOT write any files — return structured markdown only
- Do NOT fabricate URLs or sources — only cite actual search results
- Bash calls MUST use `run_in_background: false` (subagent cannot receive hook callbacks)

View File

@@ -1,359 +0,0 @@
---
name: auto
description: Chain command - automated document-driven development flow. Detects project state and runs the appropriate chain for new or existing projects.
argument-hint: "[-y|--yes] [--skip-spec] [--skip-build] [--spec <session-id>] [--resume] \"project idea or task description\""
allowed-tools: TodoWrite(*), Agent(*), AskUserQuestion(*), Read(*), Grep(*), Glob(*), Bash(*), Edit(*), Write(*)
---
## Auto Mode
When `--yes` or `-y`: All sub-commands run in auto mode. Minimal human intervention.
# DDD Auto Command (/ddd:auto)
## Purpose
Orchestrate the full document-driven development lifecycle. **Adapts to project state** — works for both new projects and existing codebases.
## Flow Variants
### Variant 1: New Project (no code, no spec)
```
spec-generator → ddd:index-build → ddd:plan → ddd:execute → verify → ddd:sync
```
### Variant 2: Existing Project (has code, no spec)
```
ddd:scan → ddd:plan → ddd:execute → verify → ddd:sync
```
### Variant 3: Existing Project with Spec (has code + spec)
```
ddd:index-build → ddd:plan → ddd:execute → verify → ddd:sync
```
### Variant 4: Index Exists (has doc-index.json)
```
ddd:plan → ddd:execute → verify → ddd:sync
```
## Flow Diagram
```
┌────────────────────────────────────────────────────────────┐
│ /ddd:auto │
│ │
│ Stage 0: Detect Project State │
│ ┌───────────────────────────────────┐ │
│ │ has_codebase? has_spec? has_index?│ │
│ └────────────┬──────────────────────┘ │
│ │ │
│ ┌──────────┼──────────────┐ │
│ ▼ ▼ ▼ │
│ No Code Code Only Code + Spec Index Exists │
│ │ │ │ │ │
│ ▼ │ │ │ │
│ Stage 1 │ │ │ │
│ Spec Gen │ │ │ │
│ │ │ │ │ │
│ ▼ │ ▼ │ │
│ Stage 2a Stage 2b Stage 2a │ │
│ index-build ddd:scan index-build │ │
│ (Path A or Path B auto-detected) │ │
│ │ │ │
│ └───────────────────┬───────────────────┘ │
│ ▼ │
│ Stage 3: DDD Plan (enhanced) │
│ (doc-index query + exploration + │
│ clarification + task planning) │
│ │ │
│ ▼ │
│ Stage 4: Execute │
│ (ddd:execute = doc-aware execution) │
│ │ │
│ ▼ │
│ Stage 4.5: Verify Gate │
│ (convergence + build + lint + tests │
│ → execution-manifest.json) │
│ │ │
│ PASS / WARN → continue │
│ FAIL → ask user │
│ │ │
│ ▼ │
│ Stage 5: Doc Sync │
│ (auto-triggered with --from-manifest, │
│ or manual /ddd:sync) │
└────────────────────────────────────────────────────────────┘
```
## Stage 0: Project State Detection
Automatically detect project state to determine which stages to run:
```
Check 1: doc-index.json exists? → has_index
Check 2: SPEC-* directories exist? → has_spec
Check 3: Source code directories? → has_codebase
Check 4: project-tech.json exists? → has_tech_analysis
```
### Decision Matrix
| has_codebase | has_spec | has_index | Action |
|:---:|:---:|:---:|--------|
| No | No | No | Stage 1 (spec-gen) → Stage 2a (index-build) → Stage 3-5 |
| No | Yes | No | Stage 2a (index-build) → Stage 3-5 |
| Yes | No | No | **Stage 2b (ddd:scan)** → Stage 3-5 |
| Yes | Yes | No | Stage 2a (index-build) → Stage 3-5 |
| Yes | * | Yes | **Skip to Stage 3** (index exists) |
### Override Flags
| Flag | Effect |
|------|--------|
| `--skip-spec` | Never run spec-generator |
| `--skip-build` | Never run index-build |
| `--spec <id>` | Use specific spec session, force Path A |
| `--from-scratch` | Rebuild index even if exists |
## Stage 1: Specification (conditional)
### Run When
- No codebase AND no spec AND `--skip-spec` not set
- User provides a new project idea (not an existing task description)
### Skip When
- `--skip-spec` flag
- Codebase already exists (existing project)
- `--spec <id>` pointing to existing session
### Execution
```
Invoke /spec-generator with user input
→ Output: .workflow/.doc-index/specs/SPEC-{slug}-{date}/
```
## Stage 2: Index Construction (conditional)
### Run When
- `doc-index.json` does not exist
- OR `--from-scratch` flag
### Route Selection
```
Has spec outputs → Stage 2a: /ddd:index-build (spec-first)
No spec, has code → Stage 2b: /ddd:scan (code-first)
```
### Stage 2a: /ddd:index-build (has spec)
```
Invoke /ddd:index-build [-y] [-s <spec-id>]
→ Output: doc-index.json from spec entities + code mapping
```
### Stage 2b: /ddd:scan (no spec, has code)
```
Invoke /ddd:scan [-y]
→ Output: doc-index.json from code analysis + inferred features
```
### Skip When
- `--skip-build` flag
- `doc-index.json` exists AND NOT `--from-scratch`
- In this case, suggest `/ddd:update` for incremental refresh
## Stage 3: Planning (always runs)
### Execution
```
Invoke /ddd:plan [-y] "task description"
```
The enhanced `/ddd:plan` now performs:
1. Doc-index query (instant context from features, requirements, components, ADRs)
2. Doc-index-guided exploration (1-4 angles based on affected features)
3. Clarification (aggregate ambiguities from exploration + doc-index gaps)
4. Task planning (plan.json + TASK-*.json with doc_context traceability)
5. Handoff selection
Output:
- `plan.json` — plan overview with doc_context
- `.task/TASK-*.json` — individual tasks with doc_context
- `exploration-{angle}.json` — exploration results (if Phase 2 ran)
- `planning-context.md` — legacy context package
### Handoff Decision
After planning, `/ddd:plan` presents execution options:
| Option | Description | Auto-Select When |
|--------|-------------|-----------------|
| **ddd:execute** | Document-aware execution (recommended) | Default in ddd workflow |
| **lite-execute** | Standard execution (no doc awareness) | When doc traceability not needed |
| **direct** | Start coding with context | User prefers manual |
| **stop** | Just the plan context | Planning/research only |
With `-y`: Auto-select `ddd:execute`.
## Stage 4: Execution
Based on Stage 3 handoff decision:
| Mode | Delegates To |
|------|-------------|
| **ddd:execute** | `/ddd:execute --in-memory` with plan.json + doc-index enrichment |
| lite-execute | `/workflow:lite-execute` with plan.json path |
| direct | Output context package, developer works manually |
| stop | End here, no execution |
### ddd:execute Features (when selected)
- Doc-enriched task prompts (feature context + component docs + ADR constraints)
- Per-batch impact verification (changes stay within planned scope)
- Result persistence (`TASK-*.result.json` per task, `execution-manifest.json` per session)
- Post-execution verify gate (Stage 4.5, unless `--skip-verify`)
- Post-completion auto-sync with manifest (Stage 5 triggered automatically)
**Note**: When using `ddd:execute`, Stage 4.5 and Stage 5 are auto-triggered. For other modes, run Stage 5 manually.
## Stage 4.5: Verify Gate
Embedded within `ddd:execute` (Step 4.5). Runs after all batches complete, before doc sync.
### Purpose
Quality gate ensuring execution output is correct before committing to documentation updates. Prevents bad code from being "blessed" into the doc-index.
### Checks Performed
| Check | Description | Gate Behavior |
|-------|-------------|---------------|
| **Convergence** | Run `task.convergence.verification` for each task | FAIL if any critical task fails |
| **Build** | Run project build command (`tsc --noEmit`, etc.) | FAIL on build errors |
| **Lint** | Run project linter (`eslint`, etc.) | WARN only (non-blocking) |
| **Regression** | Run full test suite, compare to baseline | FAIL on new test failures |
### Gate Results
| Result | Action |
|--------|--------|
| **PASS** | All checks passed → proceed to Stage 5 |
| **WARN** | Non-critical issues (lint warnings) → proceed with warnings logged |
| **FAIL** | Critical issues → ask user: fix now / skip sync / abort |
| **FAIL + `-y`** | Log failures, set `error_state` in session, stop |
### Output
- `execution-manifest.json` — persisted to session folder, consumed by Stage 5
- Contains: task results, files_modified (with task attribution), verify gate results
## Stage 5: Post-Task Sync
### Trigger
- **Auto**: `/ddd:execute` triggers `/ddd:sync --from-manifest` automatically after verify gate passes
- **Manual**: User runs `/ddd:sync` after completing work in direct/lite-execute mode
- **Resume**: `/ddd:auto --resume` after task completion
### Execution
```
# Auto mode (from ddd:execute): uses manifest for precise change tracking
Invoke /ddd:sync [-y] --task-id <id> --from-manifest {session}/execution-manifest.json "task summary"
# Manual mode (from direct/lite-execute): falls back to git diff
Invoke /ddd:sync [-y] [--task-id <id>] "task summary"
→ Updates: doc-index.json, feature-maps/, tech-registry/, action-logs/
```
## State Tracking
### Session File: `.workflow/.doc-index/.auto-session.json`
```json
{
"session_id": "DAUTO-{timestamp}",
"input": "user's original input",
"detected_state": {
"has_codebase": true,
"has_spec": false,
"has_index": false,
"build_path": "code-first"
},
"stages_completed": ["detect", "index-build", "plan"],
"current_stage": "execute",
"spec_session": "SPEC-{slug}-{date}|null",
"plan_session": "planning/{task-slug}-{date}/",
"plan_context": "planning/{task-slug}-{date}/plan.json",
"execution_mode": "ddd:execute|lite-execute|direct|stop",
"execution_manifest": "planning/{task-slug}-{date}/execution-manifest.json|null",
"verify_gate": "PASS|WARN|FAIL|null",
"error_state": null,
"last_error": {
"stage": "execute",
"message": "Task TASK-002 failed: compilation error",
"timestamp": "ISO8601",
"recoverable": true
},
"created_at": "ISO8601",
"last_updated": "ISO8601"
}
```
### Resume
```
/ddd:auto --resume → Resume from current_stage in .auto-session.json
```
### Error Recovery
```
/ddd:auto --resume
IF error_state is set:
Display last error context
Ask: retry current stage / skip to next / abort
ELSE:
Resume from current_stage normally
```
## Example Workflows
### New Project (Full Flow)
```
/ddd:auto "Build a task management API with user auth and team features"
→ Stage 0: No code, no spec → need spec-gen
→ Stage 1: spec-generator produces full spec
→ Stage 2: index-build creates index from spec + empty codebase
→ Stage 3: ddd:plan produces plan.json + TASK-*.json with doc_context
→ Stage 4: ddd:execute runs tasks with feature context enrichment
→ Stage 4.5: verify gate — convergence ✓, build ✓, tests ✓ → PASS
→ Stage 5: ddd:sync --from-manifest auto-triggered, updates index
```
### Existing Project, No Spec (Code-First)
```
/ddd:auto "Add rate limiting to API endpoints"
→ Stage 0: Has code, no spec, no index
→ Stage 2b: ddd:scan analyzes code, infers features from codebase
→ Stage 3: ddd:plan queries index, explores with security + patterns angles
→ Stage 4: ddd:execute runs with rate-limit component docs as context
→ Stage 4.5: verify gate — convergence ✓, tests 41/42 (1 regression) → WARN
→ Stage 5: ddd:sync --from-manifest, registers new rate-limit component
```
### Existing Project with Index (Incremental)
```
/ddd:auto "Fix auth token expiration bug"
→ Stage 0: Has code, has index → skip to plan
→ Stage 3: ddd:plan finds feat-auth, REQ-002, tech-auth-service (Low complexity, skip exploration)
→ Stage 4: ddd:execute runs single task with auth feature context
→ Stage 4.5: verify gate — convergence ✓, build ✓, tests ✓ → PASS
→ Stage 5: ddd:sync --from-manifest, updates tech-auth-service code locations
```
### Planning Only
```
/ddd:auto "Investigate payment module architecture"
→ Stage 0-2: (as needed)
→ Stage 3: ddd:plan shows full context with exploration results
→ Stage 4: user selects "stop" → gets plan.json + context package only
```

View File

@@ -1,222 +0,0 @@
---
name: doc-generate
description: Generate full document tree from doc-index.json. Layer 3 (components) → Layer 2 (features) → Layer 1 (indexes/overview). Standalone or called by scan/index-build.
argument-hint: "[-y|--yes] [--layer <3|2|1|all>] [--force] [--skip-overview] [--skip-schema]"
allowed-tools: TodoWrite(*), Agent(*), AskUserQuestion(*), Read(*), Grep(*), Glob(*), Bash(*), Edit(*), Write(*)
---
## Auto Mode
When `--yes` or `-y`: Auto-generate all layers without confirmation prompts.
# DDD Doc Generate Command (/ddd:doc-generate)
## Purpose
Generate the complete document tree from `doc-index.json`. **Single source of truth** for all document generation logic, following bottom-up Layer 3 → 2 → 1 strategy.
```
doc-index.json → tech-registry/*.md (L3) → feature-maps/*.md (L2) → _index.md + README + ARCHITECTURE (L1)
```
## When to Use
| Scenario | Use |
|----------|-----|
| After `/ddd:scan` builds doc-index.json | **doc-generate** (auto-called by scan) |
| After `/ddd:index-build` builds doc-index.json | **doc-generate** (auto-called by index-build) |
| Rebuild all docs from existing index | **doc-generate --force** |
| Regenerate only component docs | **doc-generate --layer 3** |
| Regenerate only overview/index docs | **doc-generate --layer 1** |
## Prerequisite
- `doc-index.json` must exist at `.workflow/.doc-index/doc-index.json`
- If not found → error: "No doc-index.json found. Run /ddd:scan or /ddd:index-build first."
## Storage Output
```
.workflow/.doc-index/
├── doc-index.json ← Input (read-only, not modified)
├── SCHEMA.md ← Schema documentation
├── README.md ← Project overview (Layer 1)
├── ARCHITECTURE.md ← Architecture overview (Layer 1)
├── feature-maps/ ← Feature documentation (Layer 2)
│ ├── _index.md
│ └── {feature-slug}.md
├── tech-registry/ ← Component documentation (Layer 3)
│ ├── _index.md
│ └── {component-slug}.md
└── planning/ ← Planning sessions (Layer 1)
├── _index.md ← Planning sessions index
└── {task-slug}-{date}/ ← Individual session folders
```
## Phase 1: Load & Validate
### 1.1 Load doc-index.json
```
Read .workflow/.doc-index/doc-index.json
Validate: features[], technicalComponents[] are non-empty arrays
```
### 1.2 Schema Version Check
```javascript
const schemaVersion = docIndex.schema_version || '0.0';
if (schemaVersion !== '1.0') {
warn(`Schema version mismatch: found ${schemaVersion}, expected 1.0`);
}
```
### 1.3 Determine Generation Scope
```
IF --layer 3: generate Layer 3 only
IF --layer 2: generate Layer 2 only (requires Layer 3 exists)
IF --layer 1: generate Layer 1 only (requires Layer 2 exists)
IF --layer all (default): generate Layer 3 → 2 → 1
```
### 1.4 Check Existing Docs
```
IF docs already exist AND NOT --force:
Warn: "Documents already exist. Use --force to overwrite."
Ask user (unless -y → overwrite)
```
## Phase 2: Layer 3 -- Component Documentation
For each component in `technicalComponents[]`, call the generate_ddd_docs endpoint:
```bash
for COMPONENT_ID in "${technicalComponents[@]}"; do
ccw tool exec generate_ddd_docs '{"strategy":"component","entityId":"'"$COMPONENT_ID"'","tool":"gemini"}'
done
```
The endpoint handles:
- Loading the component entity from doc-index.json
- Building YAML frontmatter (layer: 3, component_id, name, type, features, code_locations, generated_at)
- Constructing the CLI prompt with code context paths
- **Including Change History section**: Pull related entries from `doc-index.json.actions[]` where `affectedComponents` includes this component ID. Display as timeline (date, action type, description)
- Writing output to `.workflow/.doc-index/tech-registry/{slug}.md`
- Tool fallback (gemini -> qwen -> codex) on failure
Output: `.workflow/.doc-index/tech-registry/{component-slug}.md`
## Phase 3: Layer 2 -- Feature Documentation
For each feature in `features[]`, call the generate_ddd_docs endpoint:
```bash
for FEATURE_ID in "${features[@]}"; do
ccw tool exec generate_ddd_docs '{"strategy":"feature","entityId":"'"$FEATURE_ID"'","tool":"gemini"}'
done
```
The endpoint handles:
- Loading the feature entity from doc-index.json
- Building YAML frontmatter (layer: 2, feature_id, name, epic_id, status, requirements, components, tags, generated_at)
- Constructing the CLI prompt referencing Layer 3 component docs
- **Including Change History section**: Pull related entries from `doc-index.json.actions[]` where `affectedFeatures` includes this feature ID. Display as timeline (date, action type, description)
- Writing output to `.workflow/.doc-index/feature-maps/{slug}.md`
- Tool fallback (gemini -> qwen -> codex) on failure
Output: `.workflow/.doc-index/feature-maps/{feature-slug}.md`
## Phase 4: Layer 1 -- Index & Overview Documentation
### 4.1 Index Documents
Generate catalog files for each subdirectory:
```bash
# Feature maps index
ccw tool exec generate_ddd_docs '{"strategy":"index","entityId":"feature-maps","tool":"gemini"}'
# Tech registry index
ccw tool exec generate_ddd_docs '{"strategy":"index","entityId":"tech-registry","tool":"gemini"}'
# Action logs index
ccw tool exec generate_ddd_docs '{"strategy":"index","entityId":"action-logs","tool":"gemini"}'
# Planning sessions index
ccw tool exec generate_ddd_docs '{"strategy":"index","entityId":"planning","tool":"gemini"}'
```
Or generate all indexes at once (omit entityId):
```bash
ccw tool exec generate_ddd_docs '{"strategy":"index","tool":"gemini"}'
```
### 4.2 README.md (unless --skip-overview)
```bash
ccw tool exec generate_ddd_docs '{"strategy":"overview","tool":"gemini"}'
```
### 4.3 ARCHITECTURE.md (unless --skip-overview)
```bash
ccw tool exec generate_ddd_docs '{"strategy":"overview","entityId":"architecture","tool":"gemini"}'
```
## Phase 5: SCHEMA.md (unless --skip-schema)
### 5.1 Generate Schema Documentation
```bash
ccw tool exec generate_ddd_docs '{"strategy":"schema","tool":"gemini"}'
```
### 5.2 Versioning Policy
**Semantic Versioning**:
- **Major** (X.0): Breaking changes (field removal, type changes, incompatible structure)
- **Minor** (X.Y): Non-breaking additions (new optional fields, new sections)
**Migration Protocol**:
1. Detect version mismatch in ddd:plan/ddd:sync
2. Log warning with migration instructions
3. Provide migration script or regeneration option
4. Update schema_version after successful migration
## Phase 6: Generation Report
```
Document Generation Report
Project: {name}
Source: doc-index.json (build_path: {spec-first|code-first})
Generated:
Layer 3 (Components): {N} documents in tech-registry/
Layer 2 (Features): {N} documents in feature-maps/
Layer 1 (Indexes): {N} documents (_index.md, README, ARCHITECTURE)
Schema: SCHEMA.md
Total: {N} documents generated
```
## Flags
| Flag | Effect |
|------|--------|
| `-y, --yes` | Auto-confirm all decisions |
| `--layer <3\|2\|1\|all>` | Generate specific layer only (default: all) |
| `--force` | Overwrite existing documents |
| `--skip-overview` | Skip README.md, ARCHITECTURE.md, planning/_index.md |
| `--skip-schema` | Skip SCHEMA.md generation |
## Integration Points
- **Input from**: `doc-index.json` (from `/ddd:scan` or `/ddd:index-build`)
- **Called by**: `/ddd:scan` (after index assembly), `/ddd:index-build` (after index assembly)
- **Standalone**: Can be run independently on any project with existing doc-index.json
- **Output**: Complete document tree in `.workflow/.doc-index/`
- **Endpoint**: `ccw tool exec generate_ddd_docs` handles prompt construction, frontmatter, tool fallback, and file creation

View File

@@ -1,218 +0,0 @@
---
name: doc-refresh
description: Incrementally update affected documents based on changed components/features. Layer 3 → 2 → 1 selective refresh. Called by sync/update or used standalone.
argument-hint: "[-y|--yes] [--components <id1,id2,...>] [--features <id1,id2,...>] [--minimal] [--dry-run]"
allowed-tools: TodoWrite(*), Agent(*), AskUserQuestion(*), Read(*), Grep(*), Glob(*), Bash(*), Edit(*), Write(*)
---
## Auto Mode
When `--yes` or `-y`: Auto-update affected documents without confirmation prompts.
# DDD Doc Refresh Command (/ddd:doc-refresh)
## Purpose
Incrementally update **only the affected documents** after code changes. Unlike `/ddd:doc-generate` (full generation), this command selectively refreshes documents for specific components and features.
```
affected component/feature IDs → update tech-registry (L3) → update feature-maps (L2) → update indexes (L1)
```
## When to Use
| Scenario | Use |
|----------|-----|
| After `/ddd:sync` detects code changes | **doc-refresh** (auto-called by sync) |
| After `/ddd:update` traces impact | **doc-refresh** (auto-called by update) |
| Manual refresh of specific component docs | **doc-refresh --components tech-auth-service** |
| Quick metadata-only update | **doc-refresh --minimal --components tech-auth-service** |
| Preview what would change | **doc-refresh --dry-run --components tech-auth-service** |
## Prerequisite
- `doc-index.json` must exist at `.workflow/.doc-index/doc-index.json`
- At least one of `--components` or `--features` must be provided (or received from caller)
- Corresponding documents must already exist (generated by `/ddd:doc-generate`)
- If documents missing → error: "Documents not found. Run /ddd:doc-generate first."
## Phase 1: Determine Refresh Scope
### 1.1 Resolve Affected Entities
```
IF --components provided:
affected_components = parse comma-separated IDs
affected_features = lookup featureIds for each component in doc-index.json
IF --features provided:
affected_features = parse comma-separated IDs
affected_components = union of all component IDs linked to features
Merge both sets if both flags provided.
```
### 1.2 Validate Entities Exist
For each ID, verify it exists in doc-index.json. Warn and skip missing IDs.
### 1.3 Check Document Existence
For each affected entity, check if corresponding .md file exists:
- Missing Layer 3 doc → warn: "Component doc not found. Run /ddd:doc-generate first."
- Missing Layer 2 doc → warn: "Feature doc not found. Run /ddd:doc-generate first."
## Phase 2: Layer 3 — Update Component Docs
For each affected component's `tech-registry/{slug}.md`:
```bash
ccw cli -p "PURPOSE: Update component documentation for {component.name} after code changes
TASK:
• Update code locations and line ranges
• Update symbol list (add new exports, remove deleted)
• Add change entry to history table
• Refresh usage examples if API changed
MODE: write
CONTEXT: @{component.codeLocations[].path}
EXPECTED: Updated markdown with current API state
CONSTRAINTS: Preserve existing structure | Only update changed sections
" --tool gemini --mode write --cd .workflow/.doc-index/tech-registry/
```
Update frontmatter:
```markdown
---
layer: 3
component_id: tech-auth-service
generated_at: {original}
last_updated: ISO8601
---
```
### 2.1 Minimal Mode (--minimal)
With `--minimal`, only update:
- `codeLocations` in frontmatter
- `last_updated` timestamp
- Skip CLI call for content regeneration
## Phase 3: Layer 2 — Update Feature Docs
For each affected feature's `feature-maps/{slug}.md`:
```bash
ccw cli -p "PURPOSE: Update feature documentation for {feature.name} after component changes
TASK:
• Update component list if new components added
• Update status if requirements now fully implemented
• Add change entry to history table
• Refresh integration guide if component APIs changed
MODE: write
CONTEXT: @.workflow/.doc-index/tech-registry/{affected-components}.md
EXPECTED: Updated markdown reflecting current feature state
CONSTRAINTS: Reference updated Layer 3 docs | Preserve business language
" --tool gemini --mode write --cd .workflow/.doc-index/feature-maps/
```
Update frontmatter:
```markdown
---
layer: 2
feature_id: feat-auth
depends_on_layer3: [tech-auth-service, tech-user-model]
generated_at: {original}
last_updated: ISO8601
---
```
### 3.1 Minimal Mode (--minimal)
With `--minimal`, only update:
- Component list in frontmatter
- Feature status (if requirements mapping changed)
- `last_updated` timestamp
- Skip CLI call for content regeneration
## Phase 4: Layer 1 — Update Index Docs (conditional)
### 4.1 Trigger Conditions
| Condition | Action |
|-----------|--------|
| New component registered | Update `tech-registry/_index.md` |
| Component removed | Update `tech-registry/_index.md` |
| Feature status changed | Update `feature-maps/_index.md` |
| New feature added | Update `feature-maps/_index.md` + README.md |
| Major architecture change | Update ARCHITECTURE.md |
| New action-log entry | Update `action-logs/_index.md` |
### 4.2 Update _index.md Files
Refresh table entries for affected features/components:
- `feature-maps/_index.md`
- `tech-registry/_index.md`
- `action-logs/_index.md` (if new action entry)
### 4.3 Update Overview Docs (only if significant)
If new features added or major status changes:
```bash
ccw cli -p "PURPOSE: Update project overview docs after feature changes
TASK:
• Update README.md feature list
• Update ARCHITECTURE.md if new components added
• Update planning/_index.md with new planning sessions
MODE: write
CONTEXT: @.workflow/.doc-index/feature-maps/*.md @.workflow/.doc-index/doc-index.json
EXPECTED: Updated overview docs with current project state
CONSTRAINTS: High-level only | Link to Layer 2 for details
" --tool gemini --mode write --cd .workflow/.doc-index/
```
### 4.4 Skip Layer 1
With `--minimal` or when changes are minor (only code location updates): skip Layer 1 entirely.
## Phase 5: Refresh Report
```
Document Refresh Report
Affected Scope:
Components: {N} ({component IDs})
Features: {N} ({feature IDs})
Updated:
Layer 3 (Components): {N} documents refreshed
Layer 2 (Features): {N} documents refreshed
Layer 1 (Indexes): {N} documents refreshed (or "skipped")
Mode: {full|minimal}
```
## Dry-Run Mode
With `--dry-run`:
- Execute Phase 1 (scope determination)
- Display what would be updated (affected files list)
- Skip all file writes (Phase 2-4)
- Output: "Dry-run complete. {N} documents would be refreshed."
## Flags
| Flag | Effect |
|------|--------|
| `-y, --yes` | Auto-confirm all updates |
| `--components <ids>` | Comma-separated component IDs to refresh |
| `--features <ids>` | Comma-separated feature IDs to refresh |
| `--minimal` | Only update metadata/frontmatter, skip content regeneration |
| `--dry-run` | Preview what would change without modifying files |
## Integration Points
- **Input from**: `doc-index.json`, affected entity IDs (from `/ddd:sync` or `/ddd:update`)
- **Called by**: `/ddd:sync` (after change detection + index update), `/ddd:update` (after impact tracing + index update)
- **Standalone**: Can be run independently to refresh specific component/feature docs
- **Prerequisite**: Documents must exist (generated by `/ddd:doc-generate`)

View File

@@ -1,416 +0,0 @@
---
name: execute
description: Document-aware execution engine — executes plan.json + TASK-*.json with doc-index context enrichment, per-batch impact verification, and post-completion doc sync.
argument-hint: "[-y|--yes] [--skip-sync] [--skip-verify] [--plan <path>] [--in-memory] \"optional task description\""
allowed-tools: TodoWrite(*), Agent(*), AskUserQuestion(*), Read(*), Grep(*), Glob(*), Bash(*), Edit(*), Write(*), mcp__ace-tool__search_context(*)
---
## Auto Mode
When `--yes` or `-y`: Auto-confirm all decisions, auto-sync after completion.
# DDD Execute Command (/ddd:execute)
## Purpose
Same execution engine model as lite-execute, but each step is **doc-index-aware**:
- Tasks are enriched with feature context, component docs, and architecture constraints
- Per-batch impact verification ensures changes stay within planned scope
- Post-completion automatically syncs the document index
### Core Differentiator
Unlike generic execution engines, ddd:execute leverages the document architecture:
- Feature-maps provide business context for each task
- Tech-registry provides implementation patterns to follow
- ADRs surface as hard constraints during execution
- Requirement acceptance criteria inform convergence verification
## Prerequisite
- `plan.json` + `.task/TASK-*.json` files from `/ddd:plan`
- `doc-index.json` at `.workflow/.doc-index/doc-index.json`
- If `--in-memory`: receives executionContext from `/ddd:plan` handoff
---
## Step 1: Initialize & Load Context
### 1.1 Locate Plan
```
IF --in-memory:
Load executionContext from ddd:plan handoff
plan_path = executionContext.plan_path
task_dir = executionContext.task_dir
ELIF --plan <path>:
plan_path = <path>
task_dir = {dirname(path)}/.task/
ELSE:
Scan .workflow/.doc-index/planning/ for most recent session
plan_path = {latest_session}/plan.json
task_dir = {latest_session}/.task/
```
### 1.2 Load Plan & Tasks
- Read `plan.json` — validate against plan-overview-base-schema
- Read all `TASK-*.json` from `.task/` directory — validate against task-schema
- Read `doc-index.json` from `.workflow/.doc-index/`
### 1.3 Pre-Load Doc Context
For each task with `doc_context`:
- Load referenced `feature_docs` (feature-maps/{slug}.md)
- Load referenced `component_docs` (tech-registry/{slug}.md)
- Load ADR excerpts from doc-index `architectureDecisions[]`
- Extract requirement acceptance criteria from doc-index `requirements[]`
- Load `doc_context.symbol_docs[]` documentation content (if present)
### 1.4 Echo Strategy
Display execution summary:
```
DDD Execute: {plan.summary}
Complexity: {plan.complexity}
Tasks: {plan.task_count}
Doc-Index Impact:
Features: {doc_context.affected_features}
Requirements: {doc_context.affected_requirements}
Components: {doc_context.affected_components}
Constraints: {doc_context.architecture_constraints}
Execution plan: {batch count} batches, {parallel tasks} parallel where possible
```
---
## Step 2: Task Grouping & Batch Creation
### 2.1 Extract Dependencies
From each `TASK-*.json`, read `depends_on[]` to build dependency graph.
### 2.2 Group into Batches
```
Batch 1: Tasks with no dependencies (depends_on: [])
Batch 2: Tasks depending only on Batch 1 tasks
Batch 3: Tasks depending on Batch 1 + 2 tasks
...
```
Within each batch, tasks with the same `parallel_group` can run concurrently.
### 2.3 Assign Executor per Task
| Signal | Executor |
|--------|----------|
| `meta.execution_config.method == "cli"` | CLI tool (gemini/codex/qwen) |
| `meta.execution_config.method == "agent"` | Agent (code-developer/universal-executor) |
| Default | Agent (code-developer) |
---
## Step 3: Doc-Enriched Execution
For each task in batch order, build an enriched prompt:
### 3.1 Task Prompt Template
```markdown
## Goal
${plan.summary} — specifically: ${task.title}
## Document Context
### Feature: ${feature.name} (${feature.id})
${feature-map content excerpt — overview + requirements section}
### Components
${for each component in task.doc_context.component_ids:
tech-registry excerpt — responsibility + code locations + key patterns}
### Symbol Documentation
${if doc_context.symbol_docs is non-empty:
for each component in doc_context.component_ids:
#### ${component.name} Symbols (Top-5)
${for each symbol in component.symbol_docs.slice(0, 5):
- **${symbol.name}** (${symbol.type}): ${symbol.doc_summary}
Source: `${symbol.source_path}` | Freshness: ${symbol.freshness}
}
}
### Architecture Constraints
${for each ADR in task.doc_context.adr_ids:
ADR title + decision + rationale from doc-index}
### Requirement Acceptance Criteria
${for each requirement in task.doc_context.requirement_ids:
requirement title + priority + success criteria from doc-index}
## Task Details
${task.description}
### Files to Modify
${task.files[] — path, action, changes}
### Implementation Steps
${task.implementation[] — step-by-step guide}
## Done When
${task.convergence.criteria[]}
${task.convergence.verification}
```
### 3.2 Execute Task
**Agent execution**:
```
Agent(subagent_type="code-developer", prompt="{enriched prompt}")
```
**CLI execution**:
```bash
ccw cli -p "{enriched prompt}" --tool {cli_tool} --mode write
```
### 3.3 Record & Persist Result
After each task completes:
- Update `TASK-*.json` with `status`, `executed_at`, `result`
- Track `result.files_modified` for impact verification
- **Persist** result to `TASK-{id}.result.json` alongside the task file:
```json
{
"task_id": "TASK-001",
"status": "completed|failed",
"executed_at": "ISO8601",
"executor": "code-developer|gemini|codex",
"files_modified": [
{ "path": "src/services/auth.ts", "action": "modified", "symbols_changed": ["AuthService.validate"] },
{ "path": "src/routes/login.ts", "action": "created", "symbols_changed": ["loginRoute"] }
],
"convergence_result": {
"criteria_met": ["Rate limiter middleware exists"],
"criteria_unmet": [],
"verification_output": "test output snippet..."
},
"error": null
}
```
This file serves as the durable handoff between execute and sync — survives process interruptions.
---
## Step 4: Per-Batch Impact Verification
After each batch completes (unless `--skip-verify`):
### 4.1 Trace Changed Files
For each file modified in the batch:
```
changed_file → match to doc-index.technicalComponents[].codeLocations[].path
→ component_ids → featureIds → requirementIds
```
### 4.2 Scope Verification
Compare actual impact to planned impact:
```
Planned scope:
Features: [feat-auth]
Components: [tech-auth-service, tech-user-model]
Actual impact:
Features: [feat-auth] ← OK, within scope
Components: [tech-auth-service, tech-user-model, tech-email-service]
← WARNING: tech-email-service not in plan
```
### 4.3 Flag Unexpected Impact
If changes affect features/components NOT in `plan.doc_context`:
- **Warning**: Display unexpected impact
- **No -y**: Ask user to confirm continuation
- **With -y**: Log warning, continue execution
### 4.4 Skip Conditions
Skip verification when:
- `--skip-verify` flag is set
- Only 1 batch (no intermediate verification needed for simple plans)
---
## Step 4.5: Post-Execution Verify Gate
After all batches complete, before doc sync (unless `--skip-verify`):
### 4.5.1 Convergence Verification
For each completed task with `convergence.verification`:
```
Execute: {task.convergence.verification}
→ e.g., "npm test -- --grep rate-limit"
Record: pass/fail → update TASK-{id}.result.json.convergence_result
```
### 4.5.2 Build & Lint Check
```
Run project build command (if configured):
→ npm run build / tsc --noEmit / etc.
Run project lint command (if configured):
→ npm run lint / eslint src/ / etc.
```
If build or lint fails:
- **No -y**: Display errors, ask user: fix now / continue anyway / abort
- **With -y**: Log warning, continue (non-blocking)
### 4.5.3 Regression Test
```
Run project test suite:
→ npm test / pytest / etc.
Compare: test results before execution (baseline) vs after
```
If tests fail:
- **No -y**: Display failures, ask user: fix now / skip sync / abort
- **With -y**: Log failures as warning in execution results, continue
### 4.5.4 Verify Summary
```
Verify Gate Results:
Convergence: {passed}/{total} tasks verified
Build: pass|fail|skipped
Lint: pass|fail|skipped
Tests: {passed}/{total} ({new_failures} regressions)
Gate: PASS / WARN (continue with warnings) / FAIL (blocked)
```
### 4.5.5 Persist Verify Manifest
Write `execution-manifest.json` to session folder:
```json
{
"session_id": "{session-id}",
"plan_path": "planning/{slug}/plan.json",
"completed_at": "ISO8601",
"tasks": [
{
"task_id": "TASK-001",
"status": "completed",
"result_file": ".task/TASK-001.result.json"
}
],
"files_modified": [
{ "path": "src/services/auth.ts", "action": "modified", "task_id": "TASK-001" },
{ "path": "src/routes/login.ts", "action": "created", "task_id": "TASK-001" }
],
"verify": {
"convergence": { "passed": 2, "total": 2 },
"build": "pass",
"lint": "pass",
"tests": { "passed": 42, "total": 42, "regressions": 0 },
"gate": "PASS"
}
}
```
This manifest is the **single source of truth** consumed by `ddd:sync --from-manifest`.
---
## Step 5: Post-Completion Doc Sync
After all batches complete (unless `--skip-sync`):
### 5.1 Auto-Trigger ddd:sync
```
Invoke /ddd:sync [-y] --task-id {session-id} --from-manifest {session}/execution-manifest.json "{plan.summary}"
```
Note: `/ddd:sync` automatically creates a backup of `doc-index.json` before modifications.
When `--from-manifest` is provided, sync uses the **execution manifest** as its primary data source instead of git diff. This ensures:
- Precise file-level and symbol-level change tracking (from TASK-*.result.json)
- Task-to-file attribution (which task modified which file)
- Convergence verification results carried forward
- Survives process interruptions (manifest is persisted to disk)
Fallback: If manifest is unavailable (e.g., manual mode), sync falls back to git diff discovery.
### 5.2 Generate Action Log
Create action entry with:
- All tasks executed and their results
- Files modified across all batches
- Features and requirements addressed
### 5.3 Update Feature Status
Based on execution results:
- Requirements with verified convergence → update status
- Features with all requirements met → `status: "implemented"`
---
## Step 6: Summary & Follow-up
### 6.1 Execution Results
```
DDD Execute Complete
Tasks: {completed}/{total} ({failed} failed)
Files modified: {count}
Batches: {batch_count}
Doc-Index Changes:
Features updated: {list}
Components updated: {list}
New components registered: {list}
Requirements addressed: {list}
Convergence:
{for each task: task.id — criteria met: X/Y}
```
### 6.2 Follow-up Suggestions
Based on execution results, suggest:
- **New issues**: If unexpected scope expansion was detected
- **Additional tests**: If convergence criteria only partially met
- **Documentation gaps**: If new components were created without docs
- **Next tasks**: If plan had tasks marked as future/deferred
---
## Flags
| Flag | Effect |
|------|--------|
| `-y, --yes` | Auto-confirm, auto-sync |
| `--skip-sync` | Skip post-completion ddd:sync (Step 5) |
| `--skip-verify` | Skip per-batch impact verification (Step 4) AND post-execution verify gate (Step 4.5) |
| `--plan <path>` | Explicit plan.json path |
| `--in-memory` | Accept executionContext from ddd:plan handoff |
## Integration Points
- **Input from**: `/ddd:plan` output (plan.json + TASK-*.json), `doc-index.json`
- **Output to**: Updated `doc-index.json` (via ddd:sync), `TASK-*.result.json` (per-task), `execution-manifest.json` (session-level)
- **Schemas**: `plan-overview-ddd-schema.json` (input), `task-schema.json` + `task-ddd-extension-schema.json` (input), `doc-index.json` (enrichment)
- **Delegates to**: `/ddd:sync` for post-completion synchronization

View File

@@ -1,212 +0,0 @@
---
name: index-build
description: Build document index from spec-generator outputs + codebase mapping. Requires existing spec session. For projects without specs, use /ddd:scan instead.
argument-hint: "[-y|--yes] [-s|--spec <spec-session-id>] [--from-scratch]"
allowed-tools: TodoWrite(*), Agent(*), AskUserQuestion(*), Read(*), Grep(*), Glob(*), Bash(*), Edit(*), Write(*), mcp__ace-tool__search_context(*)
---
## Auto Mode
When `--yes` or `-y`: Auto-confirm all decisions, use inferred mappings, skip interactive review.
# DDD Index Build Command (/ddd:index-build)
## Purpose
From **spec-generator outputs** (requirements, architecture, epics), construct the central document index and map spec entities to actual code locations.
```
Spec outputs (REQ, ADR, EPIC) + Codebase → doc-index.json
```
> **No spec?** Use `/ddd:scan` instead — it reverse-engineers the index from code alone.
## Prerequisite
- At least one spec session in `.workflow/.doc-index/specs/` or `.workflow/.spec/`
- If no spec found → error with suggestion: "No spec session found. Run /ddd:scan for code-first indexing, or /spec-generator to create specs."
## Storage Location
```
.workflow/.doc-index/
├── doc-index.json ← Central index (primary output)
├── specs/ ← Spec-generator outputs
│ └── SPEC-{slug}-{date}/
├── feature-maps/ ← Feature documentation (from Epics)
│ ├── _index.md
│ └── {feature-slug}.md
├── tech-registry/ ← Technical component docs (from code mapping)
│ ├── _index.md
│ └── {component-slug}.md
└── action-logs/ ← Change history (initially empty)
└── _index.md
```
## Phase 1: Discover & Parse Spec Sources
### 1.1 Locate Spec Session
```
IF --spec <id> provided:
Load from .workflow/.doc-index/specs/<id>/ OR .workflow/.spec/<id>/
ELSE:
Scan for all SPEC-* directories
IF multiple → present list, ask user to select (-y picks latest)
IF none → ERROR: "No spec session found. Use /ddd:scan or /spec-generator."
```
### 1.2 Migrate Specs (if needed)
If spec in `.workflow/.spec/` but not in `.workflow/.doc-index/specs/`:
- Copy to `.workflow/.doc-index/specs/`
- Preserve original (backward compatibility)
### 1.3 Extract Structured Entities
| Source File | Extract To |
|------------|------------|
| `spec-config.json` | project name, domain, spec_type |
| `glossary.json` | → index glossary[] |
| `product-brief.md` | vision, goals |
| `requirements/REQ-*.md` | → index requirements[] (with MoSCoW priority) |
| `requirements/NFR-*.md` | → index requirements[] (non-functional) |
| `architecture/ADR-*.md` | → index architectureDecisions[] |
| `epics/EPIC-*.md` | → feature grouping seeds |
## Phase 2: Codebase Mapping
Map spec entities to actual code locations using Gemini:
```bash
ccw cli -p "PURPOSE: Map codebase to specification entities for documentation indexing.
TASK:
• Scan the codebase and identify all major modules/components
• For each component: extract file paths, exported symbols (classes, functions, types)
• Match components to these specification entities by name/domain similarity:
Requirements: {REQ-001: desc, REQ-002: desc, ...extracted from Phase 1}
Architecture decisions: {ADR-001: title, ...extracted from Phase 1}
• Report unmatched components (exist in code but no spec counterpart)
• Report unmatched requirements (in spec but no code found)
MODE: analysis
CONTEXT: @**/*
EXPECTED: JSON: { components: [{ name, type, files, symbols, matched_req_ids, matched_adr_id, is_orphan }], unmatched_reqs: [REQ-NNN] }
CONSTRAINTS: Focus on source directories | Ignore node_modules, dist, build" --tool gemini --mode analysis
```
### 2.1 Generate Component IDs & Link
For each discovered component:
- ID: `tech-{kebab-case-name}`
- Link to matched `REQ-NNN` and `ADR-NNN`
- Flag orphans for user review
## Phase 3: Build Feature Map (from Epics)
### 3.1 Epic → Feature Mapping
```
Each EPIC-NNN → one feat-{slug}
- id: feat-{slug} (from epic slug)
- name: from Epic name
- epicId: EPIC-NNN
- status: inferred from code mapping
- all requirements have matched components → "implemented"
- some matched → "in-progress"
- none matched → "planned"
- requirementIds: from Epic's stories → requirement links
- tags: from domain keywords
```
### 3.2 Document Generation (delegated)
Feature-map and tech-registry document generation is handled by `/ddd:doc-generate` in Phase 5.
Phase 3 only builds the data structures (feature → requirement → component mappings) that doc-generate consumes.
## Phase 4: Assemble doc-index.json
```json
{
"version": "1.0",
"project": "{project-name}",
"build_path": "spec-first",
"spec_session": "SPEC-{slug}-{date}",
"last_updated": "ISO8601",
"glossary": [
{ "id": "gloss-{slug}", "term": "Term", "definition": "...", "aliases": [], "category": "core|technical|business" }
],
"features": [
{ "id": "feat-{slug}", "name": "...", "epicId": "EPIC-NNN", "status": "...", "docPath": "feature-maps/{slug}.md", "requirementIds": ["REQ-NNN"], "tags": [] }
],
"requirements": [
{ "id": "REQ-NNN", "title": "...", "source": "spec", "priority": "Must|Should|Could|Won't", "sourcePath": "specs/SPEC-*/requirements/REQ-NNN-*.md", "techComponentIds": ["tech-{slug}"], "featureId": "feat-{slug}" }
],
"technicalComponents": [
{ "id": "tech-{slug}", "name": "...", "type": "...", "responsibility": "...", "adrId": "ADR-NNN|null", "docPath": "tech-registry/{slug}.md", "codeLocations": [{ "path": "...", "symbols": [], "lineRange": [0,0] }], "dependsOn": [], "featureIds": ["feat-{slug}"], "actionIds": [] }
],
"architectureDecisions": [
{ "id": "ADR-NNN", "title": "...", "source": "spec", "sourcePath": "specs/SPEC-*/architecture/ADR-NNN-*.md", "componentIds": ["tech-{slug}"] }
],
"actions": []
}
```
### Merge with Existing Code-First Index
If a code-first index exists (from prior `/ddd:scan`):
- Replace `IREQ-NNN` with matching `REQ-NNN` where content overlaps
- Keep `IREQ-NNN` without spec counterpart (mark `source: "legacy-inferred"`)
- Replace `IADR-NNN` with `ADR-NNN` where applicable
- Update `build_path` to `"spec-first"`
- Preserve existing `tech-*` components (update links only)
## Phase 5: Generate Documents
Delegate all document generation to `/ddd:doc-generate`:
```
Invoke /ddd:doc-generate [-y]
```
This generates the complete document tree (Layer 3 → 2 → 1):
- `tech-registry/{slug}.md` — component docs from Phase 2 mapping (Layer 3)
- `feature-maps/{slug}.md` — feature docs from Phase 3 mapping (Layer 2)
- `_index.md`, `README.md`, `ARCHITECTURE.md`, `SCHEMA.md` — index/overview docs (Layer 1)
See `/ddd:doc-generate` for full details on generation strategy and flags.
## Phase 6: Coverage Report
```
Index Build Report (spec-first)
Spec: {session-id}
Features: {N} (from {N} Epics)
Requirements: {N} (REQ: {n}, NFR: {n})
Components: {N} ({orphan} orphans without spec match)
ADRs: {N}
Mapping Coverage:
Requirements → Components: {%} ({unmapped} unmapped)
Components → Features: {%}
Epics → Features: 100%
Gaps:
- {N} requirements have no matching code component
- {N} code components are not linked to any requirement
```
## Flags
| Flag | Effect |
|------|--------|
| `-y, --yes` | Skip all interactive prompts |
| `-s, --spec <id>` | Use specific spec session |
| `--from-scratch` | Delete existing index and rebuild |
## Integration Points
- **Input from**: `spec-generator` outputs, codebase, existing `/ddd:scan` index
- **Delegates to**: `/ddd:doc-generate` (Phase 5, full document generation)
- **Output to**: `ddd:plan`, `ddd:sync`, `ddd:update`
- **Upgrades**: Can merge with prior code-first (`/ddd:scan`) index

View File

@@ -1,611 +0,0 @@
---
name: plan
description: Document-driven planning pipeline — queries doc-index, explores codebase with doc-aware angles, clarifies ambiguities, and produces unified plan.json + TASK-*.json artifacts with doc_context traceability.
argument-hint: "[-y|--yes] [--explore] [--skip-explore] [--skip-clarify] \"task description or feature keyword\""
allowed-tools: TodoWrite(*), Agent(*), AskUserQuestion(*), Read(*), Grep(*), Glob(*), Bash(*), Write(*), mcp__ace-tool__search_context(*)
---
## Auto Mode
When `--yes` or `-y`: Skip clarification (Phase 3), auto-select ddd:execute (Phase 5), skip interactive refinement.
# DDD Plan Command (/ddd:plan)
## Purpose
Full planning pipeline for document-driven development. Unlike simple context lookup, this command:
1. **Queries** the doc-index for instant context (features, requirements, components, ADRs)
2. **Explores** the codebase with doc-index-informed angles (not generic presets)
3. **Clarifies** ambiguities from exploration results and doc-index gaps
4. **Plans** with unified schema output (plan.json + TASK-*.json with doc_context)
5. **Hands off** to ddd:execute or other execution engines
### Key Differentiation from lite-plan
- Phase 1 provides instant context from doc-index (no cold-start exploration)
- Exploration angles are doc-index-informed (not generic preset selection)
- Tasks carry doc_context for traceability (features → requirements → code)
- Architecture decisions (ADRs) automatically surface as constraints
## Prerequisite
- `doc-index.json` must exist at `.workflow/.doc-index/doc-index.json`
- If not found → suggest running `/ddd:index-build` or `/ddd:scan` first
## Session Folder
```
.workflow/.doc-index/planning/{task-slug}-{YYYY-MM-DD}/
├── exploration-{angle}.json # Per-angle exploration (Phase 2)
├── explorations-manifest.json # Exploration index
├── plan.json # Plan overview (Phase 4)
├── planning-context.md # Legacy context package (Phase 0+1 combined)
├── .process/
│ └── doc-context-package.json # Bundled doc_context (Phase 1.8)
└── .task/
├── TASK-001.json
└── TASK-002.json
```
---
## Phase 0: Parse Task Intent (enhanced)
### 0.1 Extract Keywords
From the user's task description, extract:
- **Domain keywords**: feature names, module names, business terms
- **Technical keywords**: file paths, class names, function names
- **Action type**: feature | bugfix | refactor | optimization | migration
### 0.2 Glossary Match
Cross-reference extracted keywords against `doc-index.json.glossary[]`:
- Match terms and aliases
- Expand user's vocabulary with canonical terms
### 0.3 Classify Complexity
Assess task complexity based on:
- Number of features potentially affected (from keyword matching)
- Whether new components are needed or existing ones modified
- Cross-feature impact (single feature vs multiple)
| Signal | Complexity |
|--------|-----------|
| Single feature, existing components | Low |
| 1-2 features, some new components | Medium |
| 3+ features, new architecture needed | High |
---
## Phase 1: Doc-Index Query
### 1.0 Schema Version Check (TASK-006)
Before querying doc-index, verify schema compatibility:
```javascript
const docIndex = JSON.parse(Read('.workflow/.doc-index/doc-index.json'));
const schemaVersion = docIndex.schema_version || '0.0'; // Default for legacy
if (schemaVersion !== '1.0') {
console.warn(`Schema version mismatch: found ${schemaVersion}, expected 1.0`);
console.warn('Consider running schema migration or regenerating doc-index with /ddd:scan');
// Continue with degraded functionality - may encounter missing fields
}
```
**Graceful degradation**: If version mismatch detected → log warning → continue with caution (some features may not work as expected).
### 1.1 Feature Search
```
Search doc-index.json.features[] where:
- name CONTAINS keyword (fuzzy)
- tags INTERSECT keywords
- requirementIds link to matching requirements
→ Output: matched feature IDs + names
```
### 1.2 Requirement Search
```
Search doc-index.json.requirements[] where:
- title CONTAINS keyword
- id matches explicit REQ-NNN reference
- featureId matches found features
→ Output: matched requirement IDs + titles + priorities
```
### 1.3 Component Search
```
Search doc-index.json.technicalComponents[] where:
- name CONTAINS keyword
- codeLocations[].path CONTAINS file path keyword
- codeLocations[].symbols CONTAINS symbol keyword
- featureIds INTERSECT found features
→ Output: matched component IDs + code locations
```
### 1.4 ADR Search
```
Search doc-index.json.architectureDecisions[] where:
- componentIds INTERSECT found components
→ Output: matched ADR IDs + titles
```
### 1.5 Action History Search
```
Search doc-index.json.actions[] where:
- related to found features or components
→ Output: recent actions with descriptions
```
### 1.6 Build Impact Map
Assemble all found references into a structured impact map:
```json
{
"affected_features": ["feat-auth"],
"affected_requirements": ["REQ-001", "REQ-002"],
"affected_components": ["tech-auth-service", "tech-user-model"],
"architecture_constraints": ["ADR-001"],
"recent_actions": ["task-123"],
"complexity": "Medium"
}
```
Save as `planning-context.md` (legacy format for backward compatibility).
### Phase 1.7: Symbol Query (DeepWiki Bridge)
If DeepWiki is available (`deepwiki_feature_to_symbol_index` exists in doc-index.json):
1. Collect all `codeLocations[].path` from matched `technicalComponents[]`
2. Query DeepWiki: `POST /api/deepwiki/symbols-for-paths { paths: unique_paths }`
3. Build symbol_docs by component, sorted by type priority (class > function > method)
4. Populate `doc_context.symbol_docs[]` with Top-5 symbols per component
**Graceful degradation**: If DeepWiki unavailable → log warning → skip symbol injection → continue flow.
### Phase 1.8: Persist Doc Context Package
After building doc_context (including symbol_docs from Phase 1.7), persist it as a reusable context package:
1. Bundle doc_context into JSON structure:
```json
{
"affected_features": ["feat-auth"],
"affected_requirements": ["REQ-001", "REQ-002"],
"affected_components": ["tech-auth-service"],
"architecture_constraints": ["ADR-001"],
"index_path": ".workflow/.doc-index/doc-index.json",
"symbol_docs": [...]
}
```
2. Write to session folder: `{sessionFolder}/.process/doc-context-package.json`
3. Store relative path for task.json population: `../.process/doc-context-package.json`
**Error handling**: If write fails → log warning → continue without context package (backward compatible).
---
## Phase 2: Doc-Index-Guided Exploration (NEW)
Use Phase 1 results to **SELECT exploration angles intelligently**:
### 2.1 Angle Selection Logic
| Phase 1 Signal | Add Exploration Angle |
|----------------|----------------------|
| feat-auth or security-related ADR affected | `security` |
| Multiple features crossed (2+) | `integration-points` |
| New component needed (no matching tech-*) | `architecture` |
| Performance-related requirements | `performance` |
| Default (always included) | `patterns` + `dependencies` |
Select 1-4 angles total. More angles for higher complexity.
### 2.2 Skip & Trigger Conditions
| Complexity | Default Behavior | Override |
|-----------|-----------------|---------|
| **Low** | Auto-skip Phase 2 | `--explore` forces exploration |
| **Medium** | Ask user (unless `-y` → skip) | `--explore` forces, `--skip-explore` forces skip |
| **High** | Always run | `--skip-explore` forces skip |
Skip Phase 2 entirely when:
- Complexity is Low AND `--explore` not set
- OR `--skip-explore` flag is set
- OR `-y` flag AND complexity is Medium
### 2.3 Parallel Exploration
Launch 1-4 parallel `cli-explore-agent` runs:
```
For each selected angle:
Agent(subagent_type="cli-explore-agent", prompt="
Explore codebase for: {user task description}
Angle: {angle}
## Doc-Index Context (pre-loaded)
Features affected: {feature names + IDs}
Components: {component names + code locations}
Requirements: {requirement titles}
Architecture decisions: {ADR titles + decisions}
Focus exploration on {angle}-specific concerns.
Output: explore-json-schema format.
")
```
Each agent receives doc-index context (feature-maps, tech-registry docs) to avoid cold-start.
### 2.4 Save Exploration Results
- Each exploration → `exploration-{angle}.json` (explore-json-schema)
- Manifest → `explorations-manifest.json`:
```json
{
"explorations": [
{ "angle": "patterns", "path": "exploration-patterns.json", "file_count": 12 },
{ "angle": "security", "path": "exploration-security.json", "file_count": 8 }
],
"total_files_discovered": 18,
"timestamp": "ISO8601"
}
```
---
## Phase 3: Clarification (NEW)
### 3.1 Aggregate Clarification Needs
Collect from three sources:
1. **Exploration results**: `clarification_needs[]` from each exploration JSON
2. **Doc-index gaps**: unmapped requirements, orphan components, missing feature coverage
3. **Conflicting constraints**: contradictory architecture decisions, requirement priority conflicts
### 3.2 Deduplicate & Batch
- Merge duplicate/similar questions across exploration angles
- Group into rounds (max 4 questions per AskUserQuestion call)
- Prioritize: blocking questions first, nice-to-have last
### 3.3 Skip Conditions
Skip Phase 3 when:
- `-y` flag is set
- `--skip-clarify` flag is set
- No clarification needs collected from any source
- Complexity is Low AND Phase 2 was skipped (no exploration results to aggregate)
### 3.4 Execute Clarification
```
AskUserQuestion(questions=[
{
question: "Which authentication strategy should the new endpoint use?",
header: "Auth strategy",
options: [
{ label: "JWT Bearer (Recommended)", description: "Consistent with ADR-001 and existing auth middleware" },
{ label: "API Key", description: "Simpler but inconsistent with current architecture" },
{ label: "OAuth2", description: "Most flexible but higher implementation cost" }
],
multiSelect: false
}
])
```
Feed answers back into Phase 4 as constraints.
---
## Phase 4: Task Planning (NEW — produces plan.json + TASK-*.json)
### 4.1 Planning Strategy Selection
| Complexity | Strategy |
|-----------|---------|
| Low | Direct Claude planning (inline) |
| Medium | cli-lite-planning-agent with doc-index context |
| High | cli-lite-planning-agent with full exploration + doc-index context |
### 4.2 Planning Input Assembly
Combine:
- User's original task description
- Phase 1 impact map (features, requirements, components, ADRs)
- Phase 2 exploration results (if executed)
- Phase 3 clarification answers (if collected)
- Relevant feature-map and tech-registry doc excerpts
### 4.3 Execute Planning
For **Low complexity** (direct):
```
Generate plan.json + TASK-*.json directly based on assembled context.
```
For **Medium/High complexity**:
```
Agent(subagent_type="cli-lite-planning-agent", prompt="
Task: {user task description}
## Doc-Index Impact Map
{Phase 1 results}
## Exploration Context
{Phase 2 results summary}
## Clarification Answers
{Phase 3 answers}
## Architecture Constraints
{ADR excerpts}
Generate plan following plan-overview-base-schema.
Generate tasks following task-schema.
Include doc_context in both plan.json and each TASK-*.json.
")
```
### 4.3.1 Populate Task Artifacts (TASK-002)
After task generation, enrich each TASK-*.json with artifacts[] field:
1. Load doc-index.json from `.workflow/.doc-index/doc-index.json`
2. For each task, extract feature_ids from task.doc_context
3. Filter doc-index features/requirements matching task scope:
- Match by feature_ids in task.doc_context.feature_ids
- Include linked requirements via requirementIds
- Include linked components via componentIds
4. Populate task.artifacts[] with filtered references:
```json
{
"artifacts": [
{
"type": "feature_spec",
"source": "doc-index",
"path": ".workflow/.doc-index/feature-maps/auth.md",
"feature_id": "feat-auth",
"usage": "Reference for authentication requirements"
},
{
"type": "requirement",
"source": "doc-index",
"path": ".workflow/.doc-index/doc-index.json#requirements[0]",
"feature_id": "feat-auth",
"requirement_id": "REQ-001",
"usage": "Acceptance criteria source"
},
{
"type": "component_doc",
"source": "doc-index",
"path": ".workflow/.doc-index/tech-registry/auth-service.md",
"component_id": "tech-auth-service",
"usage": "Implementation reference"
}
]
}
```
**Loading pattern** (following brainstorm pattern from action-planning-agent.md:200-214):
- Load doc-index.json once for catalog
- Filter by task-relevant feature IDs (1-3 per task)
- Only include artifacts directly referenced in task scope
- Use relative paths from task file location
### 4.3.2 Populate Context Package Path (TASK-001)
Set context_package_path field in each TASK-*.json:
```json
{
"context_package_path": "../.process/doc-context-package.json"
}
```
Relative path from `.task/TASK-*.json` to `.process/doc-context-package.json`.
### 4.3.3 Add Navigation Links Block (TASK-003)
Add links{} navigation block to each TASK-*.json for improved discoverability:
```json
{
"links": {
"plan": "../plan.json",
"doc_index": "../../../doc-index.json",
"feature_maps": [
"../../../feature-maps/auth.md"
],
"related_tasks": [
"TASK-002.json",
"TASK-003.json"
]
}
}
```
**Path computation**:
- `plan`: Relative path from `.task/TASK-*.json` to `plan.json` (sibling of .task/)
- `doc_index`: Relative path to `.workflow/.doc-index/doc-index.json`
- `feature_maps`: Paths to feature-map docs from task.doc_context.feature_docs
- `related_tasks`: Task IDs from task.depends_on or tasks sharing same feature_ids
**Backward compatibility**: links{} is optional field (task-schema allows additionalProperties).
### 4.4 Output Schema: plan.json
Follows `plan-overview-base-schema` with ddd-specific `doc_context` extension:
```json
{
"summary": "...",
"approach": "...",
"task_ids": ["TASK-001", "TASK-002"],
"task_count": 2,
"complexity": "Medium",
"doc_context": {
"affected_features": ["feat-auth"],
"affected_requirements": ["REQ-001", "REQ-002"],
"affected_components": ["tech-auth-service"],
"architecture_constraints": ["ADR-001"],
"index_path": ".workflow/.doc-index/doc-index.json",
"symbol_docs": [
{
"symbol_urn": "deepwiki:symbol:<path>#L<start>-L<end>",
"name": "SymbolName",
"type": "class|function|method",
"doc_summary": "Generated documentation summary...",
"source_path": "src/path/to/file.ts",
"doc_path": ".deepwiki/file.md",
"freshness": "fresh|stale|unknown"
}
]
},
"_metadata": {
"timestamp": "ISO8601",
"source": "cli-lite-planning-agent",
"plan_type": "feature",
"schema_version": "2.0",
"exploration_angles": ["patterns", "security"]
}
}
```
### 4.5 Output Schema: TASK-*.json
Follows `task-schema` with ddd-specific `doc_context` extension:
```json
{
"id": "TASK-001",
"title": "Add rate limiting middleware",
"description": "...",
"depends_on": [],
"convergence": {
"criteria": ["Rate limiter middleware exists and is registered", "Tests pass"],
"verification": "npm test -- --grep rate-limit",
"definition_of_done": "API endpoints enforce rate limits per ADR-001 specifications"
},
"doc_context": {
"feature_ids": ["feat-auth"],
"requirement_ids": ["REQ-001"],
"component_ids": ["tech-auth-service"],
"adr_ids": ["ADR-001"],
"feature_docs": ["feature-maps/auth.md"],
"component_docs": ["tech-registry/auth-service.md"],
"symbol_docs": [
{
"symbol_urn": "deepwiki:symbol:<path>#L<start>-L<end>",
"name": "SymbolName",
"type": "class|function|method",
"doc_summary": "Generated documentation summary...",
"source_path": "src/path/to/file.ts",
"doc_path": ".deepwiki/file.md",
"freshness": "fresh|stale|unknown"
}
]
},
"files": [...],
"implementation": [...]
}
```
### 4.6 Enrichment Rules
Each task is enriched with:
- `feature_ids`, `requirement_ids`, `component_ids`, `adr_ids` — traced from Phase 1
- Relevant feature-map and tech-registry doc paths
- Requirement acceptance criteria as convergence criteria source
- ADR decisions as implementation constraints
---
## Phase 5: Confirmation & Handoff Selection
### 5.1 Display Plan Summary
Show:
- Plan overview (summary, approach, complexity)
- Task list with dependencies
- Doc-index impact: which features/requirements/components will be affected
- Estimated scope
### 5.2 Handoff Options
| Option | Description | When |
|--------|-------------|------|
| **ddd:execute** | Document-aware execution (recommended) | Default for ddd workflow |
| **lite-execute** | Standard execution (no doc awareness) | When doc traceability not needed |
| **direct** | Output context, manual work | User prefers manual coding |
| **stop** | Planning only, no execution | Research/analysis tasks |
### 5.3 Auto-Selection
With `-y`: auto-select `ddd:execute`.
Without `-y`: present options via AskUserQuestion.
---
## Phase 6: Handoff
### 6.1 Build Execution Context
Build `executionContext` compatible with lite-execute format:
```json
{
"plan_path": ".workflow/.doc-index/planning/{slug}/plan.json",
"task_dir": ".workflow/.doc-index/planning/{slug}/.task/",
"doc_index_path": ".workflow/.doc-index/doc-index.json",
"exploration_manifest": ".workflow/.doc-index/planning/{slug}/explorations-manifest.json",
"original_input": "user's task description"
}
```
### 6.2 Invoke Selected Engine
| Selection | Action |
|-----------|--------|
| `ddd:execute` | Invoke `/ddd:execute --in-memory` with executionContext |
| `lite-execute` | Invoke `/workflow:lite-execute` with plan.json path |
| `direct` | Display context package + file list for manual work |
| `stop` | Output plan summary, end here |
---
## Flags
| Flag | Effect |
|------|--------|
| `-y, --yes` | Skip clarification, auto-select ddd:execute |
| `--explore` | Force Phase 2 exploration even for Low complexity |
| `--skip-explore` | Skip Phase 2 (doc-index-guided exploration) |
| `--skip-clarify` | Skip Phase 3 (clarification) only |
## Output
- **Primary**: plan.json + TASK-*.json in session folder
- **Secondary**: planning-context.md (legacy format)
- **Exploration**: exploration-{angle}.json files (if Phase 2 ran)
- **Console**: Plan summary with doc-index impact
## Integration Points
- **Input from**: `doc-index.json` (built by `/ddd:index-build` or `/ddd:scan`)
- **Output to**: `/ddd:execute`, `/workflow:lite-execute`, `/ddd:sync` post-task
- **Schemas**: `plan-overview-ddd-schema.json` (plan output), `task-schema.json` + `task-ddd-extension-schema.json` (task output), `explore-json-schema.json`
- **Triggers**: Before any development task in ddd workflow

View File

@@ -1,365 +0,0 @@
---
name: scan
description: Scan existing codebase to build document index without specs. Analyzes code structure, infers features, discovers components, and reverse-engineers project knowledge graph.
argument-hint: "[-y|--yes] [--from-scratch] [--scope <dir>] \"optional project description\""
allowed-tools: TodoWrite(*), Agent(*), AskUserQuestion(*), Read(*), Grep(*), Glob(*), Bash(*), Edit(*), Write(*), mcp__ace-tool__search_context(*)
---
## Auto Mode
When `--yes` or `-y`: Auto-confirm feature groupings, component naming, skip interactive review.
# DDD Scan Command (/ddd:scan)
## Purpose
For **existing projects without specifications**: analyze codebase to construct the document index by reverse-engineering project structure. This is the code-first entry point — no spec-generator required.
```
Codebase → Components → Features (inferred) → Requirements (inferred) → doc-index.json
```
## When to Use
- Existing project, no spec-generator outputs
- Want to start using doc-driven workflow on a legacy codebase
- Quick project mapping for onboarding or audit
## Prerequisite
- A codebase must exist (src/, lib/, app/, or similar source directories)
- Git repository recommended (for action history seeding)
## Storage Location
```
.workflow/.doc-index/
├── doc-index.json ← Central index (primary output)
├── feature-maps/ ← Inferred feature documentation
│ ├── _index.md
│ └── {feature-slug}.md
├── tech-registry/ ← Discovered component documentation
│ ├── _index.md
│ └── {component-slug}.md
└── action-logs/ ← Git history seeds
├── _index.md
└── {act-hash}.md
```
## Phase 1: Project Structure Analysis
### 1.1 Framework & Stack Detection
```bash
ccw cli -p "PURPOSE: Analyze project structure, tech stack, and architecture for documentation indexing.
TASK:
• Detect language/framework from manifest files (package.json, go.mod, Cargo.toml, requirements.txt, etc.)
• Map directory structure: source dirs, test dirs, config dirs, entry points
• Identify architectural pattern: monolith, microservices, monorepo, library, CLI tool
• Detect key dependencies and their roles (ORM, HTTP framework, auth library, etc.)
• List all major source directories with brief purpose description
MODE: analysis
CONTEXT: @**/*
EXPECTED: JSON with: {
project_name, language, framework, architecture_pattern,
source_dirs: [{ path, purpose, file_count }],
dependencies: [{ name, role }],
entry_points: [{ path, description }]
}
CONSTRAINTS: Prioritize source directories | Ignore node_modules, dist, build, vendor" --tool gemini --mode analysis
```
### 1.2 Merge with project-tech.json
If `.workflow/project-tech.json` exists, merge to reduce redundant analysis.
## Phase 2: Component Discovery
### 2.1 Deep Module Scan
```bash
ccw cli -p "PURPOSE: Discover all significant code components/modules for documentation indexing.
TASK:
• For each source directory, identify distinct modules/components
• For each component extract:
- Name (class name, module name, or logical group)
- Type: service | controller | model | util | hook | route | config | middleware | component
- File paths (primary file + related files)
- Exported symbols (public API: classes, functions, types, constants)
- Internal dependencies: what other modules it imports from within the project
- Responsibility: one-line description of what it does
• Group small utility files under parent module when they share domain
MODE: analysis
CONTEXT: @{source_dirs from Phase 1}
EXPECTED: JSON array: [{ name, type, files, symbols, depends_on, responsibility }]
CONSTRAINTS: Focus on business logic | Min threshold: components with 2+ exports or clear domain purpose | Group utilities under parent domain" --tool gemini --mode analysis
```
### 2.2 Generate Component IDs
For each discovered component:
- ID: `tech-{kebab-case-name}` (e.g., `tech-auth-service`, `tech-user-model`)
- Validate uniqueness, append counter on collision
### 2.3 Build Dependency Graph
From `depends_on` fields, construct internal dependency edges:
```
tech-auth-service → tech-user-model
tech-auth-service → tech-jwt-util
tech-order-controller → tech-auth-service
```
## Phase 3: Feature Inference
**Key step: group components into logical features without formal specs.**
### 3.1 Inference Strategy (priority order)
```
Strategy 1 — Directory grouping:
src/auth/** → feat-auth
src/orders/** → feat-orders
src/payments/** → feat-payments
Strategy 2 — Route/endpoint grouping (web apps):
/api/users/* → feat-user-management
/api/orders/* → feat-order-management
Strategy 3 — Dependency clustering:
Components that heavily import each other → same feature
Strategy 4 — Domain keyword extraction:
Class names + file names → domain terms → feature names
```
### 3.2 Gemini Feature Synthesis
```bash
ccw cli -p "PURPOSE: Infer high-level features from discovered code components. This project has no formal specification.
TASK:
Given these discovered components:
{component list from Phase 2: names, types, files, responsibilities, dependencies}
• Group them into logical features (3-10 features for a typical project)
• For each feature:
- name: human-readable (Chinese OK)
- component_ids: which components belong
- description: what the feature does (inferred from code)
- inferred_requirements: what this feature needs to accomplish (1-3 per feature)
- status: 'implemented' (code complete) or 'partial' (incomplete patterns)
- tags: search keywords
• Identify cross-cutting concerns (logging, auth middleware, error handling) as separate features
MODE: analysis
CONTEXT: {component list JSON}
EXPECTED: JSON: { features: [{ name, description, component_ids, inferred_requirements: [{ id, title }], status, tags }] }
CONSTRAINTS: Every component must belong to at least 1 feature | Prefer fewer broad features over many narrow ones" --tool gemini --mode analysis
```
### 3.3 Interactive Feature Review (unless -y)
Present inferred features to user:
- Allow renaming, merging, splitting
- Allow reassigning components between features
- Confirm final feature list
## Phase 4: Implicit Requirement & Architecture Extraction
### 4.1 Inferred Requirements
For each feature, generate lightweight requirement entries from its components:
```
Feature: feat-auth (User Authentication)
→ IREQ-001: "Users can log in with email and password" (from LoginController)
→ IREQ-002: "JWT tokens for session management" (from AuthMiddleware + jwt dep)
→ IREQ-003: "Password reset via email" (from PasswordResetService)
```
**ID Convention**: `IREQ-NNN` — distinguishes inferred from formal `REQ-NNN`.
### 4.2 Inferred Architecture Decisions
Detect patterns from code + dependencies:
```
Express.js + JWT middleware → IADR-001: "REST API with JWT authentication"
Prisma ORM + PostgreSQL → IADR-002: "PostgreSQL via Prisma ORM"
React + Redux → IADR-003: "React frontend with Redux state"
```
**ID Convention**: `IADR-NNN` — distinguishes inferred from formal `ADR-NNN`.
### 4.3 Glossary Generation
Extract domain terms from:
- Class/function names (CamelCase → terms)
- Key business terms in comments and strings
- Framework-specific terminology
Write to `.workflow/.doc-index/glossary.json`.
## Phase 5: Git History Seeds
```bash
git log --oneline --since="3 months ago" --no-merges --format="%H|%s|%ai" | head -30
```
For each significant commit:
- Match changed files to discovered components
- Create action entry with `type: "historical"`
## Phase 6: Assemble doc-index.json
Write the index with code-first markers:
```json
{
"version": "1.0",
"project": "{project-name}",
"build_path": "code-first",
"spec_session": null,
"last_updated": "ISO8601",
"glossary": [...],
"features": [{
"id": "feat-{slug}",
"name": "Feature Name",
"epicId": null,
"status": "implemented|partial",
"docPath": "feature-maps/{slug}.md",
"requirementIds": ["IREQ-NNN"],
"tags": ["tag"]
}],
"requirements": [{
"id": "IREQ-NNN",
"title": "Inferred requirement",
"source": "inferred",
"priority": "inferred",
"sourcePath": null,
"techComponentIds": ["tech-{slug}"],
"featureId": "feat-{slug}"
}],
"technicalComponents": [{
"id": "tech-{slug}",
"name": "ComponentName",
"type": "service|controller|model|...",
"responsibility": "One-line description",
"adrId": "IADR-NNN|null",
"docPath": "tech-registry/{slug}.md",
"codeLocations": [{ "path": "src/...", "symbols": [...] }],
"dependsOn": ["tech-{other}"],
"featureIds": ["feat-{slug}"],
"actionIds": []
}],
"architectureDecisions": [{
"id": "IADR-NNN",
"title": "Inferred decision",
"source": "inferred",
"sourcePath": null,
"componentIds": ["tech-{slug}"]
}],
"actions": [{
"id": "act-{short-hash}",
"description": "Commit message",
"type": "historical",
"status": "historical",
"affectedComponents": ["tech-{slug}"],
"relatedCommit": "full-hash",
"timestamp": "ISO8601"
}],
"freshness": {
"thresholds": { "warning": 0.3, "stale": 0.7 },
"weights": { "time": 0.1, "churn": 0.4, "symbol": 0.5 },
"time_decay_k": 0.05,
"auto_regenerate": false
},
"deepwiki_feature_to_symbol_index": {}
}
```
## Phase 7: Build DeepWiki Feature-to-Symbol Index
If DeepWiki is available (`.codexlens/deepwiki_index.db` exists):
1. Collect all `codeLocations[].path` from `technicalComponents[]`
2. Query DeepWiki: `POST /api/deepwiki/symbols-for-paths { paths: [...] }`
3. Build `deepwiki_feature_to_symbol_index` by traversing:
`feature → requirementIds → techComponentIds → codeLocations → symbols`
```json
"deepwiki_feature_to_symbol_index": {
"feat-auth": [
"deepwiki:symbol:src/auth/jwt.ts#L30-L55",
"deepwiki:symbol:src/models/user.ts#L12-L40"
]
}
```
**Symbol URN format**: `deepwiki:symbol:<file_path>#L<start>-L<end>`
**Graceful degradation**: If DeepWiki is unavailable, set `deepwiki_feature_to_symbol_index: {}` and log warning.
## Phase 8: Generate Documents
Delegate all document generation to `/ddd:doc-generate`:
```
Invoke /ddd:doc-generate [-y]
```
This generates the complete document tree (Layer 3 → 2 → 1):
- `tech-registry/{slug}.md` — component docs (Layer 3)
- `feature-maps/{slug}.md` — feature docs (Layer 2)
- `_index.md`, `README.md`, `ARCHITECTURE.md`, `SCHEMA.md` — index/overview docs (Layer 1)
See `/ddd:doc-generate` for full details on generation strategy and flags.
## Phase 9: Validation & Report
```
Scan Report
Project: {name} ({language}/{framework})
Architecture: {pattern}
Source dirs: {N}
Discovered:
Components: {N} ({by type breakdown})
Features: {N} (inferred)
Requirements: {N} (IREQ, inferred)
Architecture Decisions: {N} (IADR, inferred)
Historical Actions: {N} (from git)
Coverage:
Components → Features: {%}
Dependencies mapped: {%}
Recommendations:
- Run /spec-generator to formalize {N} inferred requirements
- {N} components have unclear responsibility — review tech-registry docs
- Use /ddd:plan to start planning tasks with this index
```
## Flags
| Flag | Effect |
|------|--------|
| `-y, --yes` | Auto-confirm all decisions |
| `--from-scratch` | Delete existing index and rebuild |
| `--scope <dir>` | Limit scan to specific directory (e.g., `--scope src/auth`) |
## Upgrade Path: scan → spec
When a scanned project later runs `spec-generator` + `/ddd:index-build`:
- `/ddd:index-build` detects existing code-first index
- Merges: `IREQ-NNN``REQ-NNN`, `IADR-NNN``ADR-NNN` where content overlaps
- Updates `build_path` to `"spec-first"`
- Preserves all `tech-*` and `feat-*` entries (updates links only)
## Integration Points
- **Input from**: Codebase, git history, `project-tech.json`
- **Delegates to**: `/ddd:doc-generate` (Phase 8, full document generation)
- **Output to**: `ddd:plan`, `ddd:sync`, `ddd:update`, `ddd:index-build` (upgrade)
- **Standalone**: Can be used independently on any project

View File

@@ -1,353 +0,0 @@
---
name: sync
description: Post-task synchronization - update document index, generate action log, and refresh feature/component docs after completing a development task.
argument-hint: "[-y|--yes] [--dry-run] [--from-manifest <path>] [--task-id <id>] [--commit <hash>] \"task summary\""
allowed-tools: TodoWrite(*), Agent(*), AskUserQuestion(*), Read(*), Grep(*), Glob(*), Bash(*), Edit(*), Write(*), mcp__ace-tool__search_context(*)
---
## Auto Mode
When `--yes` or `-y`: Auto-detect changes, auto-update all docs, skip review prompts.
# DDD Sync Command (/ddd:sync)
## Purpose
After completing a development task, synchronize the document index with actual code changes:
1. **Analyze** what changed (git diff)
2. **Trace** which features/requirements/components are affected
3. **Update** index entries (status, code locations, links)
4. **Generate** action log entry
5. **Refresh** feature-map and tech-registry documents
## When to Use: sync vs update
| Scenario | Use |
|----------|-----|
| Task completed, ready to commit | **ddd:sync** — full post-task reconciliation |
| Mid-development, quick impact check | ddd:update |
| Pre-commit validation | ddd:update --check-only |
| Auto-triggered after ddd:execute | **ddd:sync** (automatic) |
| Periodic index refresh during refactoring | ddd:update |
**Rule of thumb**: `sync` = task boundary (done something), `update` = development pulse (doing something).
## Prerequisite
- `doc-index.json` must exist
- Git repository with committed or staged changes
## Phase 0: Consistency Validation
Before processing changes, verify that `doc-index.json` entries are consistent with actual code state.
### 0.1 Validate Code Locations
For each `technicalComponents[].codeLocations[]`:
- Verify file exists on disk
- If file was deleted/moved → flag for removal or update
- If file exists → verify listed `symbols[]` still exist (quick grep/AST check)
### 0.2 Validate Symbols
For components with `codeLocations[].symbols[]`:
- Check each symbol still exists in the referenced file
- Detect new exported symbols not yet tracked
- Report: `{N} stale symbols, {N} untracked symbols`
### 0.3 Validation Report
```
Consistency Check:
Components validated: {N}
Files verified: {N}
Stale references: {N} (files missing or symbols removed)
Untracked symbols: {N} (new exports not in index)
```
If stale references found: warn and auto-fix during Phase 3 updates.
If `--dry-run`: report only, no fixes.
## Phase 1: Change Detection
### 1.0.1 Schema Version Check
Before processing changes, verify doc-index.json schema compatibility:
```javascript
const docIndex = JSON.parse(Read('.workflow/.doc-index/doc-index.json'));
const schemaVersion = docIndex.schema_version || '0.0'; // Default for legacy
if (schemaVersion !== '1.0') {
console.warn(`Schema version mismatch: found ${schemaVersion}, expected 1.0`);
console.warn('Consider running schema migration or regenerating doc-index with /ddd:scan');
// Continue with degraded functionality - may encounter missing fields
}
```
**Graceful degradation**: If version mismatch detected → log warning → continue with caution (some features may not work as expected).
### 1.0 Data Source Selection
```
IF --from-manifest <path>:
Load execution-manifest.json
→ files_modified[] provides precise file list + action type + task attribution
→ TASK-*.result.json provides symbol-level changes + convergence results
→ Skip Phase 1.1/1.2 (already classified by execute)
→ Proceed directly to Phase 2 with manifest data
ELSE:
→ Fall through to Phase 1.1 (git-based discovery)
```
**`--from-manifest` advantages** (used automatically by ddd:execute):
- Precise file → task attribution (which task modified which file)
- Symbol-level change tracking (not just file-level)
- Convergence verification results carried forward to action-log
- Survives process interruptions (manifest is persisted to disk)
### 1.1 Identify Changes (git-based fallback)
```bash
# If --commit provided:
git diff --name-only {commit}^..{commit}
git diff --stat {commit}^..{commit}
# If --task-id provided, find related commits:
git log --oneline --grep="task-{id}" | head -10
# Otherwise: changes since last ddd:sync
git diff --name-only HEAD~1..HEAD
```
### 1.2 Classify Changes (git-based fallback)
For each changed file, determine:
- **Type**: added | modified | deleted | renamed
- **Category**: source | test | config | docs | other
- **Symbols affected**: parse diff for changed functions/classes (use Gemini if complex)
## Phase 2: Impact Tracing (Layer-Based, TASK-004)
**Strategy**: Trace impact through layers (files → components → features → indexes) following memory-manage pattern.
### 2.1 Match to Index
For each changed file path:
```
Search doc-index.json.technicalComponents[].codeLocations[].path
→ Find matching component IDs (Layer 3)
→ From components, find linked featureIds (Layer 2)
→ From features, find linked requirementIds (Layer 2)
```
### 2.2 Discover New Components
If changed files don't match any existing component:
- Flag as potential new component
- Ask user if it should be registered (or auto-register with `-y`)
### 2.3 Build Impact Report
```markdown
## Impact Summary
### Changed Files (5)
- src/services/auth.ts (modified) → tech-auth-service → feat-auth
- src/models/user.ts (modified) → tech-user-model → feat-auth
- src/routes/login.ts (added) → NEW COMPONENT → feat-auth
- src/tests/auth.test.ts (modified) → [test file, skip]
- package.json (modified) → [config, skip]
### Affected Features
- feat-auth: User Authentication (2 components modified, 1 new)
### Affected Requirements
- REQ-001: Email login (implementation updated)
- REQ-002: JWT token generation (implementation updated)
```
## Phase 2.4: DeepWiki Freshness Check
If DeepWiki integration is configured (`doc-index.json.freshness` exists):
### 2.4.1 Identify Modified Files
From `execution-manifest.json` or git diff, collect `files_modified[]` with `action == "modified"`.
### 2.4.2 Check Staleness
Query DeepWiki: `POST /api/deepwiki/stale-files { files: [{path, hash}] }`
For each stale file's symbols, calculate staleness score:
```
S(symbol) = min(1.0, w_t × T + w_c × C + w_s × M)
```
Where weights come from `doc-index.json.freshness.weights`.
### 2.4.3 Score Propagation (max aggregation)
```
S_file = max(S_symbol_1, S_symbol_2, ...)
S_component = max(S_file_1, S_file_2, ...)
S_feature = max(S_component_1, S_component_2, ...)
```
### 2.4.4 Status Assignment
Using thresholds from `doc-index.json.freshness.thresholds`:
- `fresh`: score in [0, warning_threshold)
- `warning`: score in [warning_threshold, stale_threshold)
- `stale`: score in [stale_threshold, 1.0]
### 2.4.5 Update Records
- Update `deepwiki_symbols.staleness_score` and `deepwiki_files.staleness_score` in DeepWiki SQLite
- Update `tech-registry/{slug}.md` YAML frontmatter with freshness block
- Update `feature-maps/{slug}.md` YAML frontmatter with freshness block
- Update `deepwiki_feature_to_symbol_index` in doc-index.json
### 2.4.6 Staleness Report
Add to action-log:
- Number of stale symbols/files/components
- Top-5 most stale items with scores
- Auto-regeneration candidates (if `auto_regenerate: true` and score >= stale threshold)
## Phase 3: Update Index
### 3.0 Dry-Run Gate
If `--dry-run` is set:
- Execute Phase 3 analysis (determine what would change)
- Display planned modifications as a preview report
- Skip all file writes (Phase 3.1-3.5 and Phase 4)
- Output: "Dry-run complete. Run without --dry-run to apply changes."
### 3.0.1 Backup Index
Before any modifications, create backup:
- Copy `doc-index.json``doc-index.json.bak`
- On failure: restore from `.bak` and report error
- On success: remove `.bak`
### 3.1 Update Technical Components
For each affected component in `doc-index.json`:
- Update `codeLocations` if file paths or line ranges changed
- Update `symbols` if new exports were added
- Add new `actionIds` entry
- **Auto-update `responsibility`**: If symbols changed (new methods/exports added or removed), re-infer responsibility from current symbols list using Gemini analysis. This prevents stale descriptions (e.g., responsibility still says "登录、注册" after adding logout support)
### 3.2 Register New Components
For newly discovered components:
- Generate `tech-{slug}` ID
- Create entry in `technicalComponents[]`
- Link to appropriate features
- Generate new `tech-registry/{slug}.md` document
### 3.3 Update Feature Status
For each affected feature:
- If all requirements now have mapped components → `status: "implemented"`
- If some requirements still unmapped → `status: "in-progress"`
### 3.4 Add Action Entry
```json
{
"id": "task-{id}",
"description": "{task summary from user}",
"type": "feature|bugfix|refactor",
"status": "completed",
"affectedFeatures": ["feat-auth"],
"affectedComponents": ["tech-auth-service", "tech-user-model"],
"changedFiles": [
{ "path": "src/services/auth.ts", "action": "modified", "task_id": "TASK-001" },
{ "path": "src/models/user.ts", "action": "modified", "task_id": "TASK-001" }
],
"symbolsChanged": ["AuthService.validate", "UserModel.toJSON"],
"convergenceResults": {
"passed": 2,
"total": 2,
"details": ["Rate limiter middleware exists", "Config accepts per-route limits"]
},
"verifyGate": "PASS|WARN|FAIL|skipped",
"relatedCommit": "{commit hash}",
"manifestPath": "{execution-manifest.json path | null}",
"timestamp": "ISO8601"
}
```
### 3.5 Update Timestamp
Set `doc-index.json.last_updated` to current time.
## Phase 4: Refresh Documents & Action Log
### 4.1 Delegate Document Refresh to /ddd:doc-refresh
From Phase 2 impact tracing, collect affected component and feature IDs, then delegate:
```
Invoke /ddd:doc-refresh [-y] --components {affected_component_ids} --features {affected_feature_ids}
```
This handles Layer 3 → 2 → 1 selective document refresh. See `/ddd:doc-refresh` for full details.
### 4.2 Generate Action Log Entry
Create `.workflow/.doc-index/action-logs/{task-id}.md`:
```markdown
---
id: task-{id}
type: feature|bugfix|refactor
status: completed
features: [feat-auth]
components: [tech-auth-service, tech-user-model]
commit: {hash}
timestamp: ISO8601
---
# Task: {summary}
## Changes
| File | Type | Component |
|------|------|-----------|
| src/services/auth.ts | modified | tech-auth-service |
## Impact
- Features affected: feat-auth
- Requirements addressed: REQ-001, REQ-002
## Staleness (if DeepWiki freshness enabled)
| Item | Type | Score | Status |
|------|------|-------|--------|
| {symbol/file/component} | {type} | {score} | {fresh/warning/stale} |
## Notes
{any user-provided notes}
```
## Phase 5: Confirmation (unless -y)
Present update summary to user:
- Files updated in doc-index
- New documents created
- Status changes
- Ask for confirmation before writing
## Flags
| Flag | Effect |
|------|--------|
| `-y, --yes` | Auto-confirm all updates |
| `--dry-run` | Preview all changes without modifying any files |
| `--from-manifest <path>` | Use execution-manifest.json as data source (auto-set by ddd:execute) |
| `--task-id <id>` | Associate with specific task ID |
| `--commit <hash>` | Analyze specific commit |
## Integration Points
- **Input from**: `execution-manifest.json` (preferred, from ddd:execute) OR Git history (fallback), `doc-index.json`, `/ddd:plan` output
- **Delegates to**: `/ddd:doc-refresh` (Phase 4.1, selective document refresh)
- **Output to**: Updated `doc-index.json`, feature-maps/, tech-registry/, action-logs/
- **Triggers**: After completing any development task
- **Data source priority**: `--from-manifest` > `--commit` > `--task-id` > git diff HEAD~1

View File

@@ -1,160 +0,0 @@
---
name: update
description: Incremental index update - detect code changes and trace impact to related features/requirements. Lightweight alternative to full sync.
argument-hint: "[-y|--yes] [--files <file1,file2,...>] [--staged] [--check-only]"
allowed-tools: TodoWrite(*), AskUserQuestion(*), Read(*), Grep(*), Glob(*), Bash(*), Edit(*), Write(*), mcp__ace-tool__search_context(*)
---
## Auto Mode
When `--yes` or `-y`: Auto-update index without confirmation prompts.
# DDD Update Command (/ddd:update)
## Purpose
Lightweight incremental update: given a set of changed files, trace their impact through the document index and update affected entries. Unlike `/ddd:sync` (full post-task sync), this command focuses on keeping the index fresh during development.
## When to Use: update vs sync
| Scenario | Use |
|----------|-----|
| Quick impact check during development | **ddd:update** |
| Preview what sync would change | **ddd:update --check-only** |
| Task completed, full reconciliation | ddd:sync |
| Register new components + update all docs | ddd:sync |
**Rule of thumb**: `update` = lightweight pulse (during work), `sync` = full checkpoint (after work).
## Use Cases
1. **During development**: Quick check which docs are affected by current changes
2. **Pre-commit check**: Ensure index is up-to-date before committing
3. **Periodic refresh**: Update stale code locations after refactoring
## Prerequisite
- `doc-index.json` must exist at `.workflow/.doc-index/doc-index.json`
## Phase 1: Identify Changed Files
### Source Priority
```
1. --files <list> → Explicit file list
2. --staged → git diff --cached --name-only
3. (default) → git diff --name-only (unstaged changes)
```
### Output
List of changed file paths with change type (added/modified/deleted/renamed).
## Phase 2: Trace Impact
### 2.1 Forward Lookup (Code → Components → Features)
For each changed file:
```
doc-index.json.technicalComponents[]
.codeLocations[].path MATCH changed_file
→ component_ids[]
doc-index.json.technicalComponents[component_ids]
.featureIds[]
→ feature_ids[]
doc-index.json.features[feature_ids]
.requirementIds[]
→ requirement_ids[]
```
### 2.2 Orphan Detection
Files not matching any component → flag as:
- **Potential new component**: if in src/ directory
- **Ignorable**: if in test/, docs/, config/ directories
### 2.3 Impact Report
```
Impact Analysis for 3 changed files:
src/services/auth.ts (modified)
→ Component: tech-auth-service (AuthService)
→ Feature: feat-auth (User Authentication)
→ Requirements: REQ-001, REQ-002
src/middleware/rate-limit.ts (added)
→ No matching component (new file)
→ Suggested: Register as new component
src/utils/hash.ts (modified)
→ Component: tech-hash-util
→ Features: feat-auth, feat-password-reset
→ Requirements: REQ-001, REQ-005
```
## Phase 3: Update Index (unless --check-only)
### 3.1 Update Code Locations
For matched components:
- If file was renamed → update `codeLocations[].path`
- If file was deleted → remove code location entry
- If symbols changed → update `symbols` list (requires AST or Gemini analysis)
### 3.2 Register New Components (interactive unless -y)
For orphan files in src/:
- Prompt user for component name and type
- Or auto-generate with `-y`: derive name from file path
- Create `technicalComponents[]` entry
- Ask which feature it belongs to (or auto-link by directory structure)
### 3.3 Update Timestamps
- Update `technicalComponents[].docPath` last_updated in corresponding .md
- Update `doc-index.json.last_updated`
## Phase 4: Refresh Documents (if updates were made)
### 4.1 Delegate to /ddd:doc-refresh
From Phase 2 impact tracing, collect affected component and feature IDs, then delegate:
```
Invoke /ddd:doc-refresh [-y] --minimal --components {affected_component_ids} --features {affected_feature_ids}
```
The `--minimal` flag ensures only metadata/frontmatter is updated (code locations, timestamps), skipping full content regeneration. This keeps the update lightweight.
See `/ddd:doc-refresh` for full details.
### 4.2 Skip If --check-only
With `--check-only`, skip Phase 3 and Phase 4 entirely — only output the impact report.
## Flags
| Flag | Effect |
|------|--------|
| `-y, --yes` | Auto-confirm updates |
| `--files <list>` | Explicit comma-separated file list |
| `--staged` | Analyze staged (git cached) files |
| `--check-only` | Report impact without modifying index |
## Output
- **Console**: Impact report showing affected features/requirements
- **Updated**: `doc-index.json` (if not --check-only)
- **Updated**: Affected tech-registry/ and feature-maps/ docs
## Integration Points
- **Input from**: Git working tree, `doc-index.json`
- **Delegates to**: `/ddd:doc-refresh` (Phase 4.1, incremental document refresh with --minimal)
- **Output to**: Updated `doc-index.json`, impact report
- **Triggers**: During development, pre-commit, or periodic refresh
- **Can chain to**: `/ddd:sync` for full post-task synchronization

View File

@@ -1,287 +0,0 @@
---
name: add
description: Add IDAW tasks - manual creation or import from ccw issue
argument-hint: "[-y|--yes] [--from-issue <id>[,<id>,...]] \"description\" [--type <task_type>] [--priority <1-5>]"
allowed-tools: AskUserQuestion(*), Read(*), Bash(*), Write(*), Glob(*)
---
# IDAW Add Command (/idaw:add)
## Auto Mode
When `--yes` or `-y`: Skip clarification questions, create task with inferred details.
## IDAW Task Schema
```json
{
"id": "IDAW-001",
"title": "string",
"description": "string",
"status": "pending",
"priority": 2,
"task_type": null,
"skill_chain": null,
"context": {
"affected_files": [],
"acceptance_criteria": [],
"constraints": [],
"references": []
},
"source": {
"type": "manual|import-issue",
"issue_id": null,
"issue_snapshot": null
},
"execution": {
"session_id": null,
"started_at": null,
"completed_at": null,
"skill_results": [],
"git_commit": null,
"error": null
},
"created_at": "ISO",
"updated_at": "ISO"
}
```
**Valid task_type values**: `bugfix|bugfix-hotfix|feature|feature-complex|refactor|tdd|test|test-fix|review|docs`
## Implementation
### Phase 1: Parse Arguments
```javascript
const args = $ARGUMENTS;
const autoYes = /(-y|--yes)\b/.test(args);
const fromIssue = args.match(/--from-issue\s+([\w,-]+)/)?.[1];
const typeFlag = args.match(/--type\s+([\w-]+)/)?.[1];
const priorityFlag = args.match(/--priority\s+(\d)/)?.[1];
// Extract description: content inside quotes (preferred), or fallback to stripping flags
const quotedMatch = args.match(/(?:^|\s)["']([^"']+)["']/);
const description = quotedMatch
? quotedMatch[1].trim()
: args.replace(/(-y|--yes|--from-issue\s+[\w,-]+|--type\s+[\w-]+|--priority\s+\d)/g, '').trim();
```
### Phase 2: Route — Import or Manual
```
--from-issue present?
├─ YES → Import Mode (Phase 3A)
└─ NO → Manual Mode (Phase 3B)
```
### Phase 3A: Import Mode (from ccw issue)
```javascript
const issueIds = fromIssue.split(',');
// Fetch all issues once (outside loop)
let issues = [];
try {
const issueJson = Bash(`ccw issue list --json`);
issues = JSON.parse(issueJson).issues || [];
} catch (e) {
console.log(`Error fetching CCW issues: ${e.message || e}`);
console.log('Ensure ccw is installed and issues exist. Use /issue:new to create issues first.');
return;
}
for (const issueId of issueIds) {
// 1. Find issue data
const issue = issues.find(i => i.id === issueId.trim());
if (!issue) {
console.log(`Warning: Issue ${issueId} not found, skipping`);
continue;
}
// 2. Check duplicate (same issue_id already imported)
const existing = Glob('.workflow/.idaw/tasks/IDAW-*.json');
for (const f of existing) {
const data = JSON.parse(Read(f));
if (data.source?.issue_id === issueId.trim()) {
console.log(`Warning: Issue ${issueId} already imported as ${data.id}, skipping`);
continue; // skip to next issue
}
}
// 3. Generate next IDAW ID
const nextId = generateNextId();
// 4. Map issue → IDAW task
const task = {
id: nextId,
title: issue.title,
description: issue.context || issue.title,
status: 'pending',
priority: parseInt(priorityFlag) || issue.priority || 3,
task_type: typeFlag || inferTaskType(issue.title, issue.context || ''),
skill_chain: null,
context: {
affected_files: issue.affected_components || [],
acceptance_criteria: [],
constraints: [],
references: issue.source_url ? [issue.source_url] : []
},
source: {
type: 'import-issue',
issue_id: issue.id,
issue_snapshot: {
id: issue.id,
title: issue.title,
status: issue.status,
context: issue.context,
priority: issue.priority,
created_at: issue.created_at
}
},
execution: {
session_id: null,
started_at: null,
completed_at: null,
skill_results: [],
git_commit: null,
error: null
},
created_at: new Date().toISOString(),
updated_at: new Date().toISOString()
};
// 5. Write task file
Bash('mkdir -p .workflow/.idaw/tasks');
Write(`.workflow/.idaw/tasks/${nextId}.json`, JSON.stringify(task, null, 2));
console.log(`Created ${nextId} from issue ${issueId}: ${issue.title}`);
}
```
### Phase 3B: Manual Mode
```javascript
// 1. Validate description
if (!description && !autoYes) {
const answer = AskUserQuestion({
questions: [{
question: 'Please provide a task description:',
header: 'Task',
multiSelect: false,
options: [
{ label: 'Provide description', description: 'What needs to be done?' }
]
}]
});
// Use custom text from "Other"
description = answer.customText || '';
}
if (!description) {
console.log('Error: No description provided. Usage: /idaw:add "task description"');
return;
}
// 2. Generate next IDAW ID
const nextId = generateNextId();
// 3. Build title from first sentence
const title = description.split(/[.\n]/)[0].substring(0, 80).trim();
// 4. Determine task_type
const taskType = typeFlag || null; // null → inferred at run time
// 5. Create task
const task = {
id: nextId,
title: title,
description: description,
status: 'pending',
priority: parseInt(priorityFlag) || 3,
task_type: taskType,
skill_chain: null,
context: {
affected_files: [],
acceptance_criteria: [],
constraints: [],
references: []
},
source: {
type: 'manual',
issue_id: null,
issue_snapshot: null
},
execution: {
session_id: null,
started_at: null,
completed_at: null,
skill_results: [],
git_commit: null,
error: null
},
created_at: new Date().toISOString(),
updated_at: new Date().toISOString()
};
Bash('mkdir -p .workflow/.idaw/tasks');
Write(`.workflow/.idaw/tasks/${nextId}.json`, JSON.stringify(task, null, 2));
console.log(`Created ${nextId}: ${title}`);
```
## Helper Functions
### ID Generation
```javascript
function generateNextId() {
const files = Glob('.workflow/.idaw/tasks/IDAW-*.json') || [];
if (files.length === 0) return 'IDAW-001';
const maxNum = files
.map(f => parseInt(f.match(/IDAW-(\d+)/)?.[1] || '0'))
.reduce((max, n) => Math.max(max, n), 0);
return `IDAW-${String(maxNum + 1).padStart(3, '0')}`;
}
```
### Task Type Inference (deferred — used at run time if task_type is null)
```javascript
function inferTaskType(title, description) {
const text = `${title} ${description}`.toLowerCase();
if (/urgent|production|critical/.test(text) && /fix|bug/.test(text)) return 'bugfix-hotfix';
if (/refactor|重构|tech.*debt/.test(text)) return 'refactor';
if (/tdd|test-driven|test first/.test(text)) return 'tdd';
if (/test fail|fix test|failing test/.test(text)) return 'test-fix';
if (/generate test|写测试|add test/.test(text)) return 'test';
if (/review|code review/.test(text)) return 'review';
if (/docs|documentation|readme/.test(text)) return 'docs';
if (/fix|bug|error|crash|fail/.test(text)) return 'bugfix';
if (/complex|multi-module|architecture/.test(text)) return 'feature-complex';
return 'feature';
}
```
## Examples
```bash
# Manual creation
/idaw:add "Fix login timeout bug" --type bugfix --priority 2
/idaw:add "Add rate limiting to API endpoints" --priority 1
/idaw:add "Refactor auth module to use strategy pattern"
# Import from ccw issue
/idaw:add --from-issue ISS-20260128-001
/idaw:add --from-issue ISS-20260128-001,ISS-20260128-002 --priority 1
# Auto mode (skip clarification)
/idaw:add -y "Quick fix for typo in header"
```
## Output
```
Created IDAW-001: Fix login timeout bug
Type: bugfix | Priority: 2 | Source: manual
→ Next: /idaw:run or /idaw:status
```

View File

@@ -1,442 +0,0 @@
---
name: resume
description: Resume interrupted IDAW session from last checkpoint
argument-hint: "[-y|--yes] [session-id]"
allowed-tools: Skill(*), TodoWrite(*), AskUserQuestion(*), Read(*), Write(*), Bash(*), Glob(*)
---
# IDAW Resume Command (/idaw:resume)
## Auto Mode
When `--yes` or `-y`: Auto-skip interrupted task, continue with remaining.
## Skill Chain Mapping
```javascript
const SKILL_CHAIN_MAP = {
'bugfix': ['workflow-lite-plan', 'workflow-test-fix'],
'bugfix-hotfix': ['workflow-lite-plan'],
'feature': ['workflow-lite-plan', 'workflow-test-fix'],
'feature-complex': ['workflow-plan', 'workflow-execute', 'workflow-test-fix'],
'refactor': ['workflow:refactor-cycle'],
'tdd': ['workflow-tdd-plan', 'workflow-execute'],
'test': ['workflow-test-fix'],
'test-fix': ['workflow-test-fix'],
'review': ['review-cycle'],
'docs': ['workflow-lite-plan']
};
```
## Task Type Inference
```javascript
function inferTaskType(title, description) {
const text = `${title} ${description}`.toLowerCase();
if (/urgent|production|critical/.test(text) && /fix|bug/.test(text)) return 'bugfix-hotfix';
if (/refactor|重构|tech.*debt/.test(text)) return 'refactor';
if (/tdd|test-driven|test first/.test(text)) return 'tdd';
if (/test fail|fix test|failing test/.test(text)) return 'test-fix';
if (/generate test|写测试|add test/.test(text)) return 'test';
if (/review|code review/.test(text)) return 'review';
if (/docs|documentation|readme/.test(text)) return 'docs';
if (/fix|bug|error|crash|fail/.test(text)) return 'bugfix';
if (/complex|multi-module|architecture/.test(text)) return 'feature-complex';
return 'feature';
}
```
## Implementation
### Phase 1: Find Resumable Session
```javascript
const args = $ARGUMENTS;
const autoYes = /(-y|--yes)/.test(args);
const targetSessionId = args.replace(/(-y|--yes)/g, '').trim();
let session = null;
let sessionDir = null;
if (targetSessionId) {
// Load specific session
sessionDir = `.workflow/.idaw/sessions/${targetSessionId}`;
try {
session = JSON.parse(Read(`${sessionDir}/session.json`));
} catch {
console.log(`Session "${targetSessionId}" not found.`);
console.log('Use /idaw:status to list sessions, or /idaw:run to start a new one.');
return;
}
} else {
// Find most recent running session
const sessionFiles = Glob('.workflow/.idaw/sessions/IDA-*/session.json') || [];
for (const f of sessionFiles) {
try {
const s = JSON.parse(Read(f));
if (s.status === 'running') {
session = s;
sessionDir = f.replace(/\/session\.json$/, '').replace(/\\session\.json$/, '');
break;
}
} catch {
// Skip malformed
}
}
if (!session) {
console.log('No running sessions found to resume.');
console.log('Use /idaw:run to start a new execution.');
return;
}
}
console.log(`Resuming session: ${session.session_id}`);
```
### Phase 2: Handle Interrupted Task
```javascript
// Find the task that was in_progress when interrupted
let currentTaskId = session.current_task;
let currentTask = null;
if (currentTaskId) {
try {
currentTask = JSON.parse(Read(`.workflow/.idaw/tasks/${currentTaskId}.json`));
} catch {
console.log(`Warning: Could not read task ${currentTaskId}`);
currentTaskId = null;
}
}
if (currentTask && currentTask.status === 'in_progress') {
if (autoYes) {
// Auto: skip interrupted task
currentTask.status = 'skipped';
currentTask.execution.error = 'Skipped on resume (auto mode)';
currentTask.execution.completed_at = new Date().toISOString();
currentTask.updated_at = new Date().toISOString();
Write(`.workflow/.idaw/tasks/${currentTaskId}.json`, JSON.stringify(currentTask, null, 2));
session.skipped.push(currentTaskId);
console.log(`Skipped interrupted task: ${currentTaskId}`);
} else {
const answer = AskUserQuestion({
questions: [{
question: `Task ${currentTaskId} was interrupted: "${currentTask.title}". How to proceed?`,
header: 'Resume',
multiSelect: false,
options: [
{ label: 'Retry', description: 'Reset to pending, re-execute from beginning' },
{ label: 'Skip', description: 'Mark as skipped, move to next task' }
]
}]
});
if (answer.answers?.Resume === 'Skip') {
currentTask.status = 'skipped';
currentTask.execution.error = 'Skipped on resume (user choice)';
currentTask.execution.completed_at = new Date().toISOString();
currentTask.updated_at = new Date().toISOString();
Write(`.workflow/.idaw/tasks/${currentTaskId}.json`, JSON.stringify(currentTask, null, 2));
session.skipped.push(currentTaskId);
} else {
// Retry: reset to pending
currentTask.status = 'pending';
currentTask.execution.started_at = null;
currentTask.execution.completed_at = null;
currentTask.execution.skill_results = [];
currentTask.execution.error = null;
currentTask.updated_at = new Date().toISOString();
Write(`.workflow/.idaw/tasks/${currentTaskId}.json`, JSON.stringify(currentTask, null, 2));
}
}
}
```
### Phase 3: Build Remaining Task Queue
```javascript
// Collect remaining tasks (pending, or the retried current task)
const allTaskIds = session.tasks;
const completedSet = new Set([...session.completed, ...session.failed, ...session.skipped]);
const remainingTasks = [];
for (const taskId of allTaskIds) {
if (completedSet.has(taskId)) continue;
try {
const task = JSON.parse(Read(`.workflow/.idaw/tasks/${taskId}.json`));
if (task.status === 'pending') {
remainingTasks.push(task);
}
} catch {
console.log(`Warning: Could not read task ${taskId}, skipping`);
}
}
if (remainingTasks.length === 0) {
console.log('No remaining tasks to execute. Session complete.');
session.status = 'completed';
session.current_task = null;
session.updated_at = new Date().toISOString();
Write(`${sessionDir}/session.json`, JSON.stringify(session, null, 2));
return;
}
// Sort: priority ASC, then ID ASC
remainingTasks.sort((a, b) => {
if (a.priority !== b.priority) return a.priority - b.priority;
return a.id.localeCompare(b.id);
});
console.log(`Remaining tasks: ${remainingTasks.length}`);
// Append resume marker to progress.md
const progressFile = `${sessionDir}/progress.md`;
try {
const currentProgress = Read(progressFile);
Write(progressFile, currentProgress + `\n---\n**Resumed**: ${new Date().toISOString()}\n\n`);
} catch {
Write(progressFile, `# IDAW Progress — ${session.session_id}\n\n---\n**Resumed**: ${new Date().toISOString()}\n\n`);
}
// Update TodoWrite
TodoWrite({
todos: remainingTasks.map((t, i) => ({
content: `IDAW:[${i + 1}/${remainingTasks.length}] ${t.title}`,
status: i === 0 ? 'in_progress' : 'pending',
activeForm: `Executing ${t.title}`
}))
});
```
### Phase 4-6: Execute Remaining (reuse run.md main loop)
Execute remaining tasks using the same Phase 4-6 logic from `/idaw:run`:
```javascript
// Phase 4: Main Loop — identical to run.md Phase 4
for (let taskIdx = 0; taskIdx < remainingTasks.length; taskIdx++) {
const task = remainingTasks[taskIdx];
// Resolve skill chain
const resolvedType = task.task_type || inferTaskType(task.title, task.description);
const chain = task.skill_chain || SKILL_CHAIN_MAP[resolvedType] || SKILL_CHAIN_MAP['feature'];
// Update task → in_progress
task.status = 'in_progress';
task.task_type = resolvedType;
task.execution.started_at = new Date().toISOString();
Write(`.workflow/.idaw/tasks/${task.id}.json`, JSON.stringify(task, null, 2));
session.current_task = task.id;
session.updated_at = new Date().toISOString();
Write(`${sessionDir}/session.json`, JSON.stringify(session, null, 2));
console.log(`\n--- [${taskIdx + 1}/${remainingTasks.length}] ${task.id}: ${task.title} ---`);
console.log(`Chain: ${chain.join(' → ')}`);
// ━━━ Pre-Task CLI Context Analysis (for complex/bugfix tasks) ━━━
if (['bugfix', 'bugfix-hotfix', 'feature-complex'].includes(resolvedType)) {
console.log(` Pre-analysis: gathering context for ${resolvedType} task...`);
const affectedFiles = (task.context?.affected_files || []).join(', ');
const preAnalysisPrompt = `PURPOSE: Pre-analyze codebase context for IDAW task before execution.
TASK: • Understand current state of: ${affectedFiles || 'files related to: ' + task.title} • Identify dependencies and risk areas • Note existing patterns to follow
MODE: analysis
CONTEXT: @**/*
EXPECTED: Brief context summary (affected modules, dependencies, risk areas) in 3-5 bullet points
CONSTRAINTS: Keep concise | Focus on execution-relevant context`;
const preAnalysis = Bash(`ccw cli -p '${preAnalysisPrompt.replace(/'/g, "'\\''")}' --tool gemini --mode analysis 2>&1 || echo "Pre-analysis skipped"`);
task.execution.skill_results.push({
skill: 'cli-pre-analysis',
status: 'completed',
context_summary: preAnalysis?.substring(0, 500),
timestamp: new Date().toISOString()
});
}
// Execute skill chain
let previousResult = null;
let taskFailed = false;
for (let skillIdx = 0; skillIdx < chain.length; skillIdx++) {
const skillName = chain[skillIdx];
const skillArgs = assembleSkillArgs(skillName, task, previousResult, autoYes, skillIdx === 0);
console.log(` [${skillIdx + 1}/${chain.length}] ${skillName}`);
try {
const result = Skill({ skill: skillName, args: skillArgs });
previousResult = result;
task.execution.skill_results.push({
skill: skillName,
status: 'completed',
timestamp: new Date().toISOString()
});
} catch (error) {
// ━━━ CLI-Assisted Error Recovery ━━━
console.log(` Diagnosing failure: ${skillName}...`);
const diagnosisPrompt = `PURPOSE: Diagnose why skill "${skillName}" failed during IDAW task execution.
TASK: • Analyze error: ${String(error).substring(0, 300)} • Check affected files: ${(task.context?.affected_files || []).join(', ') || 'unknown'} • Identify root cause • Suggest fix strategy
MODE: analysis
CONTEXT: @**/* | Memory: IDAW task ${task.id}: ${task.title}
EXPECTED: Root cause + actionable fix recommendation (1-2 sentences)
CONSTRAINTS: Focus on actionable diagnosis`;
const diagnosisResult = Bash(`ccw cli -p '${diagnosisPrompt.replace(/'/g, "'\\''")}' --tool gemini --mode analysis --rule analysis-diagnose-bug-root-cause 2>&1 || echo "CLI diagnosis unavailable"`);
task.execution.skill_results.push({
skill: `cli-diagnosis:${skillName}`,
status: 'completed',
diagnosis: diagnosisResult?.substring(0, 500),
timestamp: new Date().toISOString()
});
// Retry with diagnosis context
console.log(` Retry with diagnosis: ${skillName}`);
try {
const retryResult = Skill({ skill: skillName, args: skillArgs });
previousResult = retryResult;
task.execution.skill_results.push({
skill: skillName,
status: 'completed-retry-with-diagnosis',
timestamp: new Date().toISOString()
});
} catch (retryError) {
task.execution.skill_results.push({
skill: skillName,
status: 'failed',
error: String(retryError).substring(0, 200),
timestamp: new Date().toISOString()
});
if (autoYes) {
taskFailed = true;
break;
}
const answer = AskUserQuestion({
questions: [{
question: `${skillName} failed after CLI diagnosis + retry: ${String(retryError).substring(0, 100)}`,
header: 'Error',
multiSelect: false,
options: [
{ label: 'Skip task', description: 'Mark as failed, continue' },
{ label: 'Abort', description: 'Stop run' }
]
}]
});
if (answer.answers?.Error === 'Abort') {
task.status = 'failed';
task.execution.error = String(retryError).substring(0, 200);
Write(`.workflow/.idaw/tasks/${task.id}.json`, JSON.stringify(task, null, 2));
session.failed.push(task.id);
session.status = 'failed';
session.updated_at = new Date().toISOString();
Write(`${sessionDir}/session.json`, JSON.stringify(session, null, 2));
return;
}
taskFailed = true;
break;
}
}
}
// Phase 5: Checkpoint
if (taskFailed) {
task.status = 'failed';
task.execution.error = 'Skill chain failed after retry';
task.execution.completed_at = new Date().toISOString();
session.failed.push(task.id);
} else {
// Git commit
const commitMsg = `feat(idaw): ${task.title} [${task.id}]`;
const diffCheck = Bash('git diff --stat HEAD 2>/dev/null || echo ""');
const untrackedCheck = Bash('git ls-files --others --exclude-standard 2>/dev/null || echo ""');
if (diffCheck?.trim() || untrackedCheck?.trim()) {
Bash('git add -A');
Bash(`git commit -m "$(cat <<'EOF'\n${commitMsg}\nEOF\n)"`);
const commitHash = Bash('git rev-parse --short HEAD 2>/dev/null')?.trim();
task.execution.git_commit = commitHash;
} else {
task.execution.git_commit = 'no-commit';
}
task.status = 'completed';
task.execution.completed_at = new Date().toISOString();
session.completed.push(task.id);
}
task.updated_at = new Date().toISOString();
Write(`.workflow/.idaw/tasks/${task.id}.json`, JSON.stringify(task, null, 2));
session.updated_at = new Date().toISOString();
Write(`${sessionDir}/session.json`, JSON.stringify(session, null, 2));
// Append progress
const chain_str = chain.join(' → ');
const progressEntry = `## ${task.id}${task.title}\n- Status: ${task.status}\n- Chain: ${chain_str}\n- Commit: ${task.execution.git_commit || '-'}\n\n`;
const currentProgress = Read(`${sessionDir}/progress.md`);
Write(`${sessionDir}/progress.md`, currentProgress + progressEntry);
}
// Phase 6: Report
session.status = session.failed.length > 0 && session.completed.length === 0 ? 'failed' : 'completed';
session.current_task = null;
session.updated_at = new Date().toISOString();
Write(`${sessionDir}/session.json`, JSON.stringify(session, null, 2));
const summary = `\n---\n## Summary (Resumed)\n- Completed: ${session.completed.length}\n- Failed: ${session.failed.length}\n- Skipped: ${session.skipped.length}\n`;
const finalProgress = Read(`${sessionDir}/progress.md`);
Write(`${sessionDir}/progress.md`, finalProgress + summary);
console.log('\n=== IDAW Resume Complete ===');
console.log(`Session: ${session.session_id}`);
console.log(`Completed: ${session.completed.length} | Failed: ${session.failed.length} | Skipped: ${session.skipped.length}`);
```
## Helper Functions
### assembleSkillArgs
```javascript
function assembleSkillArgs(skillName, task, previousResult, autoYes, isFirst) {
let args = '';
if (isFirst) {
// Sanitize for shell safety
const goal = `${task.title}\n${task.description}`
.replace(/\\/g, '\\\\')
.replace(/"/g, '\\"')
.replace(/\$/g, '\\$')
.replace(/`/g, '\\`');
args = `"${goal}"`;
if (task.task_type === 'bugfix-hotfix') args += ' --hotfix';
} else if (previousResult?.session_id) {
args = `--session="${previousResult.session_id}"`;
}
if (autoYes && !args.includes('-y') && !args.includes('--yes')) {
args = args ? `${args} -y` : '-y';
}
return args;
}
```
## Examples
```bash
# Resume most recent running session (interactive)
/idaw:resume
# Resume specific session
/idaw:resume IDA-auth-fix-20260301
# Resume with auto mode (skip interrupted, continue)
/idaw:resume -y
# Resume specific session with auto mode
/idaw:resume -y IDA-auth-fix-20260301
```

View File

@@ -1,648 +0,0 @@
---
name: run-coordinate
description: IDAW coordinator - execute task skill chains via external CLI with hook callbacks and git checkpoints
argument-hint: "[-y|--yes] [--task <id>[,<id>,...]] [--dry-run] [--tool <tool>]"
allowed-tools: Agent(*), AskUserQuestion(*), Read(*), Write(*), Bash(*), Glob(*), Grep(*)
---
# IDAW Run Coordinate Command (/idaw:run-coordinate)
Coordinator variant of `/idaw:run`: external CLI execution with background tasks and hook callbacks.
**Execution Model**: `ccw cli -p "..." --tool <tool> --mode write` in background → hook callback → next step.
**vs `/idaw:run`**: Direct `Skill()` calls (blocking, main process) vs `ccw cli` (background, external process).
## When to Use
| Scenario | Use |
|----------|-----|
| Standard IDAW execution (main process) | `/idaw:run` |
| External CLI execution (background, hook-driven) | `/idaw:run-coordinate` |
| Need `claude` or `gemini` as execution tool | `/idaw:run-coordinate --tool claude` |
| Long-running tasks, avoid context window pressure | `/idaw:run-coordinate` |
## Skill Chain Mapping
```javascript
const SKILL_CHAIN_MAP = {
'bugfix': ['workflow-lite-plan', 'workflow-test-fix'],
'bugfix-hotfix': ['workflow-lite-plan'],
'feature': ['workflow-lite-plan', 'workflow-test-fix'],
'feature-complex': ['workflow-plan', 'workflow-execute', 'workflow-test-fix'],
'refactor': ['workflow:refactor-cycle'],
'tdd': ['workflow-tdd-plan', 'workflow-execute'],
'test': ['workflow-test-fix'],
'test-fix': ['workflow-test-fix'],
'review': ['review-cycle'],
'docs': ['workflow-lite-plan']
};
```
## Task Type Inference
```javascript
function inferTaskType(title, description) {
const text = `${title} ${description}`.toLowerCase();
if (/urgent|production|critical/.test(text) && /fix|bug/.test(text)) return 'bugfix-hotfix';
if (/refactor|重构|tech.*debt/.test(text)) return 'refactor';
if (/tdd|test-driven|test first/.test(text)) return 'tdd';
if (/test fail|fix test|failing test/.test(text)) return 'test-fix';
if (/generate test|写测试|add test/.test(text)) return 'test';
if (/review|code review/.test(text)) return 'review';
if (/docs|documentation|readme/.test(text)) return 'docs';
if (/fix|bug|error|crash|fail/.test(text)) return 'bugfix';
if (/complex|multi-module|architecture/.test(text)) return 'feature-complex';
return 'feature';
}
```
## 6-Phase Execution (Coordinator Model)
### Phase 1: Load Tasks
```javascript
const args = $ARGUMENTS;
const autoYes = /(-y|--yes)/.test(args);
const dryRun = /--dry-run/.test(args);
const taskFilter = args.match(/--task\s+([\w,-]+)/)?.[1]?.split(',') || null;
const cliTool = args.match(/--tool\s+(\w+)/)?.[1] || 'claude';
// Load task files
const taskFiles = Glob('.workflow/.idaw/tasks/IDAW-*.json') || [];
if (taskFiles.length === 0) {
console.log('No IDAW tasks found. Use /idaw:add to create tasks.');
return;
}
// Parse and filter
let tasks = taskFiles.map(f => JSON.parse(Read(f)));
if (taskFilter) {
tasks = tasks.filter(t => taskFilter.includes(t.id));
} else {
tasks = tasks.filter(t => t.status === 'pending');
}
if (tasks.length === 0) {
console.log('No pending tasks to execute. Use /idaw:add to add tasks or --task to specify IDs.');
return;
}
// Sort: priority ASC (1=critical first), then ID ASC
tasks.sort((a, b) => {
if (a.priority !== b.priority) return a.priority - b.priority;
return a.id.localeCompare(b.id);
});
```
### Phase 2: Session Setup
```javascript
// Generate session ID: IDA-{slug}-YYYYMMDD
const slug = tasks[0].title
.toLowerCase()
.replace(/[^a-z0-9]+/g, '-')
.substring(0, 20)
.replace(/-$/, '');
const dateStr = new Date().toISOString().slice(0, 10).replace(/-/g, '');
let sessionId = `IDA-${slug}-${dateStr}`;
// Check collision
const existingSession = Glob(`.workflow/.idaw/sessions/${sessionId}/session.json`);
if (existingSession?.length > 0) {
sessionId = `${sessionId}-2`;
}
const sessionDir = `.workflow/.idaw/sessions/${sessionId}`;
Bash(`mkdir -p "${sessionDir}"`);
const session = {
session_id: sessionId,
mode: 'coordinate', // ★ Marks this as coordinator-mode session
cli_tool: cliTool,
status: 'running',
created_at: new Date().toISOString(),
updated_at: new Date().toISOString(),
tasks: tasks.map(t => t.id),
current_task: null,
current_skill_index: 0,
completed: [],
failed: [],
skipped: [],
prompts_used: []
};
Write(`${sessionDir}/session.json`, JSON.stringify(session, null, 2));
// Initialize progress.md
const progressHeader = `# IDAW Progress — ${sessionId} (coordinate mode)\nStarted: ${session.created_at}\nCLI Tool: ${cliTool}\n\n`;
Write(`${sessionDir}/progress.md`, progressHeader);
```
### Phase 3: Startup Protocol
```javascript
// Check for existing running sessions
const runningSessions = Glob('.workflow/.idaw/sessions/IDA-*/session.json')
?.map(f => { try { return JSON.parse(Read(f)); } catch { return null; } })
.filter(s => s && s.status === 'running' && s.session_id !== sessionId) || [];
if (runningSessions.length > 0 && !autoYes) {
const answer = AskUserQuestion({
questions: [{
question: `Found running session: ${runningSessions[0].session_id}. How to proceed?`,
header: 'Conflict',
multiSelect: false,
options: [
{ label: 'Resume existing', description: 'Use /idaw:resume instead' },
{ label: 'Start fresh', description: 'Continue with new session' },
{ label: 'Abort', description: 'Cancel this run' }
]
}]
});
if (answer.answers?.Conflict === 'Resume existing') {
console.log(`Use: /idaw:resume ${runningSessions[0].session_id}`);
return;
}
if (answer.answers?.Conflict === 'Abort') return;
}
// Check git status
const gitStatus = Bash('git status --porcelain 2>/dev/null');
if (gitStatus?.trim() && !autoYes) {
const answer = AskUserQuestion({
questions: [{
question: 'Working tree has uncommitted changes. How to proceed?',
header: 'Git',
multiSelect: false,
options: [
{ label: 'Continue', description: 'Proceed with dirty tree' },
{ label: 'Stash', description: 'git stash before running' },
{ label: 'Abort', description: 'Stop and handle manually' }
]
}]
});
if (answer.answers?.Git === 'Stash') Bash('git stash push -m "idaw-pre-run"');
if (answer.answers?.Git === 'Abort') return;
}
// Dry run
if (dryRun) {
console.log(`# Dry Run — ${sessionId} (coordinate mode, tool: ${cliTool})\n`);
for (const task of tasks) {
const taskType = task.task_type || inferTaskType(task.title, task.description);
const chain = task.skill_chain || SKILL_CHAIN_MAP[taskType] || SKILL_CHAIN_MAP['feature'];
console.log(`## ${task.id}: ${task.title}`);
console.log(` Type: ${taskType} | Priority: ${task.priority}`);
console.log(` Chain: ${chain.join(' → ')}`);
console.log(` CLI: ccw cli --tool ${cliTool} --mode write\n`);
}
console.log(`Total: ${tasks.length} tasks`);
return;
}
```
### Phase 4: Launch First Task (then wait for hook)
```javascript
// Start with the first task, first skill
const firstTask = tasks[0];
const resolvedType = firstTask.task_type || inferTaskType(firstTask.title, firstTask.description);
const chain = firstTask.skill_chain || SKILL_CHAIN_MAP[resolvedType] || SKILL_CHAIN_MAP['feature'];
// Update task → in_progress
firstTask.status = 'in_progress';
firstTask.task_type = resolvedType;
firstTask.execution.started_at = new Date().toISOString();
Write(`.workflow/.idaw/tasks/${firstTask.id}.json`, JSON.stringify(firstAgent, null, 2));
// Update session
session.current_task = firstTask.id;
session.current_skill_index = 0;
session.updated_at = new Date().toISOString();
Write(`${sessionDir}/session.json`, JSON.stringify(session, null, 2));
// ━━━ Pre-Task CLI Context Analysis (for complex/bugfix tasks) ━━━
if (['bugfix', 'bugfix-hotfix', 'feature-complex'].includes(resolvedType)) {
console.log(`Pre-analysis: gathering context for ${resolvedType} task...`);
const affectedFiles = (firstTask.context?.affected_files || []).join(', ');
const preAnalysisPrompt = `PURPOSE: Pre-analyze codebase context for IDAW task.
TASK: • Understand current state of: ${affectedFiles || 'files related to: ' + firstTask.title} • Identify dependencies and risk areas
MODE: analysis
CONTEXT: @**/*
EXPECTED: Brief context summary in 3-5 bullet points
CONSTRAINTS: Keep concise`;
Bash(`ccw cli -p '${preAnalysisPrompt.replace(/'/g, "'\\''")}' --tool gemini --mode analysis 2>&1 || echo "Pre-analysis skipped"`);
}
// Assemble prompt for first skill
const skillName = chain[0];
const prompt = assembleCliPrompt(skillName, firstAgent, null, autoYes);
session.prompts_used.push({
task_id: firstTask.id,
skill_index: 0,
skill: skillName,
prompt: prompt,
timestamp: new Date().toISOString()
});
session.updated_at = new Date().toISOString();
Write(`${sessionDir}/session.json`, JSON.stringify(session, null, 2));
// Launch via ccw cli in background
console.log(`[1/${tasks.length}] ${firstTask.id}: ${firstTask.title}`);
console.log(` Chain: ${chain.join(' → ')}`);
console.log(` Launching: ${skillName} via ccw cli --tool ${cliTool}`);
Bash(
`ccw cli -p "${escapeForShell(prompt)}" --tool ${cliTool} --mode write`,
{ run_in_background: true }
);
// ★ STOP HERE — wait for hook callback
// Hook callback will trigger handleStepCompletion() below
```
### Phase 5: Hook Callback Handler (per-step completion)
```javascript
// Called by hook when background CLI completes
async function handleStepCompletion(sessionId, cliOutput) {
const sessionDir = `.workflow/.idaw/sessions/${sessionId}`;
const session = JSON.parse(Read(`${sessionDir}/session.json`));
const taskId = session.current_task;
const task = JSON.parse(Read(`.workflow/.idaw/tasks/${taskId}.json`));
const resolvedType = task.task_type || inferTaskType(task.title, task.description);
const chain = task.skill_chain || SKILL_CHAIN_MAP[resolvedType] || SKILL_CHAIN_MAP['feature'];
const skillIdx = session.current_skill_index;
const skillName = chain[skillIdx];
// Parse CLI output for session ID
const parsedOutput = parseCliOutput(cliOutput);
// Record skill result
task.execution.skill_results.push({
skill: skillName,
status: parsedOutput.success ? 'completed' : 'failed',
session_id: parsedOutput.sessionId,
timestamp: new Date().toISOString()
});
// ━━━ Handle failure with CLI diagnosis ━━━
if (!parsedOutput.success) {
console.log(` ${skillName} failed. Running CLI diagnosis...`);
const diagnosisPrompt = `PURPOSE: Diagnose why skill "${skillName}" failed during IDAW task.
TASK: • Analyze error output • Check affected files: ${(task.context?.affected_files || []).join(', ') || 'unknown'}
MODE: analysis
CONTEXT: @**/* | Memory: IDAW task ${task.id}: ${task.title}
EXPECTED: Root cause + fix recommendation
CONSTRAINTS: Actionable diagnosis`;
Bash(`ccw cli -p '${diagnosisPrompt.replace(/'/g, "'\\''")}' --tool gemini --mode analysis --rule analysis-diagnose-bug-root-cause 2>&1 || true`);
task.execution.skill_results.push({
skill: `cli-diagnosis:${skillName}`,
status: 'completed',
timestamp: new Date().toISOString()
});
// Retry once
console.log(` Retrying: ${skillName}`);
const retryPrompt = assembleCliPrompt(skillName, task, parsedOutput, true);
session.prompts_used.push({
task_id: taskId,
skill_index: skillIdx,
skill: `${skillName}-retry`,
prompt: retryPrompt,
timestamp: new Date().toISOString()
});
Write(`${sessionDir}/session.json`, JSON.stringify(session, null, 2));
Write(`.workflow/.idaw/tasks/${taskId}.json`, JSON.stringify(task, null, 2));
Bash(
`ccw cli -p "${escapeForShell(retryPrompt)}" --tool ${session.cli_tool} --mode write`,
{ run_in_background: true }
);
return; // Wait for retry hook
}
// ━━━ Skill succeeded — advance ━━━
const nextSkillIdx = skillIdx + 1;
if (nextSkillIdx < chain.length) {
// More skills in this task's chain → launch next skill
session.current_skill_index = nextSkillIdx;
session.updated_at = new Date().toISOString();
const nextSkill = chain[nextSkillIdx];
const nextPrompt = assembleCliPrompt(nextSkill, task, parsedOutput, true);
session.prompts_used.push({
task_id: taskId,
skill_index: nextSkillIdx,
skill: nextSkill,
prompt: nextPrompt,
timestamp: new Date().toISOString()
});
Write(`${sessionDir}/session.json`, JSON.stringify(session, null, 2));
Write(`.workflow/.idaw/tasks/${taskId}.json`, JSON.stringify(task, null, 2));
console.log(` Next skill: ${nextSkill}`);
Bash(
`ccw cli -p "${escapeForShell(nextPrompt)}" --tool ${session.cli_tool} --mode write`,
{ run_in_background: true }
);
return; // Wait for next hook
}
// ━━━ Task chain complete — git checkpoint ━━━
const commitMsg = `feat(idaw): ${task.title} [${task.id}]`;
const diffCheck = Bash('git diff --stat HEAD 2>/dev/null || echo ""');
const untrackedCheck = Bash('git ls-files --others --exclude-standard 2>/dev/null || echo ""');
if (diffCheck?.trim() || untrackedCheck?.trim()) {
Bash('git add -A');
Bash(`git commit -m "$(cat <<'EOF'\n${commitMsg}\nEOF\n)"`);
const commitHash = Bash('git rev-parse --short HEAD 2>/dev/null')?.trim();
task.execution.git_commit = commitHash;
} else {
task.execution.git_commit = 'no-commit';
}
task.status = 'completed';
task.execution.completed_at = new Date().toISOString();
task.updated_at = new Date().toISOString();
Write(`.workflow/.idaw/tasks/${taskId}.json`, JSON.stringify(task, null, 2));
session.completed.push(taskId);
// Append progress
const progressEntry = `## ${task.id}${task.title}\n` +
`- Status: completed\n` +
`- Type: ${task.task_type}\n` +
`- Chain: ${chain.join(' → ')}\n` +
`- Commit: ${task.execution.git_commit || '-'}\n` +
`- Mode: coordinate (${session.cli_tool})\n\n`;
const currentProgress = Read(`${sessionDir}/progress.md`);
Write(`${sessionDir}/progress.md`, currentProgress + progressEntry);
// ━━━ Advance to next task ━━━
const allTaskIds = session.tasks;
const completedSet = new Set([...session.completed, ...session.failed, ...session.skipped]);
const nextTaskId = allTaskIds.find(id => !completedSet.has(id));
if (nextTaskId) {
// Load next task
const nextTask = JSON.parse(Read(`.workflow/.idaw/tasks/${nextTaskId}.json`));
const nextType = nextTask.task_type || inferTaskType(nextTask.title, nextTask.description);
const nextChain = nextTask.skill_chain || SKILL_CHAIN_MAP[nextType] || SKILL_CHAIN_MAP['feature'];
nextTask.status = 'in_progress';
nextTask.task_type = nextType;
nextTask.execution.started_at = new Date().toISOString();
Write(`.workflow/.idaw/tasks/${nextTaskId}.json`, JSON.stringify(nextAgent, null, 2));
session.current_task = nextTaskId;
session.current_skill_index = 0;
session.updated_at = new Date().toISOString();
Write(`${sessionDir}/session.json`, JSON.stringify(session, null, 2));
// Pre-analysis for complex tasks
if (['bugfix', 'bugfix-hotfix', 'feature-complex'].includes(nextType)) {
const affectedFiles = (nextTask.context?.affected_files || []).join(', ');
Bash(`ccw cli -p 'PURPOSE: Pre-analyze context for ${nextTask.title}. TASK: Check ${affectedFiles || "related files"}. MODE: analysis. EXPECTED: 3-5 bullet points.' --tool gemini --mode analysis 2>&1 || true`);
}
const nextSkillName = nextChain[0];
const nextPrompt = assembleCliPrompt(nextSkillName, nextAgent, null, true);
session.prompts_used.push({
task_id: nextTaskId,
skill_index: 0,
skill: nextSkillName,
prompt: nextPrompt,
timestamp: new Date().toISOString()
});
Write(`${sessionDir}/session.json`, JSON.stringify(session, null, 2));
const taskNum = session.completed.length + 1;
const totalTasks = session.tasks.length;
console.log(`\n[${taskNum}/${totalTasks}] ${nextTaskId}: ${nextTask.title}`);
console.log(` Chain: ${nextChain.join(' → ')}`);
Bash(
`ccw cli -p "${escapeForShell(nextPrompt)}" --tool ${session.cli_tool} --mode write`,
{ run_in_background: true }
);
return; // Wait for hook
}
// ━━━ All tasks complete — Phase 6: Report ━━━
session.status = session.failed.length > 0 && session.completed.length === 0 ? 'failed' : 'completed';
session.current_task = null;
session.updated_at = new Date().toISOString();
Write(`${sessionDir}/session.json`, JSON.stringify(session, null, 2));
const summary = `\n---\n## Summary (coordinate mode)\n` +
`- CLI Tool: ${session.cli_tool}\n` +
`- Completed: ${session.completed.length}\n` +
`- Failed: ${session.failed.length}\n` +
`- Skipped: ${session.skipped.length}\n` +
`- Total: ${session.tasks.length}\n`;
const finalProgress = Read(`${sessionDir}/progress.md`);
Write(`${sessionDir}/progress.md`, finalProgress + summary);
console.log('\n=== IDAW Coordinate Complete ===');
console.log(`Session: ${sessionId}`);
console.log(`Completed: ${session.completed.length}/${session.tasks.length}`);
if (session.failed.length > 0) console.log(`Failed: ${session.failed.join(', ')}`);
}
```
## Helper Functions
### assembleCliPrompt
```javascript
function assembleCliPrompt(skillName, task, previousResult, autoYes) {
let prompt = '';
const yFlag = autoYes ? ' -y' : '';
// Map skill to command invocation
if (skillName === 'workflow-lite-plan') {
const goal = sanitize(`${task.title}\n${task.description}`);
prompt = `/workflow-lite-plan${yFlag} "${goal}"`;
if (task.task_type === 'bugfix') prompt = `/workflow-lite-plan${yFlag} --bugfix "${goal}"`;
if (task.task_type === 'bugfix-hotfix') prompt = `/workflow-lite-plan${yFlag} --hotfix "${goal}"`;
} else if (skillName === 'workflow-plan') {
prompt = `/workflow-plan${yFlag} "${sanitize(task.title)}"`;
} else if (skillName === 'workflow-execute') {
if (previousResult?.sessionId) {
prompt = `/workflow-execute${yFlag} --resume-session="${previousResult.sessionId}"`;
} else {
prompt = `/workflow-execute${yFlag}`;
}
} else if (skillName === 'workflow-test-fix') {
if (previousResult?.sessionId) {
prompt = `/workflow-test-fix${yFlag} "${previousResult.sessionId}"`;
} else {
prompt = `/workflow-test-fix${yFlag} "${sanitize(task.title)}"`;
}
} else if (skillName === 'workflow-tdd-plan') {
prompt = `/workflow-tdd-plan${yFlag} "${sanitize(task.title)}"`;
} else if (skillName === 'workflow:refactor-cycle') {
prompt = `/workflow:refactor-cycle${yFlag} "${sanitize(task.title)}"`;
} else if (skillName === 'review-cycle') {
if (previousResult?.sessionId) {
prompt = `/review-cycle${yFlag} --session="${previousResult.sessionId}"`;
} else {
prompt = `/review-cycle${yFlag}`;
}
} else {
// Generic fallback
prompt = `/${skillName}${yFlag} "${sanitize(task.title)}"`;
}
// Append task context
prompt += `\n\nTask: ${task.title}\nDescription: ${task.description}`;
if (task.context?.affected_files?.length > 0) {
prompt += `\nAffected files: ${task.context.affected_files.join(', ')}`;
}
if (task.context?.acceptance_criteria?.length > 0) {
prompt += `\nAcceptance criteria: ${task.context.acceptance_criteria.join('; ')}`;
}
return prompt;
}
```
### sanitize & escapeForShell
```javascript
function sanitize(text) {
return text
.replace(/\\/g, '\\\\')
.replace(/"/g, '\\"')
.replace(/\$/g, '\\$')
.replace(/`/g, '\\`');
}
function escapeForShell(prompt) {
return prompt.replace(/'/g, "'\\''");
}
```
### parseCliOutput
```javascript
function parseCliOutput(output) {
// Extract session ID from CLI output (e.g., WFS-xxx, session-xxx)
const sessionMatch = output.match(/(?:session|WFS|Session ID)[:\s]*([\w-]+)/i);
const success = !/(?:error|failed|fatal)/i.test(output) || /completed|success/i.test(output);
return {
success,
sessionId: sessionMatch?.[1] || null,
raw: output?.substring(0, 500)
};
}
```
## CLI-Assisted Analysis
Same as `/idaw:run` — integrated at two points:
### Pre-Task Context Analysis
For `bugfix`, `bugfix-hotfix`, `feature-complex` tasks: auto-invoke `ccw cli --tool gemini --mode analysis` before launching skill chain.
### Error Recovery with CLI Diagnosis
When a skill's CLI execution fails: invoke diagnosis → retry once → if still fails, mark failed and advance.
```
Skill CLI fails → CLI diagnosis (gemini) → Retry CLI → Still fails → mark failed → next task
```
## State Flow
```
Phase 4: Launch first skill
ccw cli --tool claude --mode write (background)
★ STOP — wait for hook callback
Phase 5: handleStepCompletion()
├─ Skill succeeded + more in chain → launch next skill → STOP
├─ Skill succeeded + chain complete → git checkpoint → next task → STOP
├─ Skill failed → CLI diagnosis → retry → STOP
└─ All tasks done → Phase 6: Report
```
## Session State (session.json)
```json
{
"session_id": "IDA-fix-login-20260301",
"mode": "coordinate",
"cli_tool": "claude",
"status": "running|waiting|completed|failed",
"created_at": "ISO",
"updated_at": "ISO",
"tasks": ["IDAW-001", "IDAW-002"],
"current_task": "IDAW-001",
"current_skill_index": 0,
"completed": [],
"failed": [],
"skipped": [],
"prompts_used": [
{
"task_id": "IDAW-001",
"skill_index": 0,
"skill": "workflow-lite-plan",
"prompt": "/workflow-lite-plan -y \"Fix login timeout\"",
"timestamp": "ISO"
}
]
}
```
## Differences from /idaw:run
| Aspect | /idaw:run | /idaw:run-coordinate |
|--------|-----------|---------------------|
| Execution | `Skill()` blocking in main process | `ccw cli` background + hook callback |
| Context window | Shared (each skill uses main context) | Isolated (each CLI gets fresh context) |
| Concurrency | Sequential blocking | Sequential non-blocking (hook-driven) |
| State tracking | session.json + task.json | session.json + task.json + prompts_used |
| Tool selection | N/A (Skill native) | `--tool claude\|gemini\|qwen` |
| Resume | Via `/idaw:resume` (same) | Via `/idaw:resume` (same, detects mode) |
| Best for | Short chains, interactive | Long chains, autonomous, context-heavy |
## Examples
```bash
# Execute all pending tasks via claude CLI
/idaw:run-coordinate -y
# Use specific CLI tool
/idaw:run-coordinate -y --tool gemini
# Execute specific tasks
/idaw:run-coordinate --task IDAW-001,IDAW-003 --tool claude
# Dry run (show plan without executing)
/idaw:run-coordinate --dry-run
# Interactive mode
/idaw:run-coordinate
```

View File

@@ -1,539 +0,0 @@
---
name: run
description: IDAW orchestrator - execute task skill chains serially with git checkpoints
argument-hint: "[-y|--yes] [--task <id>[,<id>,...]] [--dry-run]"
allowed-tools: Skill(*), TodoWrite(*), AskUserQuestion(*), Read(*), Write(*), Bash(*), Glob(*)
---
# IDAW Run Command (/idaw:run)
## Auto Mode
When `--yes` or `-y`: Skip all confirmations, auto-skip on failure, proceed with dirty git.
## Skill Chain Mapping
```javascript
const SKILL_CHAIN_MAP = {
'bugfix': ['workflow-lite-plan', 'workflow-test-fix'],
'bugfix-hotfix': ['workflow-lite-plan'],
'feature': ['workflow-lite-plan', 'workflow-test-fix'],
'feature-complex': ['workflow-plan', 'workflow-execute', 'workflow-test-fix'],
'refactor': ['workflow:refactor-cycle'],
'tdd': ['workflow-tdd-plan', 'workflow-execute'],
'test': ['workflow-test-fix'],
'test-fix': ['workflow-test-fix'],
'review': ['review-cycle'],
'docs': ['workflow-lite-plan']
};
```
## Task Type Inference
```javascript
function inferTaskType(title, description) {
const text = `${title} ${description}`.toLowerCase();
if (/urgent|production|critical/.test(text) && /fix|bug/.test(text)) return 'bugfix-hotfix';
if (/refactor|重构|tech.*debt/.test(text)) return 'refactor';
if (/tdd|test-driven|test first/.test(text)) return 'tdd';
if (/test fail|fix test|failing test/.test(text)) return 'test-fix';
if (/generate test|写测试|add test/.test(text)) return 'test';
if (/review|code review/.test(text)) return 'review';
if (/docs|documentation|readme/.test(text)) return 'docs';
if (/fix|bug|error|crash|fail/.test(text)) return 'bugfix';
if (/complex|multi-module|architecture/.test(text)) return 'feature-complex';
return 'feature';
}
```
## 6-Phase Execution
### Phase 1: Load Tasks
```javascript
const args = $ARGUMENTS;
const autoYes = /(-y|--yes)/.test(args);
const dryRun = /--dry-run/.test(args);
const taskFilter = args.match(/--task\s+([\w,-]+)/)?.[1]?.split(',') || null;
// Load task files
const taskFiles = Glob('.workflow/.idaw/tasks/IDAW-*.json') || [];
if (taskFiles.length === 0) {
console.log('No IDAW tasks found. Use /idaw:add to create tasks.');
return;
}
// Parse and filter
let tasks = taskFiles.map(f => JSON.parse(Read(f)));
if (taskFilter) {
tasks = tasks.filter(t => taskFilter.includes(t.id));
} else {
tasks = tasks.filter(t => t.status === 'pending');
}
if (tasks.length === 0) {
console.log('No pending tasks to execute. Use /idaw:add to add tasks or --task to specify IDs.');
return;
}
// Sort: priority ASC (1=critical first), then ID ASC
tasks.sort((a, b) => {
if (a.priority !== b.priority) return a.priority - b.priority;
return a.id.localeCompare(b.id);
});
```
### Phase 2: Session Setup
```javascript
// Generate session ID: IDA-{slug}-YYYYMMDD
const slug = tasks[0].title
.toLowerCase()
.replace(/[^a-z0-9]+/g, '-')
.substring(0, 20)
.replace(/-$/, '');
const dateStr = new Date().toISOString().slice(0, 10).replace(/-/g, '');
let sessionId = `IDA-${slug}-${dateStr}`;
// Check collision
const existingSession = Glob(`.workflow/.idaw/sessions/${sessionId}/session.json`);
if (existingSession?.length > 0) {
sessionId = `${sessionId}-2`;
}
const sessionDir = `.workflow/.idaw/sessions/${sessionId}`;
Bash(`mkdir -p "${sessionDir}"`);
const session = {
session_id: sessionId,
status: 'running',
created_at: new Date().toISOString(),
updated_at: new Date().toISOString(),
tasks: tasks.map(t => t.id),
current_task: null,
completed: [],
failed: [],
skipped: []
};
Write(`${sessionDir}/session.json`, JSON.stringify(session, null, 2));
// Initialize progress.md
const progressHeader = `# IDAW Progress — ${sessionId}\nStarted: ${session.created_at}\n\n`;
Write(`${sessionDir}/progress.md`, progressHeader);
// TodoWrite
TodoWrite({
todos: tasks.map((t, i) => ({
content: `IDAW:[${i + 1}/${tasks.length}] ${t.title}`,
status: i === 0 ? 'in_progress' : 'pending',
activeForm: `Executing ${t.title}`
}))
});
```
### Phase 3: Startup Protocol
```javascript
// Check for existing running sessions
const runningSessions = Glob('.workflow/.idaw/sessions/IDA-*/session.json')
?.map(f => JSON.parse(Read(f)))
.filter(s => s.status === 'running' && s.session_id !== sessionId) || [];
if (runningSessions.length > 0) {
if (!autoYes) {
const answer = AskUserQuestion({
questions: [{
question: `Found running session: ${runningSessions[0].session_id}. How to proceed?`,
header: 'Conflict',
multiSelect: false,
options: [
{ label: 'Resume existing', description: 'Use /idaw:resume instead' },
{ label: 'Start fresh', description: 'Continue with new session' },
{ label: 'Abort', description: 'Cancel this run' }
]
}]
});
if (answer.answers?.Conflict === 'Resume existing') {
console.log(`Use: /idaw:resume ${runningSessions[0].session_id}`);
return;
}
if (answer.answers?.Conflict === 'Abort') return;
}
// autoYes or "Start fresh": proceed
}
// Check git status
const gitStatus = Bash('git status --porcelain 2>/dev/null');
if (gitStatus?.trim()) {
if (!autoYes) {
const answer = AskUserQuestion({
questions: [{
question: 'Working tree has uncommitted changes. How to proceed?',
header: 'Git',
multiSelect: false,
options: [
{ label: 'Continue', description: 'Proceed with dirty tree' },
{ label: 'Stash', description: 'git stash before running' },
{ label: 'Abort', description: 'Stop and handle manually' }
]
}]
});
if (answer.answers?.Git === 'Stash') {
Bash('git stash push -m "idaw-pre-run"');
}
if (answer.answers?.Git === 'Abort') return;
}
// autoYes: proceed silently
}
// Dry run: show plan and exit
if (dryRun) {
console.log(`# Dry Run — ${sessionId}\n`);
for (const task of tasks) {
const taskType = task.task_type || inferTaskType(task.title, task.description);
const chain = task.skill_chain || SKILL_CHAIN_MAP[taskType] || SKILL_CHAIN_MAP['feature'];
console.log(`## ${task.id}: ${task.title}`);
console.log(` Type: ${taskType} | Priority: ${task.priority}`);
console.log(` Chain: ${chain.join(' → ')}\n`);
}
console.log(`Total: ${tasks.length} tasks`);
return;
}
```
### Phase 4: Main Loop (serial, one task at a time)
```javascript
for (let taskIdx = 0; taskIdx < tasks.length; taskIdx++) {
const task = tasks[taskIdx];
// Skip completed/failed/skipped
if (['completed', 'failed', 'skipped'].includes(task.status)) continue;
// Resolve skill chain
const resolvedType = task.task_type || inferTaskType(task.title, task.description);
const chain = task.skill_chain || SKILL_CHAIN_MAP[resolvedType] || SKILL_CHAIN_MAP['feature'];
// Update task status → in_progress
task.status = 'in_progress';
task.task_type = resolvedType; // persist inferred type
task.execution.started_at = new Date().toISOString();
Write(`.workflow/.idaw/tasks/${task.id}.json`, JSON.stringify(task, null, 2));
// Update session
session.current_task = task.id;
session.updated_at = new Date().toISOString();
Write(`${sessionDir}/session.json`, JSON.stringify(session, null, 2));
console.log(`\n--- [${taskIdx + 1}/${tasks.length}] ${task.id}: ${task.title} ---`);
console.log(`Chain: ${chain.join(' → ')}`);
// ━━━ Pre-Task CLI Context Analysis (for complex/bugfix tasks) ━━━
if (['bugfix', 'bugfix-hotfix', 'feature-complex'].includes(resolvedType)) {
console.log(` Pre-analysis: gathering context for ${resolvedType} task...`);
const affectedFiles = (task.context?.affected_files || []).join(', ');
const preAnalysisPrompt = `PURPOSE: Pre-analyze codebase context for IDAW task before execution.
TASK: • Understand current state of: ${affectedFiles || 'files related to: ' + task.title} • Identify dependencies and risk areas • Note existing patterns to follow
MODE: analysis
CONTEXT: @**/*
EXPECTED: Brief context summary (affected modules, dependencies, risk areas) in 3-5 bullet points
CONSTRAINTS: Keep concise | Focus on execution-relevant context`;
const preAnalysis = Bash(`ccw cli -p '${preAnalysisPrompt.replace(/'/g, "'\\''")}' --tool gemini --mode analysis 2>&1 || echo "Pre-analysis skipped"`);
task.execution.skill_results.push({
skill: 'cli-pre-analysis',
status: 'completed',
context_summary: preAnalysis?.substring(0, 500),
timestamp: new Date().toISOString()
});
}
// Execute each skill in chain
let previousResult = null;
let taskFailed = false;
for (let skillIdx = 0; skillIdx < chain.length; skillIdx++) {
const skillName = chain[skillIdx];
const skillArgs = assembleSkillArgs(skillName, task, previousResult, autoYes, skillIdx === 0);
console.log(` [${skillIdx + 1}/${chain.length}] ${skillName}`);
try {
const result = Skill({ skill: skillName, args: skillArgs });
previousResult = result;
task.execution.skill_results.push({
skill: skillName,
status: 'completed',
timestamp: new Date().toISOString()
});
} catch (error) {
// ━━━ CLI-Assisted Error Recovery ━━━
// Step 1: Invoke CLI diagnosis (auto-invoke trigger: self-repair fails)
console.log(` Diagnosing failure: ${skillName}...`);
const diagnosisPrompt = `PURPOSE: Diagnose why skill "${skillName}" failed during IDAW task execution.
TASK: • Analyze error: ${String(error).substring(0, 300)} • Check affected files: ${(task.context?.affected_files || []).join(', ') || 'unknown'} • Identify root cause • Suggest fix strategy
MODE: analysis
CONTEXT: @**/* | Memory: IDAW task ${task.id}: ${task.title}
EXPECTED: Root cause + actionable fix recommendation (1-2 sentences)
CONSTRAINTS: Focus on actionable diagnosis`;
const diagnosisResult = Bash(`ccw cli -p '${diagnosisPrompt.replace(/'/g, "'\\''")}' --tool gemini --mode analysis --rule analysis-diagnose-bug-root-cause 2>&1 || echo "CLI diagnosis unavailable"`);
task.execution.skill_results.push({
skill: `cli-diagnosis:${skillName}`,
status: 'completed',
diagnosis: diagnosisResult?.substring(0, 500),
timestamp: new Date().toISOString()
});
// Step 2: Retry with diagnosis context
console.log(` Retry with diagnosis: ${skillName}`);
try {
const retryResult = Skill({ skill: skillName, args: skillArgs });
previousResult = retryResult;
task.execution.skill_results.push({
skill: skillName,
status: 'completed-retry-with-diagnosis',
timestamp: new Date().toISOString()
});
} catch (retryError) {
// Step 3: Failed after CLI-assisted retry
task.execution.skill_results.push({
skill: skillName,
status: 'failed',
error: String(retryError).substring(0, 200),
timestamp: new Date().toISOString()
});
if (autoYes) {
taskFailed = true;
break;
} else {
const answer = AskUserQuestion({
questions: [{
question: `${skillName} failed after CLI diagnosis + retry: ${String(retryError).substring(0, 100)}. How to proceed?`,
header: 'Error',
multiSelect: false,
options: [
{ label: 'Skip task', description: 'Mark task as failed, continue to next' },
{ label: 'Abort', description: 'Stop entire run' }
]
}]
});
if (answer.answers?.Error === 'Abort') {
task.status = 'failed';
task.execution.error = String(retryError).substring(0, 200);
Write(`.workflow/.idaw/tasks/${task.id}.json`, JSON.stringify(task, null, 2));
session.failed.push(task.id);
session.status = 'failed';
session.updated_at = new Date().toISOString();
Write(`${sessionDir}/session.json`, JSON.stringify(session, null, 2));
return;
}
taskFailed = true;
break;
}
}
}
}
// Phase 5: Checkpoint (per task) — inline
if (taskFailed) {
task.status = 'failed';
task.execution.error = 'Skill chain failed after retry';
task.execution.completed_at = new Date().toISOString();
session.failed.push(task.id);
} else {
// Git commit checkpoint
const commitMsg = `feat(idaw): ${task.title} [${task.id}]`;
const diffCheck = Bash('git diff --stat HEAD 2>/dev/null || echo ""');
const untrackedCheck = Bash('git ls-files --others --exclude-standard 2>/dev/null || echo ""');
if (diffCheck?.trim() || untrackedCheck?.trim()) {
Bash('git add -A');
const commitResult = Bash(`git commit -m "$(cat <<'EOF'\n${commitMsg}\nEOF\n)"`);
const commitHash = Bash('git rev-parse --short HEAD 2>/dev/null')?.trim();
task.execution.git_commit = commitHash;
} else {
task.execution.git_commit = 'no-commit';
}
task.status = 'completed';
task.execution.completed_at = new Date().toISOString();
session.completed.push(task.id);
}
// Write task + session state
task.updated_at = new Date().toISOString();
Write(`.workflow/.idaw/tasks/${task.id}.json`, JSON.stringify(task, null, 2));
session.updated_at = new Date().toISOString();
Write(`${sessionDir}/session.json`, JSON.stringify(session, null, 2));
// Append to progress.md
const duration = task.execution.started_at && task.execution.completed_at
? formatDuration(new Date(task.execution.completed_at) - new Date(task.execution.started_at))
: 'unknown';
const progressEntry = `## ${task.id}${task.title}\n` +
`- Status: ${task.status}\n` +
`- Type: ${task.task_type}\n` +
`- Chain: ${chain.join(' → ')}\n` +
`- Commit: ${task.execution.git_commit || '-'}\n` +
`- Duration: ${duration}\n\n`;
const currentProgress = Read(`${sessionDir}/progress.md`);
Write(`${sessionDir}/progress.md`, currentProgress + progressEntry);
// Update TodoWrite
if (taskIdx + 1 < tasks.length) {
TodoWrite({
todos: tasks.map((t, i) => ({
content: `IDAW:[${i + 1}/${tasks.length}] ${t.title}`,
status: i < taskIdx + 1 ? 'completed' : (i === taskIdx + 1 ? 'in_progress' : 'pending'),
activeForm: `Executing ${t.title}`
}))
});
}
}
```
### Phase 6: Report
```javascript
session.status = session.failed.length > 0 && session.completed.length === 0 ? 'failed' : 'completed';
session.current_task = null;
session.updated_at = new Date().toISOString();
Write(`${sessionDir}/session.json`, JSON.stringify(session, null, 2));
// Final progress summary
const summary = `\n---\n## Summary\n` +
`- Completed: ${session.completed.length}\n` +
`- Failed: ${session.failed.length}\n` +
`- Skipped: ${session.skipped.length}\n` +
`- Total: ${tasks.length}\n`;
const finalProgress = Read(`${sessionDir}/progress.md`);
Write(`${sessionDir}/progress.md`, finalProgress + summary);
// Display report
console.log('\n=== IDAW Run Complete ===');
console.log(`Session: ${sessionId}`);
console.log(`Completed: ${session.completed.length}/${tasks.length}`);
if (session.failed.length > 0) console.log(`Failed: ${session.failed.join(', ')}`);
if (session.skipped.length > 0) console.log(`Skipped: ${session.skipped.join(', ')}`);
// List git commits
for (const taskId of session.completed) {
const t = JSON.parse(Read(`.workflow/.idaw/tasks/${taskId}.json`));
if (t.execution.git_commit && t.execution.git_commit !== 'no-commit') {
console.log(` ${t.execution.git_commit} ${t.title}`);
}
}
```
## Helper Functions
### assembleSkillArgs
```javascript
function assembleSkillArgs(skillName, task, previousResult, autoYes, isFirst) {
let args = '';
if (isFirst) {
// First skill: pass task goal — sanitize for shell safety
const goal = `${task.title}\n${task.description}`
.replace(/\\/g, '\\\\')
.replace(/"/g, '\\"')
.replace(/\$/g, '\\$')
.replace(/`/g, '\\`');
args = `"${goal}"`;
// bugfix-hotfix: add --hotfix
if (task.task_type === 'bugfix-hotfix') {
args += ' --hotfix';
}
} else if (previousResult?.session_id) {
// Subsequent skills: chain session
args = `--session="${previousResult.session_id}"`;
}
// Propagate -y
if (autoYes && !args.includes('-y') && !args.includes('--yes')) {
args = args ? `${args} -y` : '-y';
}
return args;
}
```
### formatDuration
```javascript
function formatDuration(ms) {
const seconds = Math.floor(ms / 1000);
const minutes = Math.floor(seconds / 60);
const remainingSeconds = seconds % 60;
if (minutes > 0) return `${minutes}m ${remainingSeconds}s`;
return `${seconds}s`;
}
```
## CLI-Assisted Analysis
IDAW integrates `ccw cli` (Gemini) for intelligent analysis at two key points:
### Pre-Task Context Analysis
For `bugfix`, `bugfix-hotfix`, and `feature-complex` tasks, IDAW automatically invokes CLI analysis **before** executing the skill chain to gather codebase context:
```
Task starts → CLI pre-analysis (gemini) → Context gathered → Skill chain executes
```
- Identifies dependencies and risk areas
- Notes existing patterns to follow
- Results stored in `task.execution.skill_results` as `cli-pre-analysis`
### Error Recovery with CLI Diagnosis
When a skill fails, instead of blind retry, IDAW uses CLI-assisted diagnosis:
```
Skill fails → CLI diagnosis (gemini, analysis-diagnose-bug-root-cause)
→ Root cause identified → Retry with diagnosis context
→ Still fails → Skip (autoYes) or Ask user (interactive)
```
- Uses `--rule analysis-diagnose-bug-root-cause` template
- Diagnosis results stored in `task.execution.skill_results` as `cli-diagnosis:{skill}`
- Follows CLAUDE.md auto-invoke trigger pattern: "self-repair fails → invoke CLI analysis"
### Execution Flow (with CLI analysis)
```
Phase 4 Main Loop (per task):
├─ [bugfix/complex only] CLI pre-analysis → context summary
├─ Skill 1: execute
│ ├─ Success → next skill
│ └─ Failure → CLI diagnosis → retry → success/fail
├─ Skill 2: execute ...
└─ Phase 5: git checkpoint
```
## Examples
```bash
# Execute all pending tasks
/idaw:run -y
# Execute specific tasks
/idaw:run --task IDAW-001,IDAW-003
# Dry run (show plan without executing)
/idaw:run --dry-run
# Interactive mode (confirm at each step)
/idaw:run
```

View File

@@ -1,182 +0,0 @@
---
name: status
description: View IDAW task and session progress
argument-hint: "[session-id]"
allowed-tools: Read(*), Glob(*), Bash(*)
---
# IDAW Status Command (/idaw:status)
## Overview
Read-only command to view IDAW task queue and execution session progress.
## Implementation
### Phase 1: Determine View Mode
```javascript
const sessionId = $ARGUMENTS?.trim();
if (sessionId) {
// Specific session view
showSession(sessionId);
} else {
// Overview: pending tasks + latest session
showOverview();
}
```
### Phase 2: Show Overview
```javascript
function showOverview() {
// 1. Load all tasks
const taskFiles = Glob('.workflow/.idaw/tasks/IDAW-*.json') || [];
if (taskFiles.length === 0) {
console.log('No IDAW tasks found. Use /idaw:add to create tasks.');
return;
}
const tasks = taskFiles.map(f => JSON.parse(Read(f)));
// 2. Group by status
const byStatus = {
pending: tasks.filter(t => t.status === 'pending'),
in_progress: tasks.filter(t => t.status === 'in_progress'),
completed: tasks.filter(t => t.status === 'completed'),
failed: tasks.filter(t => t.status === 'failed'),
skipped: tasks.filter(t => t.status === 'skipped')
};
// 3. Display task summary table
console.log('# IDAW Tasks\n');
console.log('| ID | Title | Type | Priority | Status |');
console.log('|----|-------|------|----------|--------|');
// Sort: priority ASC, then ID ASC
const sorted = [...tasks].sort((a, b) => {
if (a.priority !== b.priority) return a.priority - b.priority;
return a.id.localeCompare(b.id);
});
for (const t of sorted) {
const type = t.task_type || '(infer)';
console.log(`| ${t.id} | ${t.title.substring(0, 40)} | ${type} | ${t.priority} | ${t.status} |`);
}
console.log(`\nTotal: ${tasks.length} | Pending: ${byStatus.pending.length} | Completed: ${byStatus.completed.length} | Failed: ${byStatus.failed.length}`);
// 4. Show latest session (if any)
const sessionDirs = Glob('.workflow/.idaw/sessions/IDA-*/session.json') || [];
if (sessionDirs.length > 0) {
// Sort by modification time (newest first) — Glob returns sorted by mtime
const latestSessionFile = sessionDirs[0];
const session = JSON.parse(Read(latestSessionFile));
console.log(`\n## Latest Session: ${session.session_id}`);
console.log(`Status: ${session.status} | Tasks: ${session.tasks?.length || 0}`);
console.log(`Completed: ${session.completed?.length || 0} | Failed: ${session.failed?.length || 0} | Skipped: ${session.skipped?.length || 0}`);
}
}
```
### Phase 3: Show Specific Session
```javascript
function showSession(sessionId) {
const sessionFile = `.workflow/.idaw/sessions/${sessionId}/session.json`;
const progressFile = `.workflow/.idaw/sessions/${sessionId}/progress.md`;
// Try reading session
try {
const session = JSON.parse(Read(sessionFile));
console.log(`# IDAW Session: ${session.session_id}\n`);
console.log(`Status: ${session.status}`);
console.log(`Created: ${session.created_at}`);
console.log(`Updated: ${session.updated_at}`);
console.log(`Current Task: ${session.current_task || 'none'}\n`);
// Task detail table
console.log('| ID | Title | Status | Commit |');
console.log('|----|-------|--------|--------|');
for (const taskId of session.tasks) {
const taskFile = `.workflow/.idaw/tasks/${taskId}.json`;
try {
const task = JSON.parse(Read(taskFile));
const commit = task.execution?.git_commit?.substring(0, 7) || '-';
console.log(`| ${task.id} | ${task.title.substring(0, 40)} | ${task.status} | ${commit} |`);
} catch {
console.log(`| ${taskId} | (file not found) | unknown | - |`);
}
}
console.log(`\nCompleted: ${session.completed?.length || 0} | Failed: ${session.failed?.length || 0} | Skipped: ${session.skipped?.length || 0}`);
// Show progress.md if exists
try {
const progress = Read(progressFile);
console.log('\n---\n');
console.log(progress);
} catch {
// No progress file yet
}
} catch {
// Session not found — try listing all sessions
console.log(`Session "${sessionId}" not found.\n`);
listSessions();
}
}
```
### Phase 4: List All Sessions
```javascript
function listSessions() {
const sessionFiles = Glob('.workflow/.idaw/sessions/IDA-*/session.json') || [];
if (sessionFiles.length === 0) {
console.log('No IDAW sessions found. Use /idaw:run to start execution.');
return;
}
console.log('# IDAW Sessions\n');
console.log('| Session ID | Status | Tasks | Completed | Failed |');
console.log('|------------|--------|-------|-----------|--------|');
for (const f of sessionFiles) {
try {
const session = JSON.parse(Read(f));
console.log(`| ${session.session_id} | ${session.status} | ${session.tasks?.length || 0} | ${session.completed?.length || 0} | ${session.failed?.length || 0} |`);
} catch {
// Skip malformed
}
}
console.log('\nUse /idaw:status <session-id> for details.');
}
```
## Examples
```bash
# Show overview (pending tasks + latest session)
/idaw:status
# Show specific session details
/idaw:status IDA-auth-fix-20260301
# Output example:
# IDAW Tasks
#
# | ID | Title | Type | Priority | Status |
# |----------|------------------------------------|--------|----------|-----------|
# | IDAW-001 | Fix auth token refresh | bugfix | 1 | completed |
# | IDAW-002 | Add rate limiting | feature| 2 | pending |
# | IDAW-003 | Refactor payment module | refact | 3 | pending |
#
# Total: 3 | Pending: 2 | Completed: 1 | Failed: 0
```

View File

@@ -0,0 +1,811 @@
---
name: workflow-tune
description: Workflow tuning - extract commands from reference docs or natural language, execute each via ccw cli --tool claude --mode write, then analyze artifacts via gemini. For testing how commands execute in Claude.
argument-hint: "<file-path> <intent> | \"step1 | step2 | step3\" | \"skill-a,skill-b\" | --file workflow.json [--depth quick|standard|deep] [-y|--yes] [--auto-fix]"
allowed-tools: Agent(*), AskUserQuestion(*), TaskCreate(*), TaskUpdate(*), TaskList(*), Read(*), Write(*), Edit(*), Bash(*), Glob(*), Grep(*)
---
# Workflow Tune
测试 Claude command/skill 的执行效果并优化。提取可执行命令,逐步通过 `ccw cli --tool claude` 执行,分析产物质量,生成优化建议。
## Tool Assignment
| Phase | Tool | Mode | Rule |
|-------|------|------|------|
| Execute | `claude` | `write` | `universal-rigorous-style` |
| Analyze | `gemini` | `analysis` | `analysis-review-code-quality` |
| Synthesize | `gemini` | `analysis` | `analysis-review-architecture` |
## Architecture
```
Input → Parse → GenTestTask → Confirm → Setup → [resolveCmd → readMeta → assemblePrompt → Execute → STOP → Analyze → STOP]×N → Synthesize → STOP → Report
↑ ↑
Claude 直接生成测试任务 prompt 中注入 test_task
(无需 CLI 调用) 作为命令的执行输入
```
## Input Formats
```
1. --file workflow.json → JSON definition
2. "cmd1 | cmd2 | cmd3" → pipe-separated commands
3. "skill-a,skill-b,skill-c" → comma-separated skills
4. natural language → semantic decomposition
4a: <file-path> <intent> → extract commands from reference doc via LLM
4b: <pure intent text> → intent-verb matching → ccw cli command assembly
```
**ANTI-PATTERN**: Steps like `{ command: "分析 Phase 管线" }` are WRONG — descriptions, not commands. Correct: `{ command: "/workflow-lite-plan analyze auth module" }` or `{ command: "ccw cli -p '...' --tool claude --mode write" }`
## Utility: Shell Escaping
```javascript
function escapeForShell(str) {
// Replace single quotes with escaped version, wrap in single quotes
return "'" + str.replace(/'/g, "'\\''") + "'";
}
```
## Phase 1: Setup
### Step 1.1: Parse Input + Preference Collection
```javascript
const args = $ARGUMENTS.trim();
const autoYes = /\b(-y|--yes)\b/.test(args);
// Preference collection (skip if -y)
if (autoYes) {
workflowPreferences = { autoYes: true, analysisDepth: 'standard', autoFix: false };
} else {
const prefResponse = AskUserQuestion({
questions: [
{ question: "选择调优配置:", header: "Tune Config", multiSelect: false,
options: [
{ label: "Quick (轻量分析)", description: "每步简要检查" },
{ label: "Standard (标准分析) (Recommended)", description: "每步详细分析" },
{ label: "Deep (深度分析)", description: "深度审查含架构建议" }
]
},
{ question: "是否自动应用优化建议?", header: "Auto Fix", multiSelect: false,
options: [
{ label: "No (仅报告) (Recommended)", description: "只分析不修改" },
{ label: "Yes (自动应用)", description: "自动应用高优先级建议" }
]
}
]
});
const depthMap = { "Quick": "quick", "Standard": "standard", "Deep": "deep" };
const selectedDepth = Object.keys(depthMap).find(k => prefResponse["Tune Config"].startsWith(k)) || "Standard";
workflowPreferences = {
autoYes: false,
analysisDepth: depthMap[selectedDepth],
autoFix: prefResponse["Auto Fix"].startsWith("Yes")
};
}
// Parse --depth override
const depthMatch = args.match(/--depth\s+(quick|standard|deep)/);
if (depthMatch) workflowPreferences.analysisDepth = depthMatch[1];
// ── Format Detection ──
let steps = [], workflowName = 'unnamed-workflow', inputFormat = '';
let projectScenario = ''; // ★ 统一虚构项目场景,所有步骤共享(在 Step 1.1a 生成)
const fileMatch = args.match(/--file\s+"?([^\s"]+)"?/);
if (fileMatch) {
const wfDef = JSON.parse(Read(fileMatch[1]));
workflowName = wfDef.name || 'unnamed-workflow';
projectScenario = wfDef.project_scenario || wfDef.description || '';
steps = wfDef.steps;
inputFormat = 'json';
}
else if (args.includes('|')) {
const rawSteps = args.split(/(?:--context|--depth|-y|--yes|--auto-fix)\s+("[^"]*"|\S+)/)[0];
steps = rawSteps.split('|').map((cmd, i) => ({
name: `step-${i + 1}`,
command: cmd.trim(),
expected_artifacts: [], success_criteria: ''
}));
inputFormat = 'pipe';
}
else if (/^[\w-]+(,[\w-]+)+/.test(args.split(/\s/)[0])) {
const skillNames = args.match(/^([^\s]+)/)[1].split(',');
steps = skillNames.map(name => ({
name, command: `/${name}`,
expected_artifacts: [], success_criteria: ''
}));
inputFormat = 'skills';
}
else {
inputFormat = 'natural-language';
let naturalLanguageInput = args.replace(/--\w+\s+"[^"]*"/g, '').replace(/--\w+\s+\S+/g, '').replace(/-y|--yes/g, '').trim();
const filePathPattern = /(?:[A-Za-z]:[\\\/][^\s,;]+|\/[^\s,;]+\.(?:md|txt|json|yaml|yml|toml)|\.\/?[^\s,;]+\.(?:md|txt|json|yaml|yml|toml))/g;
const detectedPaths = naturalLanguageInput.match(filePathPattern) || [];
let referenceDocContent = null, referenceDocPath = null;
if (detectedPaths.length > 0) {
referenceDocPath = detectedPaths[0];
try {
referenceDocContent = Read(referenceDocPath);
naturalLanguageInput = naturalLanguageInput.replace(referenceDocPath, '').trim();
} catch (e) { referenceDocContent = null; }
}
// → Mode 4a/4b in Step 1.1b
}
// workflowContext 已移除 — 统一使用 projectScenario在 Step 1.1a 生成)
```
### Step 1.1a: Generate Test Task (测试任务直接生成)
> **核心概念**: 所有步骤共享一个**统一虚构项目场景**(如"在线书店网站"),每个命令根据自身能力获得该场景下的一个子任务。由当前 Claude 直接生成,不需要额外 CLI 调用。所有执行在独立沙箱目录中进行,不影响真实项目。
```javascript
// ★ 测试任务直接生成 — 无需 CLI 调用
// 来源优先级:
// 1. JSON 定义中的 step.test_task 字段 (已有则跳过)
// 2. 当前 Claude 直接生成
const stepsNeedTask = steps.filter(s => !s.test_task);
if (stepsNeedTask.length > 0) {
// ── Step A: 生成统一项目场景 ──
// 根据命令链的整体复杂度,选一个虚构项目作为测试场景
// 场景必须:完全虚构、与当前工作空间无关、足够支撑所有步骤
//
// 场景池示例(根据步骤数量和类型选择合适规模):
// 1-2 步: 小型项目 — "命令行 TODO 工具" "Markdown 转 HTML 工具" "天气查询 CLI"
// 3-4 步: 中型项目 — "在线书店网站" "团队任务看板" "博客系统"
// 5+ 步: 大型项目 — "多租户 SaaS 平台" "电商系统" "在线教育平台"
projectScenario = /* Claude 从上述池中选择或自创一个场景 */;
// 例如: "在线书店网站 — 支持用户注册登录、书籍搜索浏览、购物车、订单管理、评论系统"
// ── Step B: 为每步生成子任务 ──
for (const step of stepsNeedTask) {
const cmdFile = resolveCommandFile(step.command);
const cmdMeta = readCommandMeta(cmdFile);
const cmdDesc = (cmdMeta?.description || step.command).toLowerCase();
// 根据命令类型分配场景下的子任务
// 每个子任务必须按以下模板生成:
//
// ┌─────────────────────────────────────────────────┐
// │ 项目: {projectScenario} │
// │ 任务: {具体子任务描述} │
// │ 功能点: │
// │ 1. {功能点1 — 具体到接口/组件/模块} │
// │ 2. {功能点2} │
// │ 3. {功能点3} │
// │ 技术约束: {语言/框架/架构要求} │
// │ 验收标准: │
// │ 1. {可验证的标准1} │
// │ 2. {可验证的标准2} │
// └─────────────────────────────────────────────────┘
//
// 命令类型 → 子任务映射:
// plan/design → 架构设计任务: "为{场景}设计技术架构包含模块划分、数据模型、API 设计"
// implement → 功能实现任务: "实现{场景}的{某模块},包含{具体功能点}"
// analyze/review→ 代码分析任务: "先在沙箱创建{场景}的{某模块}示例代码,然后分析其质量"
// test → 测试任务: "为{场景}的{某模块}编写测试,覆盖{具体场景}"
// fix/debug → 修复任务: "先在沙箱创建含已知 bug 的代码,然后诊断修复"
// refactor → 重构任务: "先在沙箱创建可工作但需重构的代码,然后重构"
step.test_task = /* 按上述模板生成,必须包含:项目、任务、功能点、技术约束、验收标准 */;
step.acceptance_criteria = /* 从 test_task 中提取 2-4 条可验证标准 */;
step.complexity_level = /plan|design|architect/i.test(cmdDesc) ? 'high'
: /test|lint|format/i.test(cmdDesc) ? 'low' : 'medium';
}
}
```
**模拟示例** — 输入 `workflow-lite-plan,workflow-lite-execute`:
```
场景: 在线书店网站 — 支持用户注册登录、书籍搜索、购物车、订单管理
Step 1 (workflow-lite-plan → plan 类, high):
项目: 在线书店网站
任务: 为在线书店设计技术架构和实现计划
功能点:
1. 用户模块 — 注册、登录、个人信息管理
2. 书籍模块 — 搜索、分类浏览、详情页
3. 交易模块 — 购物车、下单、支付状态
4. 数据模型 — User, Book, Order, CartItem 表结构设计
技术约束: TypeScript + Express + SQLite, REST API
验收标准:
1. 输出包含模块划分和依赖关系
2. 包含数据模型定义
3. 包含 API 路由清单
4. 包含实现步骤分解
Step 2 (workflow-lite-execute → implement 类, medium):
项目: 在线书店网站
任务: 根据 Step 1 的计划,实现书籍搜索和浏览模块
功能点:
1. GET /api/books — 分页列表,支持按标题/作者搜索
2. GET /api/books/:id — 书籍详情
3. GET /api/categories — 分类列表
4. Book 数据模型 + seed 数据
技术约束: TypeScript + Express + SQLite, 沿用 Step 1 架构
验收标准:
1. API 可正常调用返回 JSON
2. 搜索支持模糊匹配
3. 包含至少 5 条 seed 数据
```
### Step 1.1b: Semantic Decomposition (Format 4 only)
#### Mode 4a: Reference Document → LLM Extraction
```javascript
if (inputFormat === 'natural-language' && referenceDocContent) {
const extractPrompt = `PURPOSE: Extract ACTUAL EXECUTABLE COMMANDS from the reference document. The user wants to TEST these commands by running them.
USER INTENT: ${naturalLanguageInput}
REFERENCE DOCUMENT: ${referenceDocPath}
DOCUMENT CONTENT:
${referenceDocContent}
CRITICAL RULES:
- "command" field MUST be a real executable: slash command (/skill-name args), ccw cli call, or shell command
- CORRECT: { "command": "/workflow-lite-plan analyze auth module" }
- CORRECT: { "command": "ccw cli -p 'review code' --tool claude --mode write" }
- WRONG: { "command": "分析 Phase 管线" } ← DESCRIPTION, not command
- Default mode to "write"
EXPECTED OUTPUT (strict JSON):
{
"workflow_name": "<name>",
"project_scenario": "<虚构项目场景>",
"steps": [{ "name": "", "command": "<executable>", "expected_artifacts": [], "success_criteria": "" }]
}`;
Bash({
command: `ccw cli -p ${escapeForShell(extractPrompt)} --tool claude --mode write --rule universal-rigorous-style`,
run_in_background: true, timeout: 300000
});
// ■ STOP — wait for hook callback, parse JSON → steps[]
}
```
#### Mode 4b: Pure Intent → Command Assembly
```javascript
if (inputFormat === 'natural-language' && !referenceDocContent) {
// Intent → rule mapping for ccw cli command generation
const intentMap = [
{ pattern: /分析|analyze|审查|inspect|scan/i, name: 'analyze', rule: 'analysis-analyze-code-patterns' },
{ pattern: /评审|review|code.?review/i, name: 'review', rule: 'analysis-review-code-quality' },
{ pattern: /诊断|debug|排查|diagnose/i, name: 'diagnose', rule: 'analysis-diagnose-bug-root-cause' },
{ pattern: /安全|security|漏洞/i, name: 'security-audit', rule: 'analysis-assess-security-risks' },
{ pattern: /性能|performance|perf/i, name: 'perf-analysis', rule: 'analysis-analyze-performance' },
{ pattern: /架构|architecture/i, name: 'arch-review', rule: 'analysis-review-architecture' },
{ pattern: /修复|fix|repair|解决/i, name: 'fix', rule: 'development-debug-runtime-issues' },
{ pattern: /实现|implement|开发|create|新增/i, name: 'implement', rule: 'development-implement-feature' },
{ pattern: /重构|refactor/i, name: 'refactor', rule: 'development-refactor-codebase' },
{ pattern: /测试|test/i, name: 'test', rule: 'development-generate-tests' },
{ pattern: /规划|plan|设计|design/i, name: 'plan', rule: 'planning-plan-architecture-design' },
];
const segments = naturalLanguageInput
.split(/[,;、]|(?:然后|接着|之后|最后|再|并|and then|then|finally|next)\s*/i)
.map(s => s.trim()).filter(Boolean);
// ★ 将意图文本转化为完整的 ccw cli 命令
steps = segments.map((segment, i) => {
const matched = intentMap.find(m => m.pattern.test(segment));
const rule = matched?.rule || 'universal-rigorous-style';
// 组装真正可执行的命令
const command = `ccw cli -p ${escapeForShell('PURPOSE: ' + segment + '\\nTASK: Execute based on intent\\nCONTEXT: @**/*')} --tool claude --mode write --rule ${rule}`;
return {
name: matched?.name || `step-${i + 1}`,
command,
original_intent: segment, // 保留原始意图用于分析
expected_artifacts: [], success_criteria: ''
};
});
}
```
### Step 1.1c: Execution Plan Confirmation
```javascript
function generateCommandDoc(steps, workflowName, projectScenario, analysisDepth) {
const stepTable = steps.map((s, i) => {
const cmdPreview = s.command.length > 60 ? s.command.substring(0, 57) + '...' : s.command;
const taskPreview = (s.test_task || '-').length > 40 ? s.test_task.substring(0, 37) + '...' : (s.test_task || '-');
return `| ${i + 1} | ${s.name} | \`${cmdPreview}\` | ${taskPreview} |`;
}).join('\n');
return `# Workflow Tune — Execution Plan\n\n**Workflow**: ${workflowName}\n**Test Project**: ${projectScenario}\n**Steps**: ${steps.length}\n**Depth**: ${analysisDepth}\n\n| # | Name | Command | Test Task |\n|---|------|---------|-----------|\n${stepTable}`;
}
const commandDoc = generateCommandDoc(steps, workflowName, projectScenario, workflowPreferences.analysisDepth);
if (!workflowPreferences.autoYes) {
const confirmation = AskUserQuestion({
questions: [{
question: commandDoc + "\n\n确认执行以上 Workflow 调优计划?", header: "Confirm Execution", multiSelect: false,
options: [
{ label: "Execute (确认执行)", description: "按计划开始执行" },
{ label: "Cancel (取消)", description: "取消" }
]
}]
});
if (confirmation["Confirm Execution"].startsWith("Cancel")) return;
}
```
### Step 1.2: (Merged into Step 1.1a)
> Test requirements (acceptance_criteria) are now generated together with test_task in Step 1.1a, avoiding an extra CLI call.
### Step 1.3: Create Workspace + Sandbox Project
```javascript
const ts = Date.now();
const workDir = `.workflow/.scratchpad/workflow-tune-${ts}`;
// ★ 创建独立沙箱项目目录 — 所有命令执行在此目录中,不影响真实项目
const sandboxDir = `${workDir}/sandbox`;
Bash(`mkdir -p "${workDir}/steps" "${sandboxDir}"`);
// 初始化沙箱为独立 git 仓库(部分命令依赖 git 环境)
Bash(`cd "${sandboxDir}" && git init && echo "# Sandbox Project" > README.md && git add . && git commit -m "init sandbox"`);
for (let i = 0; i < steps.length; i++) Bash(`mkdir -p "${workDir}/steps/step-${i + 1}/artifacts"`);
Write(`${workDir}/command-doc.md`, commandDoc);
const initialState = {
status: 'running', started_at: new Date().toISOString(),
workflow_name: workflowName, project_scenario: projectScenario,
analysis_depth: workflowPreferences.analysisDepth, auto_fix: workflowPreferences.autoFix,
sandbox_dir: sandboxDir, // ★ 独立沙箱项目目录
current_step: 0, // ★ State machine cursor
current_phase: 'execute', // 'execute' | 'analyze'
steps: steps.map((s, i) => ({
...s, index: i, status: 'pending',
test_task: s.test_task || '', // ★ 每步的测试任务
execution: null, analysis: null,
test_requirements: s.test_requirements || null
})),
gemini_session_id: null, // ★ Updated after each gemini callback
work_dir: workDir,
errors: [], error_count: 0, max_errors: 3
};
Write(`${workDir}/workflow-state.json`, JSON.stringify(initialState, null, 2));
Write(`${workDir}/process-log.md`, `# Process Log\n\n**Workflow**: ${workflowName}\n**Test Project**: ${projectScenario}\n**Steps**: ${steps.length}\n**Started**: ${new Date().toISOString()}\n\n---\n\n`);
```
## Phase 2: Execute Step
### resolveCommandFile — Slash command → file path
```javascript
function resolveCommandFile(command) {
const cmdMatch = command.match(/^\/?([^\s]+)/);
if (!cmdMatch) return null;
const cmdName = cmdMatch[1];
const cmdPath = cmdName.replace(/:/g, '/');
const searchRoots = ['.claude', '~/.claude'];
for (const root of searchRoots) {
const candidates = [
`${root}/commands/${cmdPath}.md`,
`${root}/commands/${cmdPath}/index.md`,
];
for (const candidate of candidates) {
try { Read(candidate, { limit: 1 }); return candidate; } catch {}
}
}
for (const root of searchRoots) {
const candidates = [
`${root}/skills/${cmdName}/SKILL.md`,
`${root}/skills/${cmdPath.replace(/\//g, '-')}/SKILL.md`,
];
for (const candidate of candidates) {
try { Read(candidate, { limit: 1 }); return candidate; } catch {}
}
}
return null;
}
```
### readCommandMeta — Read YAML frontmatter + body summary
```javascript
function readCommandMeta(filePath) {
if (!filePath) return null;
const content = Read(filePath);
const meta = { filePath, name: '', description: '', argumentHint: '', allowedTools: '', bodySummary: '' };
const yamlMatch = content.match(/^---\n([\s\S]*?)\n---/);
if (yamlMatch) {
const yaml = yamlMatch[1];
const nameMatch = yaml.match(/^name:\s*(.+)$/m);
const descMatch = yaml.match(/^description:\s*(.+)$/m);
const hintMatch = yaml.match(/^argument-hint:\s*"?(.+?)"?\s*$/m);
const toolsMatch = yaml.match(/^allowed-tools:\s*(.+)$/m);
if (nameMatch) meta.name = nameMatch[1].trim();
if (descMatch) meta.description = descMatch[1].trim();
if (hintMatch) meta.argumentHint = hintMatch[1].trim();
if (toolsMatch) meta.allowedTools = toolsMatch[1].trim();
}
const bodyStart = content.indexOf('---', content.indexOf('---') + 3);
if (bodyStart !== -1) {
const body = content.substring(bodyStart + 3).trim();
meta.bodySummary = body.split('\n').slice(0, 30).join('\n');
}
return meta;
}
```
### assembleStepPrompt — Build execution prompt from command metadata
```javascript
function assembleStepPrompt(step, stepIdx, state) {
// ── 1. Resolve command file + metadata ──
const isSlashCmd = step.command.startsWith('/');
const cmdFile = isSlashCmd ? resolveCommandFile(step.command) : null;
const cmdMeta = readCommandMeta(cmdFile);
const cmdArgs = isSlashCmd ? step.command.replace(/^\/?[^\s]+\s*/, '').trim() : '';
// ── 2. Prior/next step context ──
const prevStep = stepIdx > 0 ? state.steps[stepIdx - 1] : null;
const nextStep = stepIdx < state.steps.length - 1 ? state.steps[stepIdx + 1] : null;
const priorContext = prevStep
? `PRIOR STEP: "${prevStep.name}" — ${prevStep.command}\n Status: ${prevStep.status} | Artifacts: ${prevStep.execution?.artifact_count || 0}`
: 'PRIOR STEP: None (first step)';
const nextContext = nextStep
? `NEXT STEP: "${nextStep.name}" — ${nextStep.command}\n Ensure output is consumable by next step`
: 'NEXT STEP: None (last step)';
// ── 3. Acceptance criteria (from test_task generation) ──
const criteria = step.acceptance_criteria || [];
const testReqSection = criteria.length > 0
? `ACCEPTANCE CRITERIA:\n${criteria.map((c, i) => ` ${i + 1}. ${c}`).join('\n')}`
: '';
// ── 4. Test task — the concrete scenario to drive execution ──
const testTask = step.test_task || '';
const testTaskSection = testTask
? `TEST TASK (用此任务驱动命令执行):\n ${testTask}`
: '';
// ── 5. Build prompt based on whether command has metadata ──
if (cmdMeta) {
// Slash command with resolved file — rich context prompt
return `PURPOSE: Execute workflow step "${step.name}" (${stepIdx + 1}/${state.steps.length}).
COMMAND DEFINITION:
Name: ${cmdMeta.name}
Description: ${cmdMeta.description}
Argument Format: ${cmdMeta.argumentHint || 'none'}
Allowed Tools: ${cmdMeta.allowedTools || 'default'}
Source: ${cmdMeta.filePath}
COMMAND TO EXECUTE: ${step.command}
ARGUMENTS: ${cmdArgs || '(no arguments)'}
${testTaskSection}
COMMAND REFERENCE (first 30 lines):
${cmdMeta.bodySummary}
PROJECT: ${state.project_scenario}
SANDBOX PROJECT: ${state.sandbox_dir}
OUTPUT DIR: ${state.work_dir}/steps/step-${stepIdx + 1}
${priorContext}
${nextContext}
${testReqSection}
TASK: Execute the command as described in COMMAND DEFINITION, using TEST TASK as the input/scenario. Use the COMMAND REFERENCE to understand expected behavior. All work happens in the SANDBOX PROJECT directory (an isolated empty project, NOT the real workspace). Auto-confirm all prompts.
CONSTRAINTS: Stay scoped to this step only. Follow the command's own execution flow. The TEST TASK is the real work — treat it as the $ARGUMENTS input to the command. Do NOT read/modify files outside SANDBOX PROJECT.`;
} else {
// Shell command, ccw cli command, or unresolved command
return `PURPOSE: Execute workflow step "${step.name}" (${stepIdx + 1}/${state.steps.length}).
COMMAND: ${step.command}
${testTaskSection}
PROJECT: ${state.project_scenario}
SANDBOX PROJECT: ${state.sandbox_dir}
OUTPUT DIR: ${state.work_dir}/steps/step-${stepIdx + 1}
${priorContext}
${nextContext}
${testReqSection}
TASK: Execute the COMMAND above with TEST TASK as the input scenario. All work happens in the SANDBOX PROJECT directory (an isolated empty project). Auto-confirm all prompts.
CONSTRAINTS: Stay scoped to this step only. The TEST TASK is the real work to execute. Do NOT read/modify files outside SANDBOX PROJECT.`;
}
}
```
### Step Execution
```javascript
const stepIdx = state.current_step;
const step = state.steps[stepIdx];
const stepDir = `${state.work_dir}/steps/step-${stepIdx + 1}`;
// Pre-execution: snapshot sandbox directory files
const preFiles = Bash(`find "${state.sandbox_dir}" -type f 2>/dev/null | sort`).stdout.trim();
Write(`${stepDir}/pre-exec-snapshot.txt`, preFiles || '(empty)');
const startTime = Date.now();
const prompt = assembleStepPrompt(step, stepIdx, state);
// ★ All steps execute via ccw cli --tool claude --mode write
// ★ --cd 指向沙箱目录(独立项目),不影响真实工作空间
Bash({
command: `ccw cli -p ${escapeForShell(prompt)} --tool claude --mode write --rule universal-rigorous-style --cd "${state.sandbox_dir}"`,
run_in_background: true, timeout: 600000
});
// ■ STOP — wait for hook callback
```
### Post-Execute Callback Handler
```javascript
// ★ This runs after receiving the ccw cli callback
const duration = Date.now() - startTime;
// Collect artifacts by scanning sandbox (not git diff — sandbox is an independent project)
const postFiles = Bash(`find "${state.sandbox_dir}" -type f -newer "${stepDir}/pre-exec-snapshot.txt" 2>/dev/null | sort`).stdout.trim();
const newArtifacts = postFiles ? postFiles.split('\n').filter(f => !f.endsWith('.git/')) : [];
const artifactManifest = {
step: step.name, step_index: stepIdx,
success: true, duration_ms: duration,
artifacts: newArtifacts.map(f => ({
path: f,
type: f.endsWith('.md') ? 'markdown' : f.endsWith('.json') ? 'json' : 'other'
})),
collected_at: new Date().toISOString()
};
Write(`${stepDir}/artifacts-manifest.json`, JSON.stringify(artifactManifest, null, 2));
// Update state
state.steps[stepIdx].status = 'executed';
state.steps[stepIdx].execution = {
success: true, duration_ms: duration,
artifact_count: newArtifacts.length
};
state.current_phase = 'analyze';
Write(`${state.work_dir}/workflow-state.json`, JSON.stringify(state, null, 2));
// → Proceed to Phase 3 for this step
```
## Phase 3: Analyze Step (per step, via gemini)
```javascript
const manifest = JSON.parse(Read(`${stepDir}/artifacts-manifest.json`));
// Build artifact content for analysis
let artifactSummary = '';
if (state.analysis_depth === 'quick') {
artifactSummary = manifest.artifacts.map(a => `- ${a.path} (${a.type})`).join('\n');
} else {
const maxLines = state.analysis_depth === 'deep' ? 300 : 150;
artifactSummary = manifest.artifacts.map(a => {
try { return `--- ${a.path} ---\n${Read(a.path, { limit: maxLines })}`; }
catch { return `--- ${a.path} --- [unreadable]`; }
}).join('\n\n');
}
const criteria = step.acceptance_criteria || [];
const testTaskDesc = step.test_task ? `TEST TASK: ${step.test_task}` : '';
const criteriaSection = criteria.length > 0
? `ACCEPTANCE CRITERIA:\n${criteria.map((c, i) => ` ${i + 1}. ${c}`).join('\n')}`
: '';
const analysisPrompt = `PURPOSE: Evaluate execution quality of step "${step.name}" (${stepIdx + 1}/${state.steps.length}).
WORKFLOW: ${state.workflow_name}${state.project_scenario}
COMMAND: ${step.command}
${testTaskDesc}
${criteriaSection}
EXECUTION: Duration ${step.execution.duration_ms}ms | Artifacts: ${manifest.artifacts.length}
ARTIFACTS:\n${artifactSummary}
EXPECTED OUTPUT (strict JSON):
{ "quality_score": <0-100>, "requirement_match": { "pass": <bool>, "criteria_met": [], "criteria_missed": [], "fail_signals_detected": [] }, "execution_assessment": { "success": <bool>, "completeness": "", "notes": "" }, "artifact_assessment": { "count": <n>, "quality": "", "key_outputs": [], "missing_outputs": [] }, "issues": [{ "severity": "critical|high|medium|low", "description": "", "suggestion": "" }], "optimization_opportunities": [{ "area": "", "description": "", "impact": "high|medium|low" }], "step_summary": "" }`;
let cliCommand = `ccw cli -p ${escapeForShell(analysisPrompt)} --tool gemini --mode analysis --rule analysis-review-code-quality`;
if (state.gemini_session_id) cliCommand += ` --resume ${state.gemini_session_id}`;
Bash({ command: cliCommand, run_in_background: true, timeout: 300000 });
// ■ STOP — wait for hook callback
```
### Post-Analyze Callback Handler
```javascript
// ★ Parse analysis result JSON from callback
const analysisResult = /* parsed from callback output */;
// ★ Capture gemini session ID for resume chain
// Session ID is in stderr: [CCW_EXEC_ID=gem-xxxxxx-xxxx]
state.gemini_session_id = /* captured from callback exec_id */;
Write(`${stepDir}/step-${stepIdx + 1}-analysis.json`, JSON.stringify(analysisResult, null, 2));
// Update state
state.steps[stepIdx].analysis = {
quality_score: analysisResult.quality_score,
requirement_pass: analysisResult.requirement_match?.pass,
issue_count: (analysisResult.issues || []).length
};
state.steps[stepIdx].status = 'completed';
// Append to process log
const logEntry = `## Step ${stepIdx + 1}: ${step.name}\n- Score: ${analysisResult.quality_score}/100\n- Req: ${analysisResult.requirement_match?.pass ? 'PASS' : 'FAIL'}\n- Issues: ${(analysisResult.issues || []).length}\n- Summary: ${analysisResult.step_summary}\n\n`;
Edit(`${state.work_dir}/process-log.md`, /* append logEntry */);
// ★ Advance state machine
state.current_step = stepIdx + 1;
state.current_phase = 'execute';
Write(`${state.work_dir}/workflow-state.json`, JSON.stringify(state, null, 2));
// ★ Decision: advance or synthesize
if (state.current_step < state.steps.length) {
// → Back to Phase 2 for next step
} else {
// → Phase 4: Synthesize
}
```
## Step Loop — State Machine
```
NOT a sync for-loop. Each step follows this state machine:
┌─────────────────────────────────────────────────────┐
│ state.current_step = N, state.current_phase = X │
├─────────────────────────────────────────────────────┤
│ phase='execute' → Phase 2 → ccw cli claude → STOP │
│ callback → collect artifacts → phase='analyze' │
│ phase='analyze' → Phase 3 → ccw cli gemini → STOP │
│ callback → save analysis → current_step++ │
│ if current_step < total → phase='execute' (loop) │
│ else → Phase 4 (synthesize) │
└─────────────────────────────────────────────────────┘
Error handling:
- Execute timeout → retry once, then mark failed, advance
- Analyze failure → retry without --resume, then skip analysis
- 3+ consecutive errors → terminate, jump to Phase 5 partial report
```
## Phase 4: Synthesize (via gemini)
```javascript
const stepAnalyses = state.steps.map((step, i) => {
try { return { step: step.name, content: Read(`${state.work_dir}/steps/step-${i + 1}/step-${i + 1}-analysis.json`) }; }
catch { return { step: step.name, content: '[Not available]' }; }
});
const scores = state.steps.map(s => s.analysis?.quality_score).filter(Boolean);
const avgScore = scores.length > 0 ? Math.round(scores.reduce((a, b) => a + b, 0) / scores.length) : 0;
const synthesisPrompt = `PURPOSE: Synthesize all step analyses into holistic workflow assessment with actionable optimization plan.
WORKFLOW: ${state.workflow_name}${state.project_scenario}
Steps: ${state.steps.length} | Avg Quality: ${avgScore}/100
STEP ANALYSES:\n${stepAnalyses.map(a => `### ${a.step}\n${a.content}`).join('\n\n---\n\n')}
Evaluate: coherence across steps, handoff quality, redundancy, bottlenecks.
EXPECTED OUTPUT (strict JSON):
{ "workflow_score": <0-100>, "coherence": { "score": <0-100>, "assessment": "", "gaps": [] }, "bottlenecks": [{ "step": "", "issue": "", "suggestion": "" }], "per_step_improvements": [{ "step": "", "priority": "high|medium|low", "action": "" }], "workflow_improvements": [{ "area": "", "description": "", "impact": "high|medium|low" }], "summary": "" }`;
let cliCommand = `ccw cli -p ${escapeForShell(synthesisPrompt)} --tool gemini --mode analysis --rule analysis-review-architecture`;
if (state.gemini_session_id) cliCommand += ` --resume ${state.gemini_session_id}`;
Bash({ command: cliCommand, run_in_background: true, timeout: 300000 });
// ■ STOP — wait for hook callback → parse JSON, write synthesis.json, update state
```
## Phase 5: Report
```javascript
const synthesis = JSON.parse(Read(`${state.work_dir}/synthesis.json`));
const scores = state.steps.map(s => s.analysis?.quality_score).filter(Boolean);
const avgScore = scores.length > 0 ? Math.round(scores.reduce((a, b) => a + b, 0) / scores.length) : 0;
const totalIssues = state.steps.reduce((sum, s) => sum + (s.analysis?.issue_count || 0), 0);
const stepTable = state.steps.map((s, i) => {
const reqStr = s.analysis?.requirement_pass === true ? 'PASS' : s.analysis?.requirement_pass === false ? 'FAIL' : '-';
return `| ${i + 1} | ${s.name} | ${s.execution?.success ? 'OK' : 'FAIL'} | ${reqStr} | ${s.analysis?.quality_score || '-'} | ${s.analysis?.issue_count || 0} |`;
}).join('\n');
const improvements = (synthesis.per_step_improvements || [])
.filter(imp => imp.priority === 'high')
.map(imp => `- **${imp.step}**: ${imp.action}`)
.join('\n');
const report = `# Workflow Tune Report
| Field | Value |
|---|---|
| Workflow | ${state.workflow_name} |
| Test Project | ${state.project_scenario} |
| Workflow Score | ${synthesis.workflow_score || avgScore}/100 |
| Avg Step Score | ${avgScore}/100 |
| Total Issues | ${totalIssues} |
| Coherence | ${synthesis.coherence?.score || '-'}/100 |
## Step Results
| # | Step | Exec | Req | Quality | Issues |
|---|------|------|-----|---------|--------|
${stepTable}
## High Priority Improvements
${improvements || 'None'}
## Workflow-Level Improvements
${(synthesis.workflow_improvements || []).map(w => `- **${w.area}** (${w.impact}): ${w.description}`).join('\n') || 'None'}
## Bottlenecks
${(synthesis.bottlenecks || []).map(b => `- **${b.step}**: ${b.issue}${b.suggestion}`).join('\n') || 'None'}
## Summary
${synthesis.summary || 'N/A'}
`;
Write(`${state.work_dir}/final-report.md`, report);
state.status = 'completed';
Write(`${state.work_dir}/workflow-state.json`, JSON.stringify(state, null, 2));
// Output report to user
```
## Resume Chain
```
Step 1 Execute → ccw cli claude --mode write --rule universal-rigorous-style --cd step-1/ → STOP → callback → artifacts
Step 1 Analyze → ccw cli gemini --mode analysis --rule analysis-review-code-quality → STOP → callback → gemini_session_id = exec_id
Step 2 Execute → ccw cli claude --mode write --rule universal-rigorous-style --cd step-2/ → STOP → callback → artifacts
Step 2 Analyze → ccw cli gemini --mode analysis --resume gemini_session_id → STOP → callback → gemini_session_id = exec_id
...
Synthesize → ccw cli gemini --mode analysis --resume gemini_session_id → STOP → callback → synthesis
Report → local generation (no CLI call)
```
## Error Handling
| Phase | Error | Recovery |
|-------|-------|----------|
| Execute | CLI timeout | Retry once, then mark step failed and advance |
| Execute | Command not found | Skip step, note in process-log |
| Analyze | CLI fails | Retry without --resume, then skip analysis |
| Synthesize | CLI fails | Generate report from step analyses only |
| Any | 3+ consecutive errors | Terminate, produce partial report |
## Core Rules
1. **STOP After Each CLI Call**: Every `ccw cli` call runs in background — STOP output immediately, wait for hook callback
2. **State Machine**: Advance via `current_step` + `current_phase`, never use sync loops for async operations
3. **Test Task Drives Execution**: 每个命令必须有 test_task完整需求说明作为命令的 $ARGUMENTS 输入。test_task 由当前 Claude 直接根据命令链复杂度生成,不需要额外 CLI 调用
4. **All Execution via claude**: `ccw cli --tool claude --mode write --rule universal-rigorous-style`
5. **All Analysis via gemini**: `ccw cli --tool gemini --mode analysis`, chained via `--resume`
6. **Session Capture**: After each gemini callback, capture exec_id → `gemini_session_id` for resume chain
7. **Sandbox Isolation**: 所有命令在独立沙箱目录(`sandbox/`)中执行,使用虚构测试任务,不影响真实项目
8. **Artifact Collection**: Scan sandbox filesystem (not git diff), compare pre/post snapshots
9. **Prompt Assembly**: Every step goes through `assembleStepPrompt()` — resolves command file, reads YAML metadata, injects test_task, builds rich context
10. **Auto-Confirm**: All prompts auto-confirmed, no blocking interactions during execution

View File

@@ -10,11 +10,11 @@ allowed-tools: TodoWrite(*), Agent(*), AskUserQuestion(*), Read(*), Grep(*), Glo
When `--yes` or `-y`: Auto-confirm exploration decisions, use recommended analysis angles. When `--yes` or `-y`: Auto-confirm exploration decisions, use recommended analysis angles.
<purpose> <purpose>
Interactive collaborative analysis workflow combining codebase exploration (cli-explore-agent) with CLI-assisted analysis (Gemini/Codex). Produces a documented discussion timeline with evolving understanding, decision trails, and actionable conclusions. Interactive collaborative analysis workflow combining codebase exploration (cli-explore-agent), external research (workflow-research-agent), and CLI-assisted analysis (Gemini/Codex). Produces a documented discussion timeline with evolving understanding, decision trails, and actionable conclusions.
Invoked when user needs deep, multi-perspective analysis of a topic or codebase question — e.g., architecture review, implementation analysis, concept exploration, or decision evaluation. Invoked when user needs deep, multi-perspective analysis of a topic or codebase question — e.g., architecture review, implementation analysis, concept exploration, or decision evaluation.
Produces: `discussion.md` (evolving analysis document with TOC, rounds, narrative synthesis), `explorations.json`/`perspectives.json` (structured findings), `conclusions.json` (final synthesis with recommendations). All artifacts stored in `.workflow/.analysis/{session-id}/`. Produces: `discussion.md` (evolving analysis document with TOC, rounds, narrative synthesis), `explorations.json`/`perspectives.json` (structured findings), `research.json` (external research findings), `conclusions.json` (final synthesis with recommendations). All artifacts stored in `.workflow/.analysis/{session-id}/`.
</purpose> </purpose>
<conventions> <conventions>
@@ -78,10 +78,11 @@ All `AskUserQuestion` calls MUST comply:
|-------|----------|-------------| |-------|----------|-------------|
| 1 | `discussion.md` | Initialized with TOC, Current Understanding block, timeline, metadata | | 1 | `discussion.md` | Initialized with TOC, Current Understanding block, timeline, metadata |
| 1 | Session variables | Dimensions, focus areas, analysis depth | | 1 | Session variables | Dimensions, focus areas, analysis depth |
| 2 | `exploration-codebase.json` | Single codebase context from cli-explore-agent | | 2 | `exploration-codebase.json` | Shared Layer 1 discovery (files, modules, patterns) — always created |
| 2 | `explorations/*.json` | Multi-perspective codebase explorations (parallel, up to 4) | | 2 | `explorations/*.json` | Per-perspective Layer 2-3 deep-dives (multi-perspective only, max 4) |
| 2 | `explorations.json` | Single perspective aggregated findings | | 2 | `research.json` | External research findings (best practices, API details, known issues) — from workflow-research-agent |
| 2 | `perspectives.json` | Multi-perspective findings (up to 4) with synthesis | | 2 | `explorations.json` | Single perspective aggregated findings (Layer 1 + CLI analysis + research) |
| 2 | `perspectives.json` | Multi-perspective findings (Layer 1 shared + per-perspective deep-dives + research) with synthesis |
| 2 | Updated `discussion.md` | Round 1 + Initial Intent Coverage Check + Current Understanding replaced | | 2 | Updated `discussion.md` | Round 1 + Initial Intent Coverage Check + Current Understanding replaced |
| 3 | Updated `discussion.md` | Round 2-N: feedback, insights, narrative synthesis; TOC + Current Understanding updated each round | | 3 | Updated `discussion.md` | Round 2-N: feedback, insights, narrative synthesis; TOC + Current Understanding updated each round |
| 4 | `conclusions.json` | Final synthesis with recommendations (incl. steps[] + review_status) | | 4 | `conclusions.json` | Final synthesis with recommendations (incl. steps[] + review_status) |
@@ -141,98 +142,179 @@ All `AskUserQuestion` calls MUST comply:
<step name="cli_exploration"> <step name="cli_exploration">
**Phase 2: Codebase exploration FIRST, then CLI analysis.** **Phase 2: Codebase exploration FIRST, then CLI analysis.**
**Step 1: Codebase Exploration** (cli-explore-agent, parallel up to 6) **Step 1: Codebase Exploration** (cli-explore-agent, 1 shared + N perspective-specific)
- **Single**: General codebase analysis -> `{sessionFolder}/exploration-codebase.json` Two-phase approach to avoid redundant file discovery:
- **Multi-perspective**: Parallel per-perspective -> `{sessionFolder}/explorations/{perspective}.json`
- **Common tasks**: `ccw tool exec get_modules_by_depth '{}'`, keyword searches, read `.workflow/project-tech.json` **Phase A — Shared Discovery** (1 agent, always runs):
One cli-explore-agent performs Layer 1 (breadth) for ALL perspectives -> `{sessionFolder}/exploration-codebase.json`
```javascript ```javascript
// Template for cli-explore-agent (single or per-perspective) // Shared Layer 1 discovery — runs ONCE regardless of perspective count
Agent({ Agent({
subagent_type: "cli-explore-agent", subagent_type: "cli-explore-agent",
run_in_background: false, run_in_background: false,
description: `Explore codebase: ${topicSlug}`, description: `Discover codebase: ${topicSlug}`,
prompt: ` prompt: `
## Analysis Context ## Analysis Context
Topic: ${topic_or_question} Topic: ${topic_or_question}
Dimensions: ${dimensions.join(', ')} Dimensions: ${dimensions.join(', ')}
// For multi-perspective, add: Perspective: ${perspective.name} - ${perspective.focus}
Session: ${sessionFolder} Session: ${sessionFolder}
## MANDATORY FIRST STEPS ## MANDATORY FIRST STEPS
1. Run: ccw tool exec get_modules_by_depth '{}' 1. Run: ccw tool exec get_modules_by_depth '{}'
2. Read: .workflow/project-tech.json (if exists) 2. Read: .workflow/project-tech.json (if exists)
## Layered Exploration (MUST follow all 3 layers) ## Layer 1 — Module Discovery (Breadth ONLY)
- Search by topic keywords across ALL dimensions: ${dimensions.join(', ')}
### Layer 1 — Module Discovery (Breadth) - Identify ALL relevant files, map module boundaries and entry points
- Search by topic keywords, identify ALL relevant files - Categorize files by dimension/perspective relevance
- Map module boundaries and entry points -> relevant_files[] with annotations - Output: relevant_files[] with annotations + dimension tags, initial patterns[]
### Layer 2 — Structure Tracing (Depth)
- Top 3-5 key files: trace call chains 2-3 levels deep
- Identify data flow paths and dependencies -> call_chains[], data_flows[]
### Layer 3 — Code Anchor Extraction (Detail)
- Each key finding: extract code snippet (20-50 lines) with file:line
- Annotate WHY this matters -> code_anchors[]
## Output ## Output
Write to: ${sessionFolder}/exploration-codebase.json Write to: ${sessionFolder}/exploration-codebase.json
// Multi-perspective: ${sessionFolder}/explorations/${perspective.name}.json Schema: {relevant_files: [{path, annotation, dimensions[]}], patterns[], module_map: {}, questions_for_user, _metadata}
Schema: {relevant_files, patterns, key_findings, code_anchors: [{file, lines, snippet, significance}], call_chains: [{entry, chain, files}], questions_for_user, _metadata}
` `
}) })
``` ```
**Step 2: CLI Analysis** (AFTER exploration) **Phase A2 — External Research** (parallel with Phase A, runs when topic involves technologies/patterns/APIs):
- **Single**: Comprehensive CLI analysis with exploration context Determine if external research would add value — skip for purely internal codebase questions (e.g., "how does module X work"), run for topics involving technology choices, best practices, architecture patterns, API usage, or comparison with industry standards.
- **Multi (up to 4)**: Parallel CLI calls per perspective
```javascript
// External research — runs in PARALLEL with Phase A codebase exploration
// Skip if topic is purely internal codebase navigation
const needsResearch = dimensions.some(d =>
['architecture', 'comparison', 'decision', 'performance', 'security'].includes(d)
) || topic_or_question.match(/best practice|pattern|vs|compare|approach|standard|library|framework/i)
if (needsResearch) {
Agent({
subagent_type: "workflow-research-agent",
run_in_background: false,
description: `Research: ${topicSlug}`,
prompt: `
## Research Objective
Topic: ${topic_or_question}
Mode: detail-verification
Dimensions: ${dimensions.join(', ')}
## Focus
${dimensions.includes('architecture') ? '- Architecture patterns and best practices for this domain' : ''}
${dimensions.includes('performance') ? '- Performance benchmarks and optimization patterns' : ''}
${dimensions.includes('security') ? '- Security best practices and known vulnerabilities' : ''}
${dimensions.includes('comparison') ? '- Technology comparison and trade-off analysis' : ''}
${dimensions.includes('decision') ? '- Decision frameworks and industry recommendations' : ''}
- Verify assumptions about technologies/patterns involved
- Known issues and pitfalls in this area
- Recommended approaches with evidence
## Codebase Context (from Phase A if available)
Tech stack: ${techStack || 'detect from project files'}
Key patterns observed: ${sharedDiscovery?.patterns?.join(', ') || 'pending Phase A results'}
## Output
Return structured markdown per your output format.
Do NOT write files.
`
})
// Parse research agent output → save to ${sessionFolder}/research.json
// Schema: {topic, mode, findings[], best_practices[], alternatives[], pitfalls[], sources[], _metadata}
}
```
**Phase B — Perspective Deep-Dive** (parallel, only for multi-perspective, max 4):
Each perspective agent receives shared Layer 1 results, performs only Layer 2-3 on its relevant subset.
Skip if single-perspective (single mode proceeds directly to Step 2 CLI analysis with Layer 1 results).
```javascript
// Per-perspective Layer 2-3 — receives shared discovery, avoids re-scanning
// Only runs in multi-perspective mode
const sharedDiscovery = readJSON(`${sessionFolder}/exploration-codebase.json`)
const perspectiveFiles = sharedDiscovery.relevant_files
.filter(f => f.dimensions.includes(perspective.dimension))
selectedPerspectives.forEach(perspective => {
Agent({
subagent_type: "cli-explore-agent",
run_in_background: false,
description: `Deep-dive: ${perspective.name}`,
prompt: `
## Analysis Context
Topic: ${topic_or_question}
Perspective: ${perspective.name} - ${perspective.focus}
Session: ${sessionFolder}
## SHARED DISCOVERY (Layer 1 already completed — DO NOT re-scan)
Relevant files for this perspective:
${perspectiveFiles.map(f => `- ${f.path}: ${f.annotation}`).join('\n')}
Patterns found: ${sharedDiscovery.patterns.join(', ')}
## Layer 2 — Structure Tracing (Depth)
- From the relevant files above, pick top 3-5 key files for this perspective
- Trace call chains 2-3 levels deep
- Identify data flow paths and dependencies -> call_chains[], data_flows[]
## Layer 3 — Code Anchor Extraction (Detail)
- Each key finding: extract code snippet (20-50 lines) with file:line
- Annotate WHY this matters for ${perspective.name} -> code_anchors[]
## Output
Write to: ${sessionFolder}/explorations/${perspective.name}.json
Schema: {perspective, relevant_files, key_findings, code_anchors: [{file, lines, snippet, significance}], call_chains: [{entry, chain, files}], questions_for_user, _metadata}
`
})
})
```
**Step 2: CLI Deep Analysis** (AFTER exploration, single-perspective ONLY)
- **Single-perspective**: CLI does Layer 2-3 depth analysis (explore agent only did Layer 1)
- **Multi-perspective**: SKIP this step — perspective agents in Step 1 Phase B already did Layer 2-3
- Execution: `Bash` with `run_in_background: true` - Execution: `Bash` with `run_in_background: true`
```javascript ```javascript
// Build shared exploration context for CLI prompts // ONLY for single-perspective mode — multi-perspective already has deep-dive agents
if (selectedPerspectives.length <= 1) {
const sharedDiscovery = readJSON(`${sessionFolder}/exploration-codebase.json`)
const explorationContext = ` const explorationContext = `
PRIOR EXPLORATION CONTEXT: PRIOR EXPLORATION (Layer 1 discovery):
- Key files: ${explorationResults.relevant_files.slice(0,5).map(f => f.path).join(', ')} - Key files: ${sharedDiscovery.relevant_files.slice(0,8).map(f => `${f.path} (${f.annotation})`).join(', ')}
- Patterns: ${explorationResults.patterns.slice(0,3).join(', ')} - Patterns: ${sharedDiscovery.patterns.slice(0,5).join(', ')}
- Findings: ${explorationResults.key_findings.slice(0,3).join(', ')} - Module map: ${JSON.stringify(sharedDiscovery.module_map || {})}`
- Code anchors:
${(explorationResults.code_anchors || []).slice(0,5).map(a => ` [${a.file}:${a.lines}] ${a.significance}\n \`\`\`\n ${a.snippet}\n \`\`\``).join('\n')}
- Call chains: ${(explorationResults.call_chains || []).slice(0,3).map(c => `${c.entry} -> ${c.chain.join(' -> ')}`).join('; ')}`
// Single perspective (for multi: loop selectedPerspectives with perspective.purpose/tasks/constraints)
Bash({ Bash({
command: `ccw cli -p " command: `ccw cli -p "
PURPOSE: Analyze '${topic_or_question}' from ${dimensions.join(', ')} perspectives PURPOSE: Deep analysis of '${topic_or_question}' — build on prior file discovery
Success: Actionable insights with clear reasoning Success: Actionable insights with code evidence (anchors + call chains)
${explorationContext} ${explorationContext}
TASK: TASK:
- Build on exploration findings — reference specific code anchors - From discovered files, trace call chains 2-3 levels deep for top 3-5 key files
- Analyze common patterns and anti-patterns with code evidence - Extract code snippets (20-50 lines) for each key finding with file:line
- Highlight potential issues/opportunities with file:line references - Identify patterns, anti-patterns, and potential issues with evidence
- Generate discussion points for user clarification - Generate discussion points for user clarification
MODE: analysis MODE: analysis
CONTEXT: @**/* | Topic: ${topic_or_question} CONTEXT: @**/* | Topic: ${topic_or_question}
EXPECTED: Structured analysis with sections, insights tied to evidence, questions, recommendations EXPECTED: Structured analysis with: key_findings[], code_anchors[{file,lines,snippet,significance}], call_chains[{entry,chain,files}], discussion_points[]
CONSTRAINTS: Focus on ${dimensions.join(', ')} CONSTRAINTS: Focus on ${dimensions.join(', ')} | Do NOT re-discover files — use provided file list
" --tool gemini --mode analysis`, " --tool gemini --mode analysis`,
run_in_background: true run_in_background: true
}) })
// STOP: Wait for hook callback before continuing // STOP: Wait for hook callback before continuing
// Multi-perspective: Same pattern per perspective with perspective.purpose/tasks/constraints/tool }
``` ```
**Step 3: Aggregate Findings** **Step 3: Aggregate Findings**
- Consolidate explorations + CLI results - Consolidate explorations + CLI results + research findings (if research.json exists)
- Merge research best_practices[] and pitfalls[] into discussion points
- Cross-reference: flag gaps where codebase patterns diverge from research best practices
- Multi: Extract synthesis (convergent themes, conflicting views, unique contributions) - Multi: Extract synthesis (convergent themes, conflicting views, unique contributions)
- Write to `explorations.json` (single) or `perspectives.json` (multi) - Write to `explorations.json` (single) or `perspectives.json` (multi)
- If research.json exists, add `external_research` section to explorations/perspectives with: key findings, best practices, codebase gaps
**Step 4: Update discussion.md** — Append Round 1 with sources, key findings, discussion points, open questions **Step 4: Update discussion.md** — Append Round 1 with sources, key findings, discussion points, open questions
@@ -243,18 +325,36 @@ CONSTRAINTS: Focus on ${dimensions.join(', ')}
- Present to user at beginning of Phase 3: "初始探索完成后,以下意图的覆盖情况:[list]。接下来的讨论将重点关注未覆盖的部分。" - Present to user at beginning of Phase 3: "初始探索完成后,以下意图的覆盖情况:[list]。接下来的讨论将重点关注未覆盖的部分。"
- Purpose: Early course correction — catch drift before spending multiple interactive rounds - Purpose: Early course correction — catch drift before spending multiple interactive rounds
**explorations.json Schema** (single): **exploration-codebase.json Schema** (shared Layer 1):
- `session_id`, `timestamp`, `topic`, `dimensions[]`
- `relevant_files[]`: {path, annotation, dimensions[]}
- `patterns[]`, `module_map`: {}
- `questions_for_user[]`, `_metadata`
**research.json Schema** (external research findings):
- `topic`, `mode` (detail-verification|api-research|design-research), `timestamp`
- `findings[]`: {finding, detail, confidence, source_url}
- `best_practices[]`: {practice, rationale, source}
- `alternatives[]`: {option, pros, cons, verdict}
- `pitfalls[]`: {issue, mitigation, source}
- `codebase_gaps[]`: {gap, current_approach, recommended_approach}
- `sources[]`: {title, url, key_takeaway}
- `_metadata`: {queries_executed, results_found}
**explorations.json Schema** (single — Layer 1 + CLI analysis + research merged):
- `session_id`, `timestamp`, `topic`, `dimensions[]` - `session_id`, `timestamp`, `topic`, `dimensions[]`
- `sources[]`: {type, file/summary} - `sources[]`: {type, file/summary}
- `key_findings[]`, `code_anchors[]`: {file, lines, snippet, significance} - `key_findings[]`, `code_anchors[]`: {file, lines, snippet, significance}
- `call_chains[]`: {entry, chain, files} - `call_chains[]`: {entry, chain, files}
- `discussion_points[]`, `open_questions[]` - `discussion_points[]`, `open_questions[]`
- `technical_solutions[]`: {round, solution, problem, rationale, alternatives, status: proposed|validated|rejected, evidence_refs[], next_action} - `technical_solutions[]`: {round, solution, problem, rationale, alternatives, status: proposed|validated|rejected, evidence_refs[], next_action}
- `external_research`: {findings[], best_practices[], codebase_gaps[], sources[]} — merged from research.json if available
**perspectives.json Schema** (multi — extends explorations.json): **perspectives.json Schema** (multi — Layer 1 shared + per-perspective Layer 2-3 + research):
- `perspectives[]`: [{name, tool, findings, insights, questions}] - `shared_discovery`: {relevant_files[], patterns[], module_map}
- `perspectives[]`: [{name, tool, findings, insights, questions, code_anchors[], call_chains[]}]
- `external_research`: {findings[], best_practices[], codebase_gaps[], sources[]} — merged from research.json if available
- `synthesis`: {convergent_themes, conflicting_views, unique_contributions} - `synthesis`: {convergent_themes, conflicting_views, unique_contributions}
- code_anchors/call_chains include `perspective` field
| Condition | Action | | Condition | Action |
|-----------|--------| |-----------|--------|
@@ -270,6 +370,22 @@ CONSTRAINTS: Focus on ${dimensions.join(', ')}
**Guideline**: Delegate complex tasks to agents (cli-explore-agent) or CLI calls. Avoid direct analysis in main process. **Guideline**: Delegate complex tasks to agents (cli-explore-agent) or CLI calls. Avoid direct analysis in main process.
**Cumulative Context Rule**: Every agent/CLI call in Phase 3 MUST include a summary of ALL prior exploration results to avoid re-discovering known information. Build `priorContext` before each call:
```javascript
// Build cumulative context from all prior explorations (Phase 2 + previous rounds)
const allFindings = readJSON(`${sessionFolder}/explorations.json`) // or perspectives.json
const priorContext = `
## KNOWN FINDINGS (DO NOT re-discover)
- Established files: ${allFindings.sources.map(s => s.file).join(', ')}
- Key findings: ${allFindings.key_findings.join('; ')}
- Code anchors: ${allFindings.code_anchors.slice(0,5).map(a => `${a.file}:${a.lines}`).join(', ')}
- Call chains: ${allFindings.call_chains.slice(0,3).map(c => c.entry).join(', ')}
- Open questions: ${allFindings.open_questions.join('; ')}
## NEW TASK: Focus ONLY on unexplored areas below.
`
```
**Loop** (max 5 rounds): **Loop** (max 5 rounds):
1. **Current Understanding Summary** (Round >= 2, BEFORE presenting new findings): 1. **Current Understanding Summary** (Round >= 2, BEFORE presenting new findings):
@@ -280,8 +396,8 @@ CONSTRAINTS: Focus on ${dimensions.join(', ')}
3. **Gather Feedback** (AskUserQuestion, single-select, header: "分析反馈"): 3. **Gather Feedback** (AskUserQuestion, single-select, header: "分析反馈"):
- **继续深入**: Direction correct — deepen automatically or user specifies direction (combines agree+deepen and agree+suggest) - **继续深入**: Direction correct — deepen automatically or user specifies direction (combines agree+deepen and agree+suggest)
- **外部研究**: Need external research on specific technology/pattern/best practice (spawns workflow-research-agent)
- **调整方向**: Different focus or specific questions to address - **调整方向**: Different focus or specific questions to address
- **补充信息**: User has additional context, constraints, or corrections to provide
- **分析完成**: Sufficient -> exit to Phase 4 - **分析完成**: Sufficient -> exit to Phase 4
4. **Process Response** (always record user choice + impact to discussion.md): 4. **Process Response** (always record user choice + impact to discussion.md):
@@ -293,9 +409,14 @@ CONSTRAINTS: Focus on ${dimensions.join(', ')}
- **"Other" is auto-provided** by AskUserQuestion — covers user-specified custom direction (no need for separate "suggest next step" option) - **"Other" is auto-provided** by AskUserQuestion — covers user-specified custom direction (no need for separate "suggest next step" option)
- Execute selected direction -> merge new code_anchors/call_chains -> record confirmed assumptions + deepen angle - Execute selected direction -> merge new code_anchors/call_chains -> record confirmed assumptions + deepen angle
**调整方向** -> AskUserQuestion (header: "新方向", user selects or provides custom via "Other") -> new CLI exploration -> Record Decision (old vs new direction, reason, impact) **外部研究** -> Spawn workflow-research-agent for targeted research:
- AskUserQuestion (header: "研究主题", freetext via "Other"): What specific technology/pattern/approach needs external research?
- Spawn research agent with topic + current codebase context (from explorations.json)
- Merge research findings into explorations.json `external_research` section
- Update research.json with new findings (append, don't overwrite)
- Record research findings as Key Findings in discussion.md
**补充信息** -> Capture user input, integrate into context, answer questions via CLI/analysis if needed -> Record corrections/additions + updated understanding **调整方向** -> AskUserQuestion (header: "新方向", user selects or provides custom via "Other") -> new CLI exploration -> Record Decision (old vs new direction, reason, impact)
**分析完成** -> Exit loop -> Record why concluding **分析完成** -> Exit loop -> Record why concluding
@@ -525,6 +646,8 @@ ${implScope.map((item, i) => `${i+1}. **${item.objective}** [${item.priority}]
| E005 | error | No relevant findings from exploration — broaden search, ask user for clarification | cli_exploration | | E005 | error | No relevant findings from exploration — broaden search, ask user for clarification | cli_exploration |
| E006 | warning | Session folder conflict — append timestamp suffix | session_init | | E006 | warning | Session folder conflict — append timestamp suffix | session_init |
| E007 | error | Gemini unavailable — fallback to Codex or manual analysis | cli_exploration | | E007 | error | Gemini unavailable — fallback to Codex or manual analysis | cli_exploration |
| E008 | warning | Research agent WebSearch failed — continue with codebase-only analysis, note limitation | cli_exploration |
| E009 | warning | Research findings conflict with codebase patterns — flag as codebase_gaps for user review | cli_exploration |
</error_codes> </error_codes>
@@ -534,6 +657,8 @@ ${implScope.map((item, i) => `${i+1}. **${item.objective}** [${item.priority}]
- [ ] Dimensions identified and user preferences captured (Phase 1) - [ ] Dimensions identified and user preferences captured (Phase 1)
- [ ] discussion.md initialized with TOC, Current Understanding, metadata - [ ] discussion.md initialized with TOC, Current Understanding, metadata
- [ ] Codebase exploration completed with code_anchors and call_chains (Phase 2) - [ ] Codebase exploration completed with code_anchors and call_chains (Phase 2)
- [ ] External research executed if topic warrants it (architecture/comparison/decision/performance/security dimensions)
- [ ] Research findings merged into explorations/perspectives with codebase_gaps flagged
- [ ] CLI analysis executed and findings aggregated - [ ] CLI analysis executed and findings aggregated
- [ ] Initial Intent Coverage Check appended to discussion.md - [ ] Initial Intent Coverage Check appended to discussion.md
- [ ] Interactive discussion rounds documented with narrative synthesis (Phase 3) - [ ] Interactive discussion rounds documented with narrative synthesis (Phase 3)

View File

@@ -74,7 +74,7 @@ function selectExecutionOptions() {
const autoYes = workflowPreferences?.autoYes ?? false const autoYes = workflowPreferences?.autoYes ?? false
if (autoYes) { if (autoYes) {
return { execution_method: "Auto", code_review_tool: "Skip" } return { execution_method: "Auto", code_review_tool: "Skip", convergence_review_tool: "Skip" }
} }
return AskUserQuestion({ return AskUserQuestion({
@@ -90,14 +90,25 @@ function selectExecutionOptions() {
] ]
}, },
{ {
question: "Review tool for test-review phase?", question: "Code review after execution? (runs here in lite-execute)",
header: "Review Tool (passed to lite-test-review)", header: "Code Review",
multiSelect: false, multiSelect: false,
options: [ options: [
{ label: "Agent Review", description: "Agent review in test-review (default)" }, { label: "Gemini Review", description: "Gemini CLI: git diff quality review" },
{ label: "Gemini Review", description: "Gemini CLI in test-review" }, { label: "Codex Review", description: "Codex CLI: git-aware code review (--mode review)" },
{ label: "Codex Review", description: "Codex CLI in test-review" }, { label: "Agent Review", description: "@code-reviewer agent" },
{ label: "Skip", description: "Skip review in test-review" } { label: "Skip", description: "No code review" }
]
},
{
question: "Convergence review in test-review phase?",
header: "Convergence Review",
multiSelect: false,
options: [
{ label: "Agent", description: "Agent: verify convergence criteria" },
{ label: "Gemini", description: "Gemini CLI: convergence verification" },
{ label: "Codex", description: "Codex CLI: convergence verification" },
{ label: "Skip", description: "Skip convergence review, run tests only" }
] ]
} }
] ]
@@ -117,7 +128,8 @@ if (executionContext) {
console.log(` console.log(`
Execution Strategy (from lite-plan): Execution Strategy (from lite-plan):
Method: ${executionContext.executionMethod} Method: ${executionContext.executionMethod}
Review: ${executionContext.codeReviewTool} Code Review: ${executionContext.codeReviewTool}
Convergence Review: ${executionContext.convergenceReviewTool}
Tasks: ${getTasks(executionContext.planObject).length} Tasks: ${getTasks(executionContext.planObject).length}
Complexity: ${executionContext.planObject.complexity} Complexity: ${executionContext.planObject.complexity}
${executionContext.executorAssignments ? ` Assignments: ${JSON.stringify(executionContext.executorAssignments)}` : ''} ${executionContext.executorAssignments ? ` Assignments: ${JSON.stringify(executionContext.executorAssignments)}` : ''}
@@ -367,18 +379,97 @@ ${(t.test?.success_metrics || []).length > 0 ? `**Success metrics**: ${t.test.su
} }
``` ```
### Step 4: Chain to Test Review & Post-Completion ### Step 4: Code Review
> **Note**: Spec sync (session:sync) is handled by lite-test-review's TR-Phase 5, not here. This avoids duplicate sync and ensures test fix changes are also captured. **Skip if**: `codeReviewTool === 'Skip'`
**Map review tool**: Convert lite-execute's `codeReviewTool` to test-review tool name. **Resolve review tool**: From `executionContext.codeReviewTool` (Mode 1) or `userSelection.code_review_tool` (Mode 2/3).
```javascript ```javascript
function mapReviewTool(codeReviewTool) { const codeReviewTool = executionContext?.codeReviewTool || userSelection?.code_review_tool || 'Skip'
const resolvedTool = (() => {
if (!codeReviewTool || codeReviewTool === 'Skip') return 'skip' if (!codeReviewTool || codeReviewTool === 'Skip') return 'skip'
if (/gemini/i.test(codeReviewTool)) return 'gemini' if (/gemini/i.test(codeReviewTool)) return 'gemini'
if (/codex/i.test(codeReviewTool)) return 'codex' if (/codex/i.test(codeReviewTool)) return 'codex'
return 'agent' return 'agent'
})()
if (resolvedTool === 'skip') {
console.log('[Code Review] Skipped')
} else {
// proceed with review
}
```
**Agent Code Review** (resolvedTool === 'agent'):
```javascript
Agent({
subagent_type: "code-reviewer",
run_in_background: false,
description: `Code review: ${planObject.summary}`,
prompt: `## Code Review — Post-Execution Quality Check
**Goal**: ${originalUserInput}
**Plan Summary**: ${planObject.summary}
### Changed Files
Run \`git diff --name-only HEAD~${getTasks(planObject).length}..HEAD\` to identify changes.
### Review Focus
1. **Code quality**: Readability, naming, structure, dead code
2. **Correctness**: Logic errors, off-by-one, null handling, edge cases
3. **Patterns**: Consistency with existing codebase conventions
4. **Security**: Injection, XSS, auth bypass, secrets exposure
5. **Performance**: Unnecessary loops, N+1 queries, missing indexes
### Instructions
1. Run git diff to see actual changes
2. Read changed files for full context
3. For each issue found: severity (Critical/High/Medium/Low) + file:line + description + fix suggestion
4. Return structured review: issues[], summary, overall verdict (PASS/WARN/FAIL)`
})
```
**CLI Code Review — Codex** (resolvedTool === 'codex'):
```javascript
const reviewId = `${sessionId}-code-review`
Bash(`ccw cli -p "Review code changes for quality, correctness, security, and pattern compliance. Focus: ${planObject.summary}" --tool codex --mode review --id ${reviewId}`, { run_in_background: true })
// STOP - wait for hook callback
```
**CLI Code Review — Gemini** (resolvedTool === 'gemini'):
```javascript
const reviewId = `${sessionId}-code-review`
Bash(`ccw cli -p "PURPOSE: Post-execution code quality review for: ${planObject.summary}
TASK: • Run git diff to identify all changes • Review each changed file for quality, correctness, security • Check pattern compliance with existing codebase • Identify potential bugs, edge cases, performance issues
MODE: analysis
CONTEXT: @**/* | Memory: lite-execute completed, reviewing code quality
EXPECTED: Per-file review with severity levels (Critical/High/Medium/Low), file:line references, fix suggestions, overall verdict
CONSTRAINTS: Read-only | Focus on code quality not convergence" --tool gemini --mode analysis --rule analysis-review-code-quality --id ${reviewId}`, { run_in_background: true })
// STOP - wait for hook callback
```
**Write review artifact** (if session folder exists):
```javascript
if (executionContext?.session?.folder) {
Write(`${executionContext.session.folder}/code-review.md`, codeReviewOutput)
}
```
### Step 5: Chain to Test Review & Post-Completion
**Resolve convergence review tool**: From `executionContext.convergenceReviewTool` (Mode 1) or `userSelection.convergence_review_tool` (Mode 2/3).
```javascript
function resolveConvergenceTool(ctx, selection) {
const raw = ctx?.convergenceReviewTool || selection?.convergence_review_tool || 'skip'
if (!raw || raw === 'Skip') return 'skip'
if (/gemini/i.test(raw)) return 'gemini'
if (/codex/i.test(raw)) return 'codex'
return 'agent'
} }
``` ```
@@ -389,7 +480,7 @@ testReviewContext = {
planObject: planObject, planObject: planObject,
taskFiles: executionContext?.taskFiles taskFiles: executionContext?.taskFiles
|| getTasks(planObject).map(t => ({ id: t.id, path: `${executionContext?.session?.folder}/.task/${t.id}.json` })), || getTasks(planObject).map(t => ({ id: t.id, path: `${executionContext?.session?.folder}/.task/${t.id}.json` })),
reviewTool: mapReviewTool(executionContext?.codeReviewTool), convergenceReviewTool: resolveConvergenceTool(executionContext, userSelection),
executionResults: previousExecutionResults, executionResults: previousExecutionResults,
originalUserInput: originalUserInput, originalUserInput: originalUserInput,
session: executionContext?.session || { session: executionContext?.session || {
@@ -442,7 +533,8 @@ Skill("lite-test-review")
explorationManifest: {...} | null, explorationManifest: {...} | null,
clarificationContext: {...} | null, clarificationContext: {...} | null,
executionMethod: "Agent" | "Codex" | "Auto", executionMethod: "Agent" | "Codex" | "Auto",
codeReviewTool: "Skip" | "Gemini Review" | "Agent Review" | string, codeReviewTool: "Skip" | "Gemini Review" | "Codex Review" | "Agent Review",
convergenceReviewTool: "Skip" | "Agent" | "Gemini" | "Codex",
originalUserInput: string, originalUserInput: string,
executorAssignments: { // per-task override, priority over executionMethod executorAssignments: { // per-task override, priority over executionMethod
[taskId]: { executor: "gemini" | "codex" | "agent", reason: string } [taskId]: { executor: "gemini" | "codex" | "agent", reason: string }

View File

@@ -40,7 +40,7 @@ Produces exploration results, a structured plan (plan.json), independent task fi
**Output Directory**: `.workflow/.lite-plan/{task-slug}-{YYYY-MM-DD}/` **Output Directory**: `.workflow/.lite-plan/{task-slug}-{YYYY-MM-DD}/`
**Agent Usage**: Low → Direct Claude planning (no agent) | Medium/High`cli-lite-planning-agent` **Agent Usage**: All complexities`cli-lite-planning-agent`
**Schema Reference**: `~/.ccw/workflows/cli-templates/schemas/plan-overview-base-schema.json` **Schema Reference**: `~/.ccw/workflows/cli-templates/schemas/plan-overview-base-schema.json`
@@ -51,7 +51,7 @@ Produces exploration results, a structured plan (plan.json), independent task fi
| LP-0 | Initialize workflowPreferences | autoYes, forceExplore | | LP-0 | Initialize workflowPreferences | autoYes, forceExplore |
| LP-1 | Complexity assessment → parallel cli-explore-agents (1-4) | exploration-*.json + manifest | | LP-1 | Complexity assessment → parallel cli-explore-agents (1-4) | exploration-*.json + manifest |
| LP-2 | Aggregate + dedup clarification_needs → multi-round AskUserQuestion | clarificationContext (in-memory) | | LP-2 | Aggregate + dedup clarification_needs → multi-round AskUserQuestion | clarificationContext (in-memory) |
| LP-3 | Low: Direct Claude planning / Medium+High: cli-lite-planning-agent | plan.json + .task/TASK-*.json | | LP-3 | cli-lite-planning-agent | plan.json + .task/TASK-*.json |
| LP-4 | Display plan → AskUserQuestion (Confirm + Execution + Review) | userSelection | | LP-4 | Display plan → AskUserQuestion (Confirm + Execution + Review) | userSelection |
| LP-5 | Build executionContext → Skill("lite-execute") | handoff (Mode 1) | | LP-5 | Build executionContext → Skill("lite-execute") | handoff (Mode 1) |
@@ -85,7 +85,7 @@ bash(`mkdir -p ${sessionFolder} && test -d ${sessionFolder} && echo "SUCCESS: ${
TodoWrite({ todos: [ TodoWrite({ todos: [
{ content: `LP-Phase 1: Exploration [${complexity}] ${selectedAngles.length} angles`, status: "in_progress", activeForm: `Exploring: ${selectedAngles.join(', ')}` }, { content: `LP-Phase 1: Exploration [${complexity}] ${selectedAngles.length} angles`, status: "in_progress", activeForm: `Exploring: ${selectedAngles.join(', ')}` },
{ content: "LP-Phase 2: Clarification", status: "pending" }, { content: "LP-Phase 2: Clarification", status: "pending" },
{ content: `LP-Phase 3: Planning [${planningStrategy}]`, status: "pending" }, { content: "LP-Phase 3: Planning [cli-lite-planning-agent]", status: "pending" },
{ content: "LP-Phase 4: Confirmation", status: "pending" }, { content: "LP-Phase 4: Confirmation", status: "pending" },
{ content: "LP-Phase 5: Execution", status: "pending" } { content: "LP-Phase 5: Execution", status: "pending" }
]}) ]})
@@ -154,12 +154,7 @@ function selectAngles(taskDescription, count) {
const selectedAngles = selectAngles(task_description, complexity === 'High' ? 4 : (complexity === 'Medium' ? 3 : 1)) const selectedAngles = selectAngles(task_description, complexity === 'High' ? 4 : (complexity === 'Medium' ? 3 : 1))
// Direct Claude planning ONLY for: Low + no prior analysis + single angle console.log(`Exploration Plan: ${complexity} | ${selectedAngles.join(', ')} | cli-lite-planning-agent`)
const planningStrategy = (
complexity === 'Low' && !hasPriorAnalysis && selectedAngles.length <= 1
) ? 'Direct Claude Planning' : 'cli-lite-planning-agent'
console.log(`Exploration Plan: ${complexity} | ${selectedAngles.join(', ')} | ${planningStrategy}`)
``` ```
**Launch Parallel Explorations**: **Launch Parallel Explorations**:
@@ -328,56 +323,7 @@ taskFiles.forEach(taskPath => {
}) })
``` ```
**Low Complexity** — Direct planning by Claude: **Invoke cli-lite-planning-agent**:
```javascript
const schema = Bash(`cat ~/.ccw/workflows/cli-templates/schemas/plan-overview-base-schema.json`)
const manifest = file_exists(`${sessionFolder}/explorations-manifest.json`)
? JSON.parse(Read(`${sessionFolder}/explorations-manifest.json`))
: { explorations: [] }
manifest.explorations.forEach(exp => {
console.log(`\n### Exploration: ${exp.angle}\n${Read(exp.path)}`)
})
// When handoffSpec exists, use it as primary planning input
// implementation_scope[].acceptance_criteria -> convergence.criteria
// implementation_scope[].target_files -> files[]
// implementation_scope[].objective -> task title/description
if (handoffSpec) {
console.log(`\n### Handoff Spec from ${handoffSpec.source}`)
console.log(`Scope items: ${handoffSpec.implementation_scope.length}`)
handoffSpec.implementation_scope.forEach((item, i) => {
console.log(` ${i+1}. ${item.objective} [${item.priority}] — Done when: ${item.acceptance_criteria.join('; ')}`)
})
}
// Generate tasks — MUST incorporate exploration insights OR handoff spec
// When handoffSpec: map implementation_scope[] → tasks[] (1:1 or group by context)
// Field names: convergence.criteria (not acceptance), files[].change (not modification_points), test (not verification)
const tasks = [
{
id: "TASK-001", title: "...", description: "...", depends_on: [],
convergence: { criteria: ["..."] }, // From handoffSpec: item.acceptance_criteria
files: [{ path: "...", change: "..." }], // From handoffSpec: item.target_files + item.change_summary
implementation: ["..."], test: "..."
}
]
const taskDir = `${sessionFolder}/.task`
Bash(`mkdir -p "${taskDir}"`)
tasks.forEach(task => Write(`${taskDir}/${task.id}.json`, JSON.stringify(task, null, 2)))
const plan = {
summary: "...", approach: "...",
task_ids: tasks.map(t => t.id), task_count: tasks.length,
complexity: "Low", estimated_time: "...", recommended_execution: "Agent",
_metadata: { timestamp: getUtc8ISOString(), source: "direct-planning", planning_mode: "direct", plan_type: "feature" }
}
Write(`${sessionFolder}/plan.json`, JSON.stringify(plan, null, 2))
// MUST continue to LP-Phase 4 — DO NOT execute code here
```
**Medium/High Complexity** — Invoke cli-lite-planning-agent:
```javascript ```javascript
Task( Task(
@@ -492,8 +438,8 @@ ${tasks.map((t, i) => `${i+1}. ${t.title} (${t.scope || t.files?.[0]?.path || ''
let userSelection let userSelection
if (workflowPreferences.autoYes) { if (workflowPreferences.autoYes) {
console.log(`[Auto] Allow & Execute | Auto | Skip`) console.log(`[Auto] Allow & Execute | Auto | Skip + Skip`)
userSelection = { confirmation: "Allow", execution_method: "Auto", code_review_tool: "Skip" } userSelection = { confirmation: "Allow", execution_method: "Auto", code_review_tool: "Skip", convergence_review_tool: "Skip" }
} else { } else {
// "Other" in Execution allows specifying CLI tools from ~/.claude/cli-tools.json // "Other" in Execution allows specifying CLI tools from ~/.claude/cli-tools.json
userSelection = AskUserQuestion({ userSelection = AskUserQuestion({
@@ -519,14 +465,25 @@ if (workflowPreferences.autoYes) {
] ]
}, },
{ {
question: "Code review after execution?", question: "Code review after execution? (runs in lite-execute)",
header: "Review", header: "Code Review",
multiSelect: false, multiSelect: false,
options: [ options: [
{ label: "Gemini Review", description: "Gemini CLI review" }, { label: "Gemini Review", description: "Gemini CLI: git diff quality review" },
{ label: "Codex Review", description: "Git-aware review (prompt OR --uncommitted)" }, { label: "Codex Review", description: "Codex CLI: git-aware code review (--mode review)" },
{ label: "Agent Review", description: "@code-reviewer agent" }, { label: "Agent Review", description: "@code-reviewer agent" },
{ label: "Skip", description: "No review" } { label: "Skip", description: "No code review" }
]
},
{
question: "Convergence review in test-review phase?",
header: "Convergence Review",
multiSelect: false,
options: [
{ label: "Agent", description: "Agent: verify convergence criteria against implementation" },
{ label: "Gemini", description: "Gemini CLI: convergence verification" },
{ label: "Codex", description: "Codex CLI: convergence verification" },
{ label: "Skip", description: "Skip convergence review, run tests only" }
] ]
} }
] ]
@@ -534,7 +491,7 @@ if (workflowPreferences.autoYes) {
} }
``` ```
// TodoWrite: Phase 4 → completed `[${userSelection.execution_method} + ${userSelection.code_review_tool}]`, Phase 5 → in_progress // TodoWrite: Phase 4 → completed `[${userSelection.execution_method} | CR:${userSelection.code_review_tool} | CVR:${userSelection.convergence_review_tool}]`, Phase 5 → in_progress
## 10. LP-Phase 5: Handoff to Execution ## 10. LP-Phase 5: Handoff to Execution
@@ -561,6 +518,7 @@ executionContext = {
clarificationContext: clarificationContext || null, clarificationContext: clarificationContext || null,
executionMethod: userSelection.execution_method, executionMethod: userSelection.execution_method,
codeReviewTool: userSelection.code_review_tool, codeReviewTool: userSelection.code_review_tool,
convergenceReviewTool: userSelection.convergence_review_tool,
originalUserInput: task_description, originalUserInput: task_description,
executorAssignments: executorAssignments, // { taskId: { executor, reason } } — overrides executionMethod executorAssignments: executorAssignments, // { taskId: { executor, reason } } — overrides executionMethod
session: { session: {
@@ -588,7 +546,7 @@ TodoWrite({ todos: [
{ content: "LP-Phase 1: Exploration", status: "completed" }, { content: "LP-Phase 1: Exploration", status: "completed" },
{ content: "LP-Phase 2: Clarification", status: "completed" }, { content: "LP-Phase 2: Clarification", status: "completed" },
{ content: "LP-Phase 3: Planning", status: "completed" }, { content: "LP-Phase 3: Planning", status: "completed" },
{ content: `LP-Phase 4: Confirmed [${userSelection.execution_method}]`, status: "completed" }, { content: `LP-Phase 4: Confirmed [${userSelection.execution_method} | CR:${userSelection.code_review_tool} | CVR:${userSelection.convergence_review_tool}]`, status: "completed" },
{ content: `LP-Phase 5: Handoff → lite-execute`, status: "completed" }, { content: `LP-Phase 5: Handoff → lite-execute`, status: "completed" },
{ content: `LE-Phase 1: Task Loading [${taskCount} tasks]`, status: "in_progress", activeForm: "Loading tasks" } { content: `LE-Phase 1: Task Loading [${taskCount} tasks]`, status: "in_progress", activeForm: "Loading tasks" }
]}) ]})
@@ -605,6 +563,7 @@ Skill("lite-execute")
├── explorations-manifest.json # Exploration index ├── explorations-manifest.json # Exploration index
├── planning-context.md # Evidence paths + understanding ├── planning-context.md # Evidence paths + understanding
├── plan.json # Plan overview (task_ids[]) ├── plan.json # Plan overview (task_ids[])
├── code-review.md # Generated by lite-execute Step 4
├── test-checklist.json # Generated by lite-test-review ├── test-checklist.json # Generated by lite-test-review
├── test-review.md # Generated by lite-test-review ├── test-review.md # Generated by lite-test-review
└── .task/ └── .task/
@@ -618,9 +577,12 @@ Skill("lite-execute")
``` ```
lite-plan (LP-Phase 1-5) lite-plan (LP-Phase 1-5)
└─ Skill("lite-execute") ← executionContext (global) └─ Skill("lite-execute") ← executionContext (global)
├─ Step 1-4: Execute + Review ├─ Step 1-3: Task Execution
├─ Step 4: Code Review (quality/correctness/security)
└─ Step 5: Skill("lite-test-review") ← testReviewContext (global) └─ Step 5: Skill("lite-test-review") ← testReviewContext (global)
├─ TR-Phase 1-4: Test + Fix ├─ TR-Phase 1: Detect test framework
├─ TR-Phase 2: Convergence verification (plan criteria)
├─ TR-Phase 3-4: Run tests + Auto-fix
└─ TR-Phase 5: Report + Sync specs └─ TR-Phase 5: Report + Sync specs
``` ```
@@ -629,7 +591,7 @@ lite-plan (LP-Phase 1-5)
| Error | Resolution | | Error | Resolution |
|-------|------------| |-------|------------|
| Exploration agent failure | Skip exploration, continue with task description only | | Exploration agent failure | Skip exploration, continue with task description only |
| Planning agent failure | Fallback to direct planning by Claude | | Planning agent failure | Retry with reduced complexity or suggest breaking task |
| Clarification timeout | Use exploration findings as-is | | Clarification timeout | Use exploration findings as-is |
| Confirmation timeout | Save context, display resume instructions | | Confirmation timeout | Save context, display resume instructions |
| Modify loop > 3 times | Suggest breaking task or using /workflow-plan | | Modify loop > 3 times | Suggest breaking task or using /workflow-plan |
@@ -649,7 +611,7 @@ Auto mode authorizes the complete plan-and-execute workflow with a single confir
- [ ] Parallel exploration agents launched with run_in_background=false - [ ] Parallel exploration agents launched with run_in_background=false
- [ ] Explorations manifest built from auto-discovered files - [ ] Explorations manifest built from auto-discovered files
- [ ] Clarification needs aggregated, deduped, and presented in batches of 4 - [ ] Clarification needs aggregated, deduped, and presented in batches of 4
- [ ] Plan generated via direct Claude (Low) or cli-lite-planning-agent (Medium/High) - [ ] Plan generated via cli-lite-planning-agent
- [ ] Plan output as two-layer: plan.json (task_ids[]) + .task/TASK-*.json - [ ] Plan output as two-layer: plan.json (task_ids[]) + .task/TASK-*.json
- [ ] User confirmation collected (or auto-approved in auto mode) - [ ] User confirmation collected (or auto-approved in auto mode)
- [ ] executionContext fully built with all artifacts and session references - [ ] executionContext fully built with all artifacts and session references

View File

@@ -31,31 +31,31 @@ Test review and fix engine for lite-execute chain or standalone invocation.
**Input Source**: `testReviewContext` global variable set by lite-execute Step 4 **Input Source**: `testReviewContext` global variable set by lite-execute Step 4
**Behavior**: Skip session discovery, inherit reviewTool from execution chain, proceed directly to TR-Phase 1. **Behavior**: Skip session discovery, inherit convergenceReviewTool from execution chain, proceed directly to TR-Phase 1.
> **Note**: lite-execute Step 4 is the chain gate. Mode 1 invocation means execution is complete — proceed with test review. > **Note**: lite-execute Step 5 is the chain gate. Mode 1 invocation means execution + code review are complete — proceed with convergence verification + tests.
### Mode 2: Standalone ### Mode 2: Standalone
**Trigger**: User calls with session path or `--last` **Trigger**: User calls with session path or `--last`
**Behavior**: Discover session → load plan + tasks → `reviewTool = 'agent'` → proceed to TR-Phase 1. **Behavior**: Discover session → load plan + tasks → `convergenceReviewTool = 'agent'` → proceed to TR-Phase 1.
```javascript ```javascript
let sessionPath, plan, taskFiles, reviewTool let sessionPath, plan, taskFiles, convergenceReviewTool
if (testReviewContext) { if (testReviewContext) {
// Mode 1: from lite-execute chain // Mode 1: from lite-execute chain
sessionPath = testReviewContext.session.folder sessionPath = testReviewContext.session.folder
plan = testReviewContext.planObject plan = testReviewContext.planObject
taskFiles = testReviewContext.taskFiles.map(tf => JSON.parse(Read(tf.path))) taskFiles = testReviewContext.taskFiles.map(tf => JSON.parse(Read(tf.path)))
reviewTool = testReviewContext.reviewTool || 'agent' convergenceReviewTool = testReviewContext.convergenceReviewTool || 'agent'
} else { } else {
// Mode 2: standalone — find last session or use provided path // Mode 2: standalone — find last session or use provided path
sessionPath = resolveSessionPath($ARGUMENTS) // Glob('.workflow/.lite-plan/*/plan.json'), take last sessionPath = resolveSessionPath($ARGUMENTS) // Glob('.workflow/.lite-plan/*/plan.json'), take last
plan = JSON.parse(Read(`${sessionPath}/plan.json`)) plan = JSON.parse(Read(`${sessionPath}/plan.json`))
taskFiles = plan.task_ids.map(id => JSON.parse(Read(`${sessionPath}/.task/${id}.json`))) taskFiles = plan.task_ids.map(id => JSON.parse(Read(`${sessionPath}/.task/${id}.json`)))
reviewTool = 'agent' convergenceReviewTool = 'agent'
} }
const skipFix = $ARGUMENTS?.includes('--skip-fix') || false const skipFix = $ARGUMENTS?.includes('--skip-fix') || false
@@ -66,7 +66,7 @@ const skipFix = $ARGUMENTS?.includes('--skip-fix') || false
| Phase | Core Action | Output | | Phase | Core Action | Output |
|-------|-------------|--------| |-------|-------------|--------|
| TR-Phase 1 | Detect test framework + gather changes | testConfig, changedFiles | | TR-Phase 1 | Detect test framework + gather changes | testConfig, changedFiles |
| TR-Phase 2 | Review implementation against convergence criteria | reviewResults[] | | TR-Phase 2 | Convergence verification against plan criteria | reviewResults[] |
| TR-Phase 3 | Run tests + generate checklist | test-checklist.json | | TR-Phase 3 | Run tests + generate checklist | test-checklist.json |
| TR-Phase 4 | Auto-fix failures (iterative, max 3 rounds) | Fixed code + updated checklist | | TR-Phase 4 | Auto-fix failures (iterative, max 3 rounds) | Fixed code + updated checklist |
| TR-Phase 5 | Output report + chain to session:sync | test-review.md | | TR-Phase 5 | Output report + chain to session:sync | test-review.md |
@@ -93,32 +93,45 @@ Output: `testConfig = { command, framework, type }` + `changedFiles[]`
// TodoWrite: Phase 1 → completed, Phase 2 → in_progress // TodoWrite: Phase 1 → completed, Phase 2 → in_progress
## TR-Phase 2: Review Implementation Against Plan ## TR-Phase 2: Convergence Verification
**Skip if**: `reviewTool === 'skip'` — set all tasks to PASS, proceed to Phase 3. **Skip if**: `convergenceReviewTool === 'skip'` — set all tasks to PASS, proceed to Phase 3.
For each task, verify convergence criteria and identify test gaps. Verify each task's convergence criteria are met in the implementation and identify test gaps.
**Agent Review** (reviewTool === 'agent', default): **Agent Convergence Review** (convergenceReviewTool === 'agent', default):
For each task in taskFiles: For each task in taskFiles:
1. Extract `convergence.criteria[]` and `test` requirements 1. Extract `convergence.criteria[]` from the task
2. Find changed files matching `task.files[].path` against `changedFiles` 2. Match `task.files[].path` against `changedFiles` to find actually-changed files
3. Read matched files, evaluate each criterion against implementation 3. Read each matched file, verify each convergence criterion with file:line evidence
4. Check test coverage: if `task.test.unit` exists but no test files in changedFiles → mark as test gap 4. Check test coverage gaps:
5. Same for `task.test.integration` - If `task.test.unit` defined but no matching test files in changedFiles → mark as test gap
6. Build `reviewResult = { taskId, title, criteria_met[], criteria_unmet[], test_gaps[], files_reviewed[] }` - If `task.test.integration` defined but no integration test in changedFiles → mark as test gap
5. Build `reviewResult = { taskId, title, criteria_met[], criteria_unmet[], test_gaps[], files_reviewed[] }`
**CLI Review** (reviewTool === 'gemini' or 'codex'): **Verdict logic**:
- PASS = all `convergence.criteria` met + no test gaps
- PARTIAL = some criteria met OR has test gaps
- FAIL = no criteria met
**CLI Convergence Review** (convergenceReviewTool === 'gemini' or 'codex'):
```javascript ```javascript
const reviewId = `${sessionId}-tr-review` const reviewId = `${sessionId}-convergence`
Bash(`ccw cli -p "PURPOSE: Post-execution test review — verify convergence criteria met and identify test gaps const taskCriteria = taskFiles.map(t => `${t.id}: [${(t.convergence?.criteria || []).join(' | ')}]`).join('\n')
TASK: • Read plan.json and .task/*.json convergence criteria • For each criterion, check implementation in changed files • Identify missing unit/integration tests • List unmet criteria with file:line evidence Bash(`ccw cli -p "PURPOSE: Convergence verification check each task's completion criteria against actual implementation
TASK: • For each task below, verify every convergence criterion is satisfied in the changed files • Mark each criterion as MET (with file:line evidence) or UNMET (with what's missing) • Identify test coverage gaps (planned tests not found in changes)
TASK CRITERIA:
${taskCriteria}
CHANGED FILES: ${changedFiles.join(', ')}
MODE: analysis MODE: analysis
CONTEXT: @${sessionPath}/plan.json @${sessionPath}/.task/*.json @**/* | Memory: lite-execute completed, reviewing convergence CONTEXT: @${sessionPath}/plan.json @${sessionPath}/.task/*.json @**/* | Memory: lite-execute completed
EXPECTED: Per-task verdict table (PASS/PARTIAL/FAIL) + unmet criteria list + test gap list EXPECTED: Per-task verdict (PASS/PARTIAL/FAIL) with per-criterion evidence + test gap list
CONSTRAINTS: Read-only | Focus on convergence verification" --tool ${reviewTool} --mode analysis --id ${reviewId}`, { run_in_background: true }) CONSTRAINTS: Read-only | Focus strictly on convergence criteria verification, NOT code quality (code review already done in lite-execute)" --tool ${convergenceReviewTool} --mode analysis --id ${reviewId}`, { run_in_background: true })
// STOP - wait for hook callback, then parse CLI output into reviewResults format // STOP - wait for hook callback, then parse CLI output into reviewResults format
``` ```
@@ -207,13 +220,13 @@ Skill({ skill: "workflow:session:sync", args: `-y "Test review: ${testChecklist.
## Data Structures ## Data Structures
### testReviewContext (Input - Mode 1, set by lite-execute) ### testReviewContext (Input - Mode 1, set by lite-execute Step 5)
```javascript ```javascript
{ {
planObject: { /* same as executionContext.planObject */ }, planObject: { /* same as executionContext.planObject */ },
taskFiles: [{ id: string, path: string }], taskFiles: [{ id: string, path: string }],
reviewTool: "skip" | "agent" | "gemini" | "codex", convergenceReviewTool: "skip" | "agent" | "gemini" | "codex",
executionResults: [...], executionResults: [...],
originalUserInput: string, originalUserInput: string,
session: { session: {

View File

@@ -1,495 +0,0 @@
---
name: workflow-tune
description: Workflow tuning skill for multi-command/skill pipelines. Executes each step sequentially, inspects artifacts after each command, analyzes quality via ccw cli resume, builds process documentation, and generates optimization suggestions. Triggers on "workflow tune", "tune workflow", "workflow optimization".
allowed-tools: Skill, Agent, AskUserQuestion, TaskCreate, TaskUpdate, TaskList, Read, Write, Edit, Bash, Glob, Grep
---
# Workflow Tune
Tune multi-step workflows composed of commands or skills. Execute each step, inspect artifacts, analyze via ccw cli resume, build process documentation, and produce actionable optimization suggestions.
## Architecture Overview
```
┌──────────────────────────────────────────────────────────────────────┐
│ Workflow Tune Orchestrator (SKILL.md) │
│ → Parse → Decompose → Confirm → Setup → Step Loop → Synthesize │
└──────────────────────┬───────────────────────────────────────────────┘
┌───────────────────┼───────────────────────────────────┐
↓ ↓ ↓
┌──────────┐ ┌─────────────────────────────┐ ┌──────────────┐
│ Phase 1 │ │ Step Loop (2→3 per step) │ │ Phase 4 + 5 │
│ Setup │ │ ┌─────┐ ┌─────┐ │ │ Synthesize + │
│ │──→│ │ P2 │→ │ P3 │ │────→│ Report │
│ Parse + │ │ │Exec │ │Anal │ │ │ │
│ Decomp + │ │ └─────┘ └─────┘ │ └──────────────┘
│ Confirm │ │ ↑ │ next step │
└──────────┘ │ └───────┘ │
└─────────────────────────────┘
Phase 1 Detail:
Input → [Format 1-3: direct parse] ──→ Command Doc → Confirm → Init
→ [Format 4: natural lang] ──→ Semantic Decompose → Command Doc → Confirm → Init
```
## Key Design Principles
1. **Test-First Evaluation**: Auto-generate per-step acceptance criteria before execution — judge results against concrete requirements, not vague quality
2. **Step-by-Step Execution**: Each workflow step executes independently, artifacts inspected before proceeding
3. **Resume-Based Analysis**: Uses ccw cli `--resume` to maintain analysis context across steps
4. **Process Documentation**: Running `process-log.md` accumulates observations per step
5. **Two-Tool Pipeline**: Claude/target tool (execute) + Gemini (analyze) = complementary perspectives
6. **Pure Orchestrator**: SKILL.md coordinates only — execution detail in phase files
7. **Progressive Phase Loading**: Phase docs read only when that phase executes
## Interactive Preference Collection
```javascript
// ★ Auto mode detection
const autoYes = /\b(-y|--yes)\b/.test($ARGUMENTS)
if (autoYes) {
workflowPreferences = {
autoYes: true,
analysisDepth: 'standard',
autoFix: false
}
} else {
const prefResponse = AskUserQuestion({
questions: [
{
question: "选择 Workflow 调优配置:",
header: "Tune Config",
multiSelect: false,
options: [
{ label: "Quick (轻量分析)", description: "每步简要检查,快速产出建议" },
{ label: "Standard (标准分析) (Recommended)", description: "每步详细分析,完整过程文档" },
{ label: "Deep (深度分析)", description: "每步深度审查,含性能和架构建议" }
]
},
{
question: "是否自动应用优化建议?",
header: "Auto Fix",
multiSelect: false,
options: [
{ label: "No (仅生成报告) (Recommended)", description: "只分析,不修改" },
{ label: "Yes (自动应用)", description: "分析后自动应用高优先级建议" }
]
}
]
})
const depthMap = {
"Quick": "quick",
"Standard": "standard",
"Deep": "deep"
}
const selectedDepth = Object.keys(depthMap).find(k =>
prefResponse["Tune Config"].startsWith(k)
) || "Standard"
workflowPreferences = {
autoYes: false,
analysisDepth: depthMap[selectedDepth],
autoFix: prefResponse["Auto Fix"].startsWith("Yes")
}
}
```
## Input Processing
```
$ARGUMENTS → Parse:
├─ Workflow definition: one of:
│ ├─ Format 1: Inline steps — "step1 | step2 | step3" (pipe-separated commands)
│ ├─ Format 2: Skill names — "skill-a,skill-b,skill-c" (comma-separated)
│ ├─ Format 3: File path — "--file workflow.json" (JSON definition)
│ └─ Format 4: Natural language — free-text description, auto-decomposed into steps
├─ Test context: --context "description of what the workflow should achieve"
└─ Flags: --depth quick|standard|deep, -y/--yes, --auto-fix
```
### Format Detection Priority
```
1. --file flag present → Format 3 (JSON)
2. Contains pipe "|" → Format 1 (inline commands)
3. Matches skill-name pattern → Format 2 (comma-separated skills)
4. Everything else → Format 4 (natural language → semantic decomposition)
4a. Contains file path? → Read file as reference doc, extract workflow steps via LLM
4b. Pure intent text → Direct intent-verb matching (intentMap)
```
### Format 4: Semantic Decomposition (Natural Language)
When input is free-text (e.g., "分析 src 目录代码质量,做代码评审,然后修复高优先级问题"), the orchestrator:
#### 4a. Reference Document Mode (input contains file path)
When the input contains a file path (e.g., `d:\maestro2\guide\command-usage-guide.md 提取核心工作流`), the orchestrator:
1. **Detect File Path**: Extract file path from input via path pattern matching
2. **Read Reference Doc**: Read the file content as workflow reference material
3. **Extract Workflow via LLM**: Use Gemini to analyze the document + user intent, extract executable workflow steps
4. **Step Chain Generation**: LLM returns structured step chain with commands, tools, and execution order
5. **Command Doc + Confirmation**: Same as 4b below
#### 4b. Pure Intent Mode (no file path)
1. **Semantic Parse**: Identify intent verbs and targets → map to available skills/commands
2. **Step Chain Generation**: Produce ordered step chain with tool/mode selection
3. **Command Doc**: Generate formatted execution plan document
4. **User Confirmation**: Display plan, ask user to confirm/edit before execution
```javascript
// ★ 4a: If input contains file path → read file, extract workflow via LLM
// Detect paths: Windows (D:\path\file.md), Unix (/path/file.md), relative (./file.md)
// Read file content → send to Gemini with user intent → get executable step chain
// See phases/01-setup.md Step 1.1b Mode 4a
// ★ 4b: Pure intent text → regex-based intent-to-tool mapping
const intentMap = {
'分析|analyze|审查|inspect|scan': { tool: 'gemini', mode: 'analysis', rule: 'analysis-analyze-code-patterns' },
'评审|review|code review': { tool: 'gemini', mode: 'analysis', rule: 'analysis-review-code-quality' },
// ... (full map in phases/01-setup.md Step 1.1b Mode 4b)
};
// Match input segments to intents, produce step chain
// See phases/01-setup.md Step 1.1b for full algorithm
```
### Workflow JSON Format (when using --file)
```json
{
"name": "my-workflow",
"description": "What this workflow achieves",
"steps": [
{
"name": "step-1-name",
"type": "skill|command|ccw-cli",
"command": "/skill-name args" | "ccw cli -p '...' --tool gemini --mode analysis",
"expected_artifacts": ["output.md", "report.json"],
"success_criteria": "description of what success looks like"
}
]
}
```
### Inline Step Parsing
```javascript
// Pipe-separated: each segment is a command
// "ccw cli -p 'analyze' --tool gemini --mode analysis | /review-code src/ | ccw cli -p 'fix' --tool claude --mode write"
const steps = input.split('|').map((cmd, i) => ({
name: `step-${i + 1}`,
type: cmd.trim().startsWith('/') ? 'skill' : 'command',
command: cmd.trim(),
expected_artifacts: [],
success_criteria: ''
}));
```
## Pre-Execution Confirmation
After parsing (all formats) or decomposition (Format 4), generate a **Command Document** and ask for user confirmation before executing.
### Command Document Format
```markdown
# Workflow Tune — Execution Plan
**Workflow**: {name}
**Goal**: {context}
**Steps**: {count}
**Analysis Depth**: {depth}
## Step Chain
| # | Name | Type | Command | Tool | Mode |
|---|------|------|---------|------|------|
| 1 | {name} | {type} | {command} | {tool} | {mode} |
| 2 | ... | ... | ... | ... | ... |
## Execution Flow
```
Step 1: {name}
→ Command: {command}
→ Expected: {artifacts}
→ Feeds into: Step 2
Step 2: {name}
→ Command: {command}
→ Expected: {artifacts}
→ Feeds into: Step 3
...
```
## Estimated Scope
- Total CLI calls: {N} (execute) + {N} (analyze) + 1 (synthesize)
- Analysis tool: gemini (--resume chain)
- Process documentation: process-log.md (accumulated)
```
### Confirmation Flow
```javascript
// ★ Skip confirmation only if -y/--yes flag
if (!workflowPreferences.autoYes) {
// Display command document to user
// Output the formatted plan (direct text output, NOT a file)
const confirmation = AskUserQuestion({
questions: [{
question: "确认执行以上 Workflow 调优计划?",
header: "Confirm Execution",
multiSelect: false,
options: [
{ label: "Execute (确认执行)", description: "按计划开始执行" },
{ label: "Edit steps (修改步骤)", description: "我想调整某些步骤" },
{ label: "Cancel (取消)", description: "取消本次调优" }
]
}]
});
if (confirmation["Confirm Execution"].startsWith("Cancel")) {
// Abort workflow
return;
}
if (confirmation["Confirm Execution"].startsWith("Edit")) {
// Ask user for modifications
const editResponse = AskUserQuestion({
questions: [{
question: "请描述要修改的内容删除步骤2、步骤3改用codex、在步骤1后加入安全扫描",
header: "Edit Steps"
}]
});
// Apply user edits to steps[] → re-display command doc → re-confirm
// (recursive confirmation loop until Execute or Cancel)
}
}
```
## Execution Flow
> **COMPACT DIRECTIVE**: Context compression MUST check TaskUpdate phase status.
> The phase currently marked `in_progress` is the active execution phase — preserve its FULL content.
> Only compress phases marked `completed` or `pending`.
### Phase 1: Setup (one-time)
Read and execute: `Ref: phases/01-setup.md`
- Parse workflow steps from input (Format 1-3: direct parse, Format 4: semantic decomposition)
- Generate Command Document (formatted execution plan)
- **User Confirmation**: Display plan, wait for confirm/edit/cancel
- **Generate Test Requirements**: Auto-create per-step acceptance criteria via Gemini (expected outputs, content signals, quality thresholds, pass/fail criteria, handoff contracts)
- Create workspace at `.workflow/.scratchpad/workflow-tune-{ts}/`
- Initialize workflow-state.json (with test_requirements per step)
- Create process-log.md template
Output: `workDir`, `steps[]` (with test_requirements), `workflowContext`, `commandDoc`, initialized state
### Step Loop (Phase 2 + Phase 3, per step)
```javascript
// Track analysis session ID for resume chain
let analysisSessionId = null;
for (let stepIdx = 0; stepIdx < state.steps.length; stepIdx++) {
const step = state.steps[stepIdx];
TaskUpdate(stepLoopTask, {
subject: `Step ${stepIdx + 1}/${state.steps.length}: ${step.name}`,
status: 'in_progress'
});
// === Phase 2: Execute Step ===
// Read: phases/02-step-execute.md
// Execute command/skill → collect artifacts
// Write step-{N}-artifacts-manifest.json
// === Phase 3: Analyze Step ===
// Read: phases/03-step-analyze.md
// Inspect artifacts → ccw cli gemini --resume analysisSessionId
// Write step-{N}-analysis.md → append to process-log.md
// Update analysisSessionId for next step's resume
// Update state
state.steps[stepIdx].status = 'completed';
Write(`${state.work_dir}/workflow-state.json`, JSON.stringify(state, null, 2));
}
```
### Phase 2: Execute Step (per step)
Read and execute: `Ref: phases/02-step-execute.md`
- Create step working directory
- Execute command/skill via ccw cli or Skill tool
- Collect output artifacts
- Write artifacts manifest
### Phase 3: Analyze Step (per step)
Read and execute: `Ref: phases/03-step-analyze.md`
- Inspect step artifacts (file list, content summary, quality signals)
- **Compare actual output against test requirements** (pass_criteria, content_signals, fail_signals, handoff_contract)
- Build analysis prompt with step context + test requirements + previous process log
- Execute: `ccw cli --tool gemini --mode analysis [--resume sessionId]`
- Parse analysis → write step-{N}-analysis.md (with requirement match: PASS/FAIL)
- Append findings to process-log.md
- Return analysis session ID for resume chain
### Phase 4: Synthesize (one-time)
Read and execute: `Ref: phases/04-synthesize.md`
- Read complete process-log.md + all step analyses
- Build synthesis prompt with full workflow context
- Execute: `ccw cli --tool gemini --mode analysis --resume analysisSessionId`
- Generate cross-step optimization insights
- Write synthesis.md
### Phase 5: Optimization Report (one-time)
Read and execute: `Ref: phases/05-optimize-report.md`
- Aggregate all analyses and synthesis
- Generate structured optimization report
- Optionally apply high-priority fixes (if autoFix enabled)
- Write final-report.md
- Display summary to user
**Phase Reference Documents**:
| Phase | Document | Purpose | Compact |
|-------|----------|---------|---------|
| 1 | [phases/01-setup.md](phases/01-setup.md) | Initialize workspace and state | TaskUpdate driven |
| 2 | [phases/02-step-execute.md](phases/02-step-execute.md) | Execute workflow step | TaskUpdate driven |
| 3 | [phases/03-step-analyze.md](phases/03-step-analyze.md) | Analyze step artifacts | TaskUpdate driven + resume |
| 4 | [phases/04-synthesize.md](phases/04-synthesize.md) | Cross-step synthesis | TaskUpdate driven + resume |
| 5 | [phases/05-optimize-report.md](phases/05-optimize-report.md) | Generate final report | TaskUpdate driven |
## Data Flow
```
User Input (workflow steps / natural language + context)
Phase 1: Setup
├─ [Format 1-3] Direct parse → steps[]
├─ [Format 4a] File path detected → Read doc → LLM extract → steps[]
├─ [Format 4b] Pure intent text → Regex intent matching → steps[]
Command Document (formatted plan)
User Confirmation (Execute / Edit / Cancel)
↓ (Execute confirmed)
Generate Test Requirements (Gemini) → per-step acceptance criteria
↓ workDir, steps[] (with test_requirements), workflow-state.json, process-log.md
┌─→ Phase 2: Execute Step N (ccw cli / Skill)
│ ↓ step-N/ artifacts
│ ↓
│ Phase 3: Analyze Step N (ccw cli gemini --resume)
│ ↓ step-N-analysis.md, process-log.md updated
│ ↓ analysisSessionId carried forward
│ ↓
│ [More steps?]─── YES ──→ next step (Phase 2)
│ ↓ NO
│ ↓
└───┘
Phase 4: Synthesize (ccw cli gemini --resume)
↓ synthesis.md
Phase 5: Report
↓ final-report.md + optional auto-fix
Done
```
## TaskUpdate Pattern
```javascript
// Initial state
TaskCreate({ subject: "Phase 1: Setup workspace", activeForm: "Parsing workflow" })
TaskCreate({ subject: "Step Loop", activeForm: "Executing steps" })
TaskCreate({ subject: "Phase 4-5: Synthesize & Report", activeForm: "Pending" })
// Per-step tracking
for (const step of state.steps) {
TaskCreate({
subject: `Step: ${step.name}`,
activeForm: `Pending`,
description: `${step.type}: ${step.command}`
})
}
// During step execution
TaskUpdate(stepTask, {
subject: `Step: ${step.name} — Executing`,
activeForm: `Running ${step.command}`
})
// After step analysis
TaskUpdate(stepTask, {
subject: `Step: ${step.name} — Analyzed`,
activeForm: `Quality: ${stepQuality} | Issues: ${issueCount}`,
status: 'completed'
})
// Final
TaskUpdate(synthesisTask, {
subject: `Synthesis & Report (${state.steps.length} steps, ${totalIssues} issues)`,
status: 'completed'
})
```
## Resume Chain Strategy
```
Step 1 Execute → artifacts
Step 1 Analyze → ccw cli gemini --mode analysis → sessionId_1
Step 2 Execute → artifacts
Step 2 Analyze → ccw cli gemini --mode analysis --resume sessionId_1 → sessionId_2
...
Step N Analyze → sessionId_N
Synthesize → ccw cli gemini --mode analysis --resume sessionId_N → final
```
Each analysis step resumes the previous session, maintaining full context of:
- All prior step observations
- Accumulated quality patterns
- Cross-step dependency insights
## Error Handling
| Phase | Error | Recovery |
|-------|-------|----------|
| 2: Execute | CLI timeout/crash | Retry once, then record failure and continue to next step |
| 2: Execute | Skill not found | Skip step, note in process-log |
| 3: Analyze | CLI fails | Retry without --resume, start fresh session |
| 3: Analyze | Resume session not found | Start fresh analysis session |
| 4: Synthesize | CLI fails | Generate report from individual step analyses only |
| Any | 3+ consecutive errors | Terminate with partial report |
**Error Budget**: Each step gets 1 retry. 3 consecutive failures triggers early termination.
## Core Rules
1. **Start Immediately**: First action is preference collection → Phase 1 setup
2. **Progressive Loading**: Read phase doc ONLY when that phase is about to execute
3. **Inspect Before Proceed**: Always check step artifacts before moving to next step
4. **Background CLI**: ccw cli runs in background, wait for hook callback before proceeding
5. **Resume Chain**: Maintain analysis session continuity via --resume
6. **Process Documentation**: Every step observation goes into process-log.md
7. **Single State Source**: `workflow-state.json` is the only source of truth
8. **DO NOT STOP**: Continuous execution until all steps processed

View File

@@ -1,670 +0,0 @@
# Phase 1: Setup
Initialize workspace, parse workflow definition, semantic decomposition for natural language, generate command document, user confirmation, create state and process log.
## Objective
- Parse workflow steps from user input (Format 1-3: direct parse, Format 4: semantic decomposition)
- Generate Command Document (formatted execution plan)
- User confirmation: Execute / Edit steps / Cancel
- Validate step commands/skill paths
- Create isolated workspace directory
- Initialize workflow-state.json and process-log.md
## Execution
### Step 1.1: Parse Input
```javascript
const args = $ARGUMENTS.trim();
// Detect input format
let steps = [];
let workflowName = 'unnamed-workflow';
let workflowContext = '';
// Format 1: JSON file (--file path)
const fileMatch = args.match(/--file\s+"?([^\s"]+)"?/);
if (fileMatch) {
const wfDef = JSON.parse(Read(fileMatch[1]));
workflowName = wfDef.name || 'unnamed-workflow';
workflowContext = wfDef.description || '';
steps = wfDef.steps;
}
// Format 2: Pipe-separated commands ("cmd1 | cmd2 | cmd3")
else if (args.includes('|')) {
const rawSteps = args.split(/(?:--context|--depth|-y|--yes|--auto-fix)\s+("[^"]*"|\S+)/)[0];
steps = rawSteps.split('|').map((cmd, i) => ({
name: `step-${i + 1}`,
type: cmd.trim().startsWith('/') ? 'skill'
: cmd.trim().startsWith('ccw cli') ? 'ccw-cli'
: 'command',
command: cmd.trim(),
expected_artifacts: [],
success_criteria: ''
}));
}
// Format 3: Comma-separated skill names (matches pattern: word,word or word-word,word-word)
else if (/^[\w-]+(,[\w-]+)+/.test(args.split(/\s/)[0])) {
const skillPart = args.match(/^([^\s]+)/);
const skillNames = skillPart ? skillPart[1].split(',') : [];
steps = skillNames.map((name, i) => {
const skillPath = name.startsWith('.claude/') ? name : `.claude/skills/${name}`;
return {
name: name.replace('.claude/skills/', ''),
type: 'skill',
command: `/${name.replace('.claude/skills/', '')}`,
skill_path: skillPath,
expected_artifacts: [],
success_criteria: ''
};
});
}
// Format 4: Natural language → semantic decomposition
else {
inputFormat = 'natural-language';
naturalLanguageInput = args.replace(/--\w+\s+"[^"]*"/g, '').replace(/--\w+\s+\S+/g, '').replace(/-y|--yes/g, '').trim();
// ★ 4a: Detect file paths in input (Windows absolute, Unix absolute, or relative paths)
const filePathPattern = /(?:[A-Za-z]:[\\\/][^\s,;,;、]+|\/[^\s,;,;、]+\.(?:md|txt|json|yaml|yml|toml)|\.\/?[^\s,;,;、]+\.(?:md|txt|json|yaml|yml|toml))/g;
const detectedPaths = naturalLanguageInput.match(filePathPattern) || [];
referenceDocContent = null;
referenceDocPath = null;
if (detectedPaths.length > 0) {
// Read first detected file as reference document
referenceDocPath = detectedPaths[0];
try {
referenceDocContent = Read(referenceDocPath);
// Remove file path from natural language input to get pure user intent
naturalLanguageInput = naturalLanguageInput.replace(referenceDocPath, '').trim();
} catch (e) {
// File not readable — fall through to 4b (pure intent mode)
referenceDocContent = null;
}
}
// Steps will be populated in Step 1.1b
steps = [];
}
// Parse --context
const contextMatch = args.match(/--context\s+"([^"]+)"/);
workflowContext = contextMatch ? contextMatch[1] : workflowContext;
// Parse --depth
const depthMatch = args.match(/--depth\s+(quick|standard|deep)/);
if (depthMatch) {
workflowPreferences.analysisDepth = depthMatch[1];
}
// If no context provided, ask user
if (!workflowContext) {
const response = AskUserQuestion({
questions: [{
question: "请描述这个 workflow 的目标和预期效果:",
header: "Workflow Context",
multiSelect: false,
options: [
{ label: "General quality check", description: "通用质量检查,评估步骤间衔接" },
{ label: "Custom description", description: "自定义描述 workflow 目标" }
]
}]
});
workflowContext = response["Workflow Context"];
}
```
### Step 1.1b: Semantic Decomposition (Format 4 only)
> Skip this step if `inputFormat !== 'natural-language'`.
Two sub-modes based on whether a reference document was detected in Step 1.1:
#### Mode 4a: Reference Document → LLM Extraction
When `referenceDocContent` is available, use Gemini to extract executable workflow steps from the document, guided by the user's intent text.
```javascript
if (inputFormat === 'natural-language' && referenceDocContent) {
// ★ 4a: Extract workflow steps from reference document via LLM
const extractPrompt = `PURPOSE: Extract an executable workflow step chain from the reference document below, guided by the user's intent.
USER INTENT: ${naturalLanguageInput}
REFERENCE DOCUMENT PATH: ${referenceDocPath}
REFERENCE DOCUMENT CONTENT:
${referenceDocContent}
TASK:
1. Read the document and identify the workflow/process it describes (commands, steps, phases, procedures)
2. Filter by user intent — only extract the steps the user wants to test/tune
3. For each step, determine:
- The actual command to execute (shell command, CLI invocation, or skill name)
- The execution order and dependencies
- What tool to use (gemini/claude/codex/qwen) and mode (default: write)
4. Generate a step chain that can be directly executed
IMPORTANT:
- Extract REAL executable commands from the document, not analysis tasks about the document
- The user wants to RUN these workflow steps, not analyze the document itself
- If the document describes CLI commands like "maestro init", "maestro plan", etc., those are the steps to extract
- Preserve the original command syntax from the document
- Map each command to appropriate tool/mode for ccw cli execution, OR mark as 'command' type for direct shell execution
- Default mode to "write" — almost all steps produce output artifacts (files, reports, configs), even analysis steps need write permission to save results
EXPECTED OUTPUT (strict JSON, no markdown):
{
"workflow_name": "<descriptive name>",
"workflow_context": "<what this workflow achieves>",
"steps": [
{
"name": "<step name>",
"type": "command|ccw-cli|skill",
"command": "<the actual command to execute>",
"tool": "<gemini|claude|codex|qwen or null for shell commands>",
"mode": "<write (default) | analysis (read-only, rare) | null for shell commands>",
"rule": "<rule template or null>",
"original_text": "<source text from document>",
"expected_artifacts": ["<expected output files>"],
"success_criteria": "<what success looks like>"
}
]
}
CONSTRAINTS: Output ONLY valid JSON. Extract executable steps, NOT document analysis tasks.`;
Bash({
command: `ccw cli -p "${escapeForShell(extractPrompt)}" --tool gemini --mode analysis --rule universal-rigorous-style`,
run_in_background: true,
timeout: 300000
});
// STOP — wait for hook callback
// After callback: parse JSON response into steps[]
const extractOutput = /* CLI output from callback */;
const extractJsonMatch = extractOutput.match(/\{[\s\S]*\}/);
if (extractJsonMatch) {
try {
const extracted = JSON.parse(extractJsonMatch[0]);
workflowName = extracted.workflow_name || 'doc-workflow';
workflowContext = extracted.workflow_context || naturalLanguageInput;
steps = (extracted.steps || []).map((s, i) => ({
name: s.name || `step-${i + 1}`,
type: s.type || 'command',
command: s.command,
tool: s.tool || null,
mode: s.mode || null,
rule: s.rule || null,
original_text: s.original_text || '',
expected_artifacts: s.expected_artifacts || [],
success_criteria: s.success_criteria || ''
}));
} catch (e) {
// JSON parse failed — fall through to 4b intent matching
referenceDocContent = null;
}
}
if (steps.length === 0) {
// Extraction produced no steps — fall through to 4b
referenceDocContent = null;
}
}
```
#### Mode 4b: Pure Intent → Regex Matching
When no reference document, or when 4a extraction failed, decompose by intent-verb matching.
```javascript
if (inputFormat === 'natural-language' && !referenceDocContent) {
// Intent-to-tool mapping (regex patterns → tool config)
const intentMap = [
{ pattern: /分析|analyze|审查|inspect|scan/i, name: 'analyze', tool: 'gemini', mode: 'analysis', rule: 'analysis-analyze-code-patterns' },
{ pattern: /评审|review|code.?review/i, name: 'review', tool: 'gemini', mode: 'analysis', rule: 'analysis-review-code-quality' },
{ pattern: /诊断|debug|排查|diagnose/i, name: 'diagnose', tool: 'gemini', mode: 'analysis', rule: 'analysis-diagnose-bug-root-cause' },
{ pattern: /安全|security|漏洞|vulnerability/i, name: 'security-audit', tool: 'gemini', mode: 'analysis', rule: 'analysis-assess-security-risks' },
{ pattern: /性能|performance|perf/i, name: 'perf-analysis', tool: 'gemini', mode: 'analysis', rule: 'analysis-analyze-performance' },
{ pattern: /架构|architecture/i, name: 'arch-review', tool: 'gemini', mode: 'analysis', rule: 'analysis-review-architecture' },
{ pattern: /修复|fix|repair|解决/i, name: 'fix', tool: 'claude', mode: 'write', rule: 'development-debug-runtime-issues' },
{ pattern: /实现|implement|开发|create|新增/i, name: 'implement', tool: 'claude', mode: 'write', rule: 'development-implement-feature' },
{ pattern: /重构|refactor/i, name: 'refactor', tool: 'claude', mode: 'write', rule: 'development-refactor-codebase' },
{ pattern: /测试|test|generate.?test/i, name: 'test', tool: 'claude', mode: 'write', rule: 'development-generate-tests' },
{ pattern: /规划|plan|设计|design/i, name: 'plan', tool: 'gemini', mode: 'analysis', rule: 'planning-plan-architecture-design' },
{ pattern: /拆解|breakdown|分解/i, name: 'breakdown', tool: 'gemini', mode: 'analysis', rule: 'planning-breakdown-task-steps' },
];
// Segment input by Chinese/English delimiters: 、,,;然后/接着/最后/之后 etc.
const segments = naturalLanguageInput
.split(/[,;、]|(?:然后|接着|之后|最后|再|并|and then|then|finally|next)\s*/i)
.map(s => s.trim())
.filter(Boolean);
// Match each segment to an intent (with ambiguity resolution)
steps = segments.map((segment, i) => {
const allMatches = intentMap.filter(m => m.pattern.test(segment));
let matched = allMatches[0] || null;
// ★ Ambiguity resolution: if multiple intents match, ask user
if (allMatches.length > 1) {
const disambig = AskUserQuestion({
questions: [{
question: `"${segment}" 匹配到多个意图,请选择最符合的:`,
header: `Disambiguate Step ${i + 1}`,
multiSelect: false,
options: allMatches.map(m => ({
label: m.name,
description: `Tool: ${m.tool}, Mode: ${m.mode}, Rule: ${m.rule}`
}))
}]
});
const chosen = disambig[`Disambiguate Step ${i + 1}`];
matched = allMatches.find(m => m.name === chosen) || allMatches[0];
}
if (matched) {
// Extract target scope from segment (e.g., "分析 src 目录" → scope = "src")
const scopeMatch = segment.match(/(?:目录|文件|模块|directory|file|module)?\s*[:]?\s*(\S+)/);
const scope = scopeMatch ? scopeMatch[1].replace(/[的地得]$/, '') : '**/*';
return {
name: `${matched.name}`,
type: 'ccw-cli',
command: `ccw cli -p "${segment}" --tool ${matched.tool} --mode ${matched.mode} --rule ${matched.rule}`,
tool: matched.tool,
mode: matched.mode,
rule: matched.rule,
original_text: segment,
expected_artifacts: [],
success_criteria: ''
};
} else {
// Unmatched segment → generic analysis step
return {
name: `step-${i + 1}`,
type: 'ccw-cli',
command: `ccw cli -p "${segment}" --tool gemini --mode analysis`,
tool: 'gemini',
mode: 'analysis',
rule: 'universal-rigorous-style',
original_text: segment,
expected_artifacts: [],
success_criteria: ''
};
}
});
// Deduplicate: if same intent name appears twice, suffix with index
const nameCount = {};
steps.forEach(s => {
nameCount[s.name] = (nameCount[s.name] || 0) + 1;
if (nameCount[s.name] > 1) {
s.name = `${s.name}-${nameCount[s.name]}`;
}
});
}
// Common: set workflow context and name for Format 4
if (inputFormat === 'natural-language') {
if (!workflowContext) {
workflowContext = naturalLanguageInput;
}
if (!workflowName || workflowName === 'unnamed-workflow') {
workflowName = referenceDocPath ? 'doc-workflow' : 'nl-workflow';
}
}
```
### Step 1.1c: Generate Command Document
Generate a formatted execution plan for user review. This runs for ALL input formats, not just Format 4.
```javascript
function generateCommandDoc(steps, workflowName, workflowContext, analysisDepth) {
const stepTable = steps.map((s, i) => {
const tool = s.tool || (s.type === 'skill' ? '-' : 'claude');
const mode = s.mode || (s.type === 'skill' ? '-' : 'write');
const cmdPreview = s.command.length > 60 ? s.command.substring(0, 57) + '...' : s.command;
return `| ${i + 1} | ${s.name} | ${s.type} | \`${cmdPreview}\` | ${tool} | ${mode} |`;
}).join('\n');
const flowDiagram = steps.map((s, i) => {
const arrow = i < steps.length - 1 ? '\n ↓' : '';
const feedsInto = i < steps.length - 1 ? `Feeds into: Step ${i + 2} (${steps[i + 1].name})` : 'Final step';
const originalText = s.original_text ? `\n Source: "${s.original_text}"` : '';
return `Step ${i + 1}: ${s.name}
Command: ${s.command}
Type: ${s.type} | Tool: ${s.tool || '-'} | Mode: ${s.mode || '-'}${originalText}
${feedsInto}${arrow}`;
}).join('\n');
const totalCli = steps.filter(s => s.type === 'ccw-cli').length;
const totalSkill = steps.filter(s => s.type === 'skill').length;
const totalCmd = steps.filter(s => s.type === 'command').length;
return `# Workflow Tune — Execution Plan
**Workflow**: ${workflowName}
**Goal**: ${workflowContext}
**Steps**: ${steps.length}
**Analysis Depth**: ${analysisDepth}
## Step Chain
| # | Name | Type | Command | Tool | Mode |
|---|------|------|---------|------|------|
${stepTable}
## Execution Flow
\`\`\`
${flowDiagram}
\`\`\`
## Estimated Scope
- CLI execute calls: ${totalCli}
- Skill invocations: ${totalSkill}
- Shell commands: ${totalCmd}
- Analysis calls (gemini --resume chain): ${steps.length} (per-step) + 1 (synthesis)
- Process documentation: process-log.md (accumulated)
- Final output: final-report.md with optimization recommendations
`;
}
const commandDoc = generateCommandDoc(steps, workflowName, workflowContext, workflowPreferences.analysisDepth);
// Output command document to user (direct text output)
// The orchestrator displays this as formatted text before confirmation
```
### Step 1.1d: Pre-Execution Confirmation
```javascript
// ★ Skip confirmation if -y/--yes auto mode
if (!workflowPreferences.autoYes) {
// Display commandDoc to user as formatted text output
// Then ask for confirmation
const confirmation = AskUserQuestion({
questions: [{
question: "确认执行以上 Workflow 调优计划?",
header: "Confirm Execution",
multiSelect: false,
options: [
{ label: "Execute (确认执行)", description: "按计划开始执行所有步骤" },
{ label: "Edit steps (修改步骤)", description: "调整步骤顺序、增删步骤、更换工具" },
{ label: "Cancel (取消)", description: "取消本次调优" }
]
}]
});
const choice = confirmation["Confirm Execution"];
if (choice.startsWith("Cancel")) {
// Abort: no workspace created, no state written
// Output: "Workflow tune cancelled."
return;
}
if (choice.startsWith("Edit")) {
// Enter edit loop: ask user what to change, apply, re-display, re-confirm
let editing = true;
while (editing) {
const editResponse = AskUserQuestion({
questions: [{
question: "请描述要修改的内容:\n" +
" - 删除步骤: '删除步骤2' 或 'remove step 2'\n" +
" - 添加步骤: '在步骤1后加入安全扫描' 或 'add security scan after step 1'\n" +
" - 修改工具: '步骤3改用codex' 或 'step 3 use codex'\n" +
" - 调换顺序: '步骤2和步骤3互换' 或 'swap step 2 and 3'\n" +
" - 修改命令: '步骤1命令改为 ccw cli -p \"...\" --tool gemini'",
header: "Edit Steps"
}]
});
const editText = editResponse["Edit Steps"];
// Apply edits to steps[] based on user instruction
// The orchestrator interprets the edit instruction and modifies steps:
//
// Delete: filter out the specified step, re-index
// Add: insert new step at specified position
// Modify tool: update the step's tool/mode/command
// Swap: exchange positions of two steps
// Modify command: replace command string
//
// After applying edits, re-generate command doc and re-display
const updatedCommandDoc = generateCommandDoc(steps, workflowName, workflowContext, workflowPreferences.analysisDepth);
// Display updatedCommandDoc to user
const reconfirm = AskUserQuestion({
questions: [{
question: "修改后的计划如上,是否确认?",
header: "Confirm Execution",
multiSelect: false,
options: [
{ label: "Execute (确认执行)", description: "按修改后的计划执行" },
{ label: "Edit more (继续修改)", description: "还需要调整" },
{ label: "Cancel (取消)", description: "取消本次调优" }
]
}]
});
const reChoice = reconfirm["Confirm Execution"];
if (reChoice.startsWith("Execute")) {
editing = false;
} else if (reChoice.startsWith("Cancel")) {
return; // Abort
}
// else: continue editing loop
}
}
// choice === "Execute" → proceed to workspace creation
}
// Save command doc for reference
// Will be written to workspace after Step 1.3
```
### Step 1.2: Validate Steps
```javascript
for (const step of steps) {
if (step.type === 'skill' && step.skill_path) {
const skillFiles = Glob(`${step.skill_path}/SKILL.md`);
if (skillFiles.length === 0) {
step.validation = 'warning';
step.validation_msg = `Skill not found: ${step.skill_path}`;
} else {
step.validation = 'ok';
}
} else {
// Command-type steps: basic validation (non-empty)
step.validation = step.command && step.command.trim() ? 'ok' : 'invalid';
}
}
const invalidSteps = steps.filter(s => s.validation === 'invalid');
if (invalidSteps.length > 0) {
throw new Error(`Invalid steps: ${invalidSteps.map(s => s.name).join(', ')}`);
}
```
### Step 1.2b: Generate Test Requirements (Acceptance Criteria)
> 调优的前提:为每一步生成跟任务匹配的验收标准。没有预期基准,就无法判断命令执行是否达标。
用 Gemini 根据 step command + workflow context + 上下游关系,自动推断每步的验收标准。
```javascript
// Build step chain description for context
const stepChainDesc = steps.map((s, i) =>
`Step ${i + 1}: ${s.name} (${s.type}) — ${s.command}`
).join('\n');
const reqGenPrompt = `PURPOSE: Generate concrete acceptance criteria (test requirements) for each step in a workflow pipeline. These criteria will be used to objectively judge whether each step's execution succeeded or failed.
WORKFLOW:
Name: ${workflowName}
Goal: ${workflowContext}
STEP CHAIN:
${stepChainDesc}
TASK:
For each step, generate:
1. **expected_outputs** — what files/artifacts should be produced (specific filenames or patterns)
2. **content_signals** — what content patterns indicate success (keywords, structures, data shapes)
3. **quality_thresholds** — minimum quality bar (e.g., "no empty files", "JSON must be parseable", "must contain at least N items")
4. **pass_criteria** — 1-2 sentence description of what "pass" looks like for this step
5. **fail_signals** — what patterns indicate failure (error messages, empty output, wrong format)
6. **handoff_contract** — what this step must provide for the next step to work (data format, required fields)
CONTEXT RULES:
- Infer from the command what the step is supposed to do
- Consider workflow goal when judging what "good enough" means
- Each step's handoff_contract should match what the next step needs as input
- Be specific: "report.md with ## Summary section" not "a report file"
EXPECTED OUTPUT (strict JSON, no markdown):
{
"step_requirements": [
{
"step_index": 0,
"step_name": "<name>",
"expected_outputs": ["<file or pattern>"],
"content_signals": ["<keyword or pattern that indicates success>"],
"quality_thresholds": ["<minimum bar>"],
"pass_criteria": "<what pass looks like>",
"fail_signals": ["<pattern that indicates failure>"],
"handoff_contract": "<what next step needs from this step>"
}
]
}
CONSTRAINTS: Be specific to each command, output ONLY JSON`;
Bash({
command: `ccw cli -p "${escapeForShell(reqGenPrompt)}" --tool gemini --mode analysis --rule universal-rigorous-style`,
run_in_background: true,
timeout: 300000
});
// STOP — wait for hook callback
// After callback: parse JSON, attach requirements to each step
const reqOutput = /* CLI output from callback */;
const reqJsonMatch = reqOutput.match(/\{[\s\S]*\}/);
if (reqJsonMatch) {
try {
const reqData = JSON.parse(reqJsonMatch[0]);
(reqData.step_requirements || []).forEach(req => {
const idx = req.step_index;
if (idx >= 0 && idx < steps.length) {
steps[idx].test_requirements = {
expected_outputs: req.expected_outputs || [],
content_signals: req.content_signals || [],
quality_thresholds: req.quality_thresholds || [],
pass_criteria: req.pass_criteria || '',
fail_signals: req.fail_signals || [],
handoff_contract: req.handoff_contract || ''
};
}
});
} catch (e) {
// Fallback: proceed without generated requirements
// Steps will use any manually provided success_criteria
}
}
// Capture session ID for resume chain start
const reqSessionMatch = reqOutput.match(/\[CCW_EXEC_ID=([^\]]+)\]/);
const reqSessionId = reqSessionMatch ? reqSessionMatch[1] : null;
```
### Step 1.3: Create Workspace
```javascript
const ts = Date.now();
const workDir = `.workflow/.scratchpad/workflow-tune-${ts}`;
Bash(`mkdir -p "${workDir}/steps"`);
// Create per-step directories
for (let i = 0; i < steps.length; i++) {
Bash(`mkdir -p "${workDir}/steps/step-${i + 1}/artifacts"`);
}
```
### Step 1.3b: Save Command Document
```javascript
// Save confirmed command doc to workspace for reference
Write(`${workDir}/command-doc.md`, commandDoc);
```
### Step 1.4: Initialize State
```javascript
const initialState = {
status: 'running',
started_at: new Date().toISOString(),
updated_at: new Date().toISOString(),
workflow_name: workflowName,
workflow_context: workflowContext,
analysis_depth: workflowPreferences.analysisDepth,
auto_fix: workflowPreferences.autoFix,
steps: steps.map((s, i) => ({
...s,
index: i,
status: 'pending',
execution: null,
analysis: null,
test_requirements: s.test_requirements || null // from Step 1.2b
})),
analysis_session_id: reqSessionId || null, // resume chain starts from requirements generation
process_log_entries: [],
synthesis: null,
errors: [],
error_count: 0,
max_errors: 3,
work_dir: workDir
};
Write(`${workDir}/workflow-state.json`, JSON.stringify(initialState, null, 2));
```
### Step 1.5: Initialize Process Log
```javascript
const processLog = `# Workflow Tune Process Log
**Workflow**: ${workflowName}
**Context**: ${workflowContext}
**Steps**: ${steps.length}
**Analysis Depth**: ${workflowPreferences.analysisDepth}
**Started**: ${new Date().toISOString()}
---
`;
Write(`${workDir}/process-log.md`, processLog);
```
## Output
- **Variables**: `workDir`, `steps[]`, `workflowContext`, `commandDoc`, initialized state
- **Files**: `workflow-state.json`, `process-log.md`, `command-doc.md`, per-step directories
- **User Confirmation**: Execution plan confirmed (or cancelled → abort)
- **TaskUpdate**: Mark Phase 1 completed, start Step Loop

View File

@@ -1,197 +0,0 @@
# Phase 2: Execute Step
> **COMPACT SENTINEL [Phase 2: Execute Step]**
> This phase contains 4 execution steps (Step 2.1 -- 2.4).
> If you can read this sentinel but cannot find the full Step protocol below, context has been compressed.
> Recovery: `Read("phases/02-step-execute.md")`
Execute a single workflow step and collect its output artifacts.
## Objective
- Determine step execution method (skill invoke / ccw cli / shell command)
- Execute step with appropriate tool
- Collect output artifacts into step directory
- Write artifacts manifest
## Execution
### Step 2.1: Prepare Step Directory
```javascript
const stepIdx = currentStepIndex; // from orchestrator loop
const step = state.steps[stepIdx];
const stepDir = `${state.work_dir}/steps/step-${stepIdx + 1}`;
const artifactsDir = `${stepDir}/artifacts`;
// Capture pre-execution state (git status, file timestamps)
const preGitStatus = Bash('git status --porcelain 2>/dev/null || echo "not a git repo"').stdout;
// ★ Warn if dirty git working directory (first step only)
if (stepIdx === 0 && preGitStatus.trim() && preGitStatus.trim() !== 'not a git repo') {
const dirtyLines = preGitStatus.trim().split('\n').length;
// Log warning — artifact collection via git diff may be unreliable
// This is informational; does not block execution
console.warn(`⚠ Dirty git working directory detected (${dirtyLines} changed files). Artifact collection via git diff may include pre-existing changes.`);
}
const preExecSnapshot = {
timestamp: new Date().toISOString(),
git_status: preGitStatus,
working_files: Glob('**/*.{ts,js,md,json}').slice(0, 50) // sample
};
Write(`${stepDir}/pre-exec-snapshot.json`, JSON.stringify(preExecSnapshot, null, 2));
```
### Step 2.2: Execute by Step Type
```javascript
let executionResult = { success: false, method: '', output: '', duration: 0 };
const startTime = Date.now();
switch (step.type) {
case 'skill': {
// Skill invocation — use Skill tool
// Extract skill name and arguments from command
const skillCmd = step.command.replace(/^\//, '');
const [skillName, ...skillArgs] = skillCmd.split(/\s+/);
// Execute skill (this runs synchronously within current context)
// Note: Skill execution produces artifacts in the working directory
// We capture changes by comparing pre/post state
Skill({
name: skillName,
arguments: skillArgs.join(' ')
});
executionResult.method = 'skill';
executionResult.success = true;
break;
}
case 'ccw-cli': {
// Direct ccw cli command
const cliCommand = step.command;
Bash({
command: cliCommand,
run_in_background: true,
timeout: 600000 // 10 minutes
});
// STOP — wait for hook callback
// After callback:
executionResult.method = 'ccw-cli';
executionResult.success = true;
break;
}
case 'command': {
// Generic shell command
const result = Bash({
command: step.command,
timeout: 300000 // 5 minutes
});
executionResult.method = 'command';
executionResult.output = result.stdout || '';
executionResult.success = result.exitCode === 0;
// Save command output
if (executionResult.output) {
Write(`${artifactsDir}/command-output.txt`, executionResult.output);
}
if (result.stderr) {
Write(`${artifactsDir}/command-stderr.txt`, result.stderr);
}
break;
}
}
executionResult.duration = Date.now() - startTime;
```
### Step 2.3: Collect Artifacts
```javascript
// Capture post-execution state
const postExecSnapshot = {
timestamp: new Date().toISOString(),
git_status: Bash('git status --porcelain 2>/dev/null || echo "not a git repo"').stdout,
working_files: Glob('**/*.{ts,js,md,json}').slice(0, 50)
};
// Detect changed/new files by comparing snapshots
const preFiles = new Set(preExecSnapshot.working_files);
const newOrChanged = postExecSnapshot.working_files.filter(f => !preFiles.has(f));
// Also check git diff for modified files
const gitDiff = Bash('git diff --name-only 2>/dev/null || true').stdout.trim().split('\n').filter(Boolean);
// Collect all artifacts (new files + git-changed files + declared expected_artifacts)
const declaredArtifacts = (step.expected_artifacts || []).filter(f => {
// Verify declared artifacts actually exist
const exists = Glob(f);
return exists.length > 0;
}).flatMap(f => Glob(f));
const allArtifacts = [...new Set([...newOrChanged, ...gitDiff, ...declaredArtifacts])];
// Copy detected artifacts to step artifacts dir (or record references)
const artifactManifest = {
step: step.name,
step_index: stepIdx,
execution_method: executionResult.method,
success: executionResult.success,
duration_ms: executionResult.duration,
artifacts: allArtifacts.map(f => ({
path: f,
type: f.endsWith('.md') ? 'markdown' : f.endsWith('.json') ? 'json' : 'other',
size: 'unknown' // Can be filled by stat if needed
})),
// For skill type: also check .workflow/.scratchpad for generated files
scratchpad_files: step.type === 'skill'
? Glob('.workflow/.scratchpad/**/*').filter(f => {
// Only include files created after step started
return true; // Heuristic: include recent scratchpad files
}).slice(0, 20)
: [],
collected_at: new Date().toISOString()
};
Write(`${stepDir}/artifacts-manifest.json`, JSON.stringify(artifactManifest, null, 2));
```
### Step 2.4: Update State
```javascript
state.steps[stepIdx].status = 'executed';
state.steps[stepIdx].execution = {
method: executionResult.method,
success: executionResult.success,
duration_ms: executionResult.duration,
artifacts_dir: artifactsDir,
manifest_path: `${stepDir}/artifacts-manifest.json`,
artifact_count: artifactManifest.artifacts.length,
started_at: preExecSnapshot.timestamp,
completed_at: new Date().toISOString()
};
state.updated_at = new Date().toISOString();
Write(`${state.work_dir}/workflow-state.json`, JSON.stringify(state, null, 2));
```
## Error Handling
| Error | Recovery |
|-------|----------|
| Skill not found | Record failure, set success=false, continue to Phase 3 |
| CLI timeout (10min) | Retry once with shorter timeout, then record failure |
| Command exit non-zero | Record stderr, set success=false, continue to Phase 3 |
| No artifacts detected | Continue to Phase 3 — analysis evaluates step definition quality |
## Output
- **Files**: `pre-exec-snapshot.json`, `artifacts-manifest.json`, `artifacts/` (if command type)
- **State**: `steps[stepIdx].execution` updated
- **Next**: Phase 3 (Analyze Step)

View File

@@ -1,386 +0,0 @@
# Phase 3: Analyze Step
> **COMPACT SENTINEL [Phase 3: Analyze Step]**
> This phase contains 5 execution steps (Step 3.1 -- 3.5).
> If you can read this sentinel but cannot find the full Step protocol below, context has been compressed.
> Recovery: `Read("phases/03-step-analyze.md")`
Analyze a completed step's artifacts and quality using `ccw cli --tool gemini --mode analysis`. Uses `--resume` to maintain context across step analyses, building a continuous analysis chain.
## Objective
- Inspect step artifacts (file list, content, quality signals)
- Build analysis prompt with step context + prior process log
- Execute via ccw cli Gemini with resume chain
- Parse analysis results → write step-{N}-analysis.md
- Append findings to process-log.md
- Return updated session ID for resume chain
## Execution
### Step 3.1: Inspect Artifacts
```javascript
const stepIdx = currentStepIndex;
const step = state.steps[stepIdx];
const stepDir = `${state.work_dir}/steps/step-${stepIdx + 1}`;
// Read artifacts manifest
const manifest = JSON.parse(Read(`${stepDir}/artifacts-manifest.json`));
// Build artifact summary based on analysis depth
let artifactSummary = '';
if (state.analysis_depth === 'quick') {
// Quick: just file list and sizes
artifactSummary = `Artifacts (${manifest.artifacts.length} files):\n` +
manifest.artifacts.map(a => `- ${a.path} (${a.type})`).join('\n');
} else {
// Standard/Deep: include file content summaries
artifactSummary = manifest.artifacts.map(a => {
const maxLines = state.analysis_depth === 'deep' ? 300 : 150;
try {
const content = Read(a.path, { limit: maxLines });
return `--- ${a.path} (${a.type}) ---\n${content}`;
} catch {
return `--- ${a.path} --- [unreadable]`;
}
}).join('\n\n');
// Deep: also include scratchpad files
if (state.analysis_depth === 'deep' && manifest.scratchpad_files?.length > 0) {
artifactSummary += '\n\n--- Scratchpad Files ---\n' +
manifest.scratchpad_files.slice(0, 5).map(f => {
const content = Read(f, { limit: 100 });
return `--- ${f} ---\n${content}`;
}).join('\n\n');
}
}
// Execution result summary
const execSummary = `Execution: ${step.execution.method} | ` +
`Success: ${step.execution.success} | ` +
`Duration: ${step.execution.duration_ms}ms | ` +
`Artifacts: ${manifest.artifacts.length} files`;
```
### Step 3.2: Build Prior Context
```javascript
// Build accumulated process log context for this analysis
const priorProcessLog = Read(`${state.work_dir}/process-log.md`);
// Build step chain context (what came before, what comes after)
const stepChainContext = state.steps.map((s, i) => {
const status = i < stepIdx ? 'completed' : i === stepIdx ? 'CURRENT' : 'pending';
const score = s.analysis?.quality_score || '-';
return `${i + 1}. [${status}] ${s.name} (${s.type}) — Quality: ${score}`;
}).join('\n');
// Previous step handoff context (if not first step)
let handoffContext = '';
if (stepIdx > 0) {
const prevStep = state.steps[stepIdx - 1];
const prevAnalysis = prevStep.analysis;
if (prevAnalysis) {
handoffContext = `PREVIOUS STEP OUTPUT SUMMARY:
Step "${prevStep.name}" produced ${prevStep.execution?.artifact_count || 0} artifacts.
Quality: ${prevAnalysis.quality_score}/100
Key outputs: ${prevAnalysis.key_outputs?.join(', ') || 'unknown'}
Handoff notes: ${prevAnalysis.handoff_notes || 'none'}`;
}
}
```
### Step 3.3: Construct Analysis Prompt
```javascript
// Ref: templates/step-analysis-prompt.md
const depthInstructions = {
quick: 'Provide brief assessment (3-5 bullet points). Focus on: execution success, output completeness, obvious issues.',
standard: 'Provide detailed assessment. Cover: execution quality, output completeness, artifact quality, step-to-step handoff readiness, potential issues.',
deep: 'Provide exhaustive assessment. Cover: execution quality, output completeness and correctness, artifact quality and structure, step-to-step handoff integrity, error handling, performance signals, architecture implications, edge cases.'
};
// ★ Build test requirements section (the evaluation baseline)
const testReqs = step.test_requirements;
let testReqSection = '';
if (testReqs) {
testReqSection = `
TEST REQUIREMENTS (Acceptance Criteria — use these as the PRIMARY evaluation baseline):
Pass Criteria: ${testReqs.pass_criteria}
Expected Outputs: ${(testReqs.expected_outputs || []).join(', ') || 'not specified'}
Content Signals (patterns that indicate success): ${(testReqs.content_signals || []).join(', ') || 'not specified'}
Quality Thresholds: ${(testReqs.quality_thresholds || []).join(', ') || 'not specified'}
Fail Signals (patterns that indicate failure): ${(testReqs.fail_signals || []).join(', ') || 'not specified'}
Handoff Contract (what next step needs): ${testReqs.handoff_contract || 'not specified'}
IMPORTANT: Score quality_score based on how well the actual output matches these test requirements.
- 90-100: All pass_criteria met, all expected_outputs present, content_signals found, no fail_signals
- 70-89: Most criteria met, minor gaps
- 50-69: Partial match, significant gaps
- 0-49: Fail — fail_signals present or pass_criteria not met`;
} else {
testReqSection = `
NOTE: No pre-generated test requirements for this step. Evaluate based on general quality signals and workflow context.`;
}
const analysisPrompt = `PURPOSE: Evaluate workflow step "${step.name}" (step ${stepIdx + 1}/${state.steps.length}) against its acceptance criteria. Judge whether the command execution met the pre-defined test requirements.
WORKFLOW CONTEXT:
Name: ${state.workflow_name}
Goal: ${state.workflow_context}
Step Chain:
${stepChainContext}
CURRENT STEP:
Name: ${step.name}
Type: ${step.type}
Command: ${step.command}
${step.success_criteria ? `Success Criteria: ${step.success_criteria}` : ''}
${testReqSection}
EXECUTION RESULT:
${execSummary}
${handoffContext}
STEP ARTIFACTS:
${artifactSummary}
ANALYSIS DEPTH: ${state.analysis_depth}
${depthInstructions[state.analysis_depth]}
TASK:
1. **Requirement Matching**: Compare actual output against test requirements (pass_criteria, expected_outputs, content_signals)
2. **Fail Signal Detection**: Check for any fail_signals in the output
3. **Handoff Contract Verification**: Does the output satisfy handoff_contract for the next step?
4. **Gap Analysis**: What's missing between actual output and requirements?
5. **Quality Score**: Rate 0-100 based on requirement fulfillment (NOT general quality)
EXPECTED OUTPUT (strict JSON, no markdown):
{
"quality_score": <0-100>,
"requirement_match": {
"pass": <true|false>,
"criteria_met": ["<which pass_criteria were satisfied>"],
"criteria_missed": ["<which pass_criteria were NOT satisfied>"],
"expected_outputs_found": ["<expected files that exist>"],
"expected_outputs_missing": ["<expected files that are absent>"],
"content_signals_found": ["<success patterns detected in output>"],
"content_signals_missing": ["<success patterns NOT found>"],
"fail_signals_detected": ["<failure patterns found, if any>"]
},
"execution_assessment": {
"success": <true|false>,
"completeness": "<complete|partial|failed>",
"notes": "<brief assessment>"
},
"artifact_assessment": {
"count": <number>,
"quality": "<high|medium|low>",
"key_outputs": ["<main output 1>", "<main output 2>"],
"missing_outputs": ["<expected but missing>"]
},
"handoff_assessment": {
"ready": <true|false>,
"contract_satisfied": <true|false|null>,
"next_step_compatible": <true|false|null>,
"handoff_notes": "<what next step should know>"
},
"issues": [
{ "severity": "high|medium|low", "description": "<issue>", "suggestion": "<fix>" }
],
"optimization_opportunities": [
{ "area": "<area>", "description": "<opportunity>", "impact": "high|medium|low" }
],
"step_summary": "<1-2 sentence summary for process log>"
}
CONSTRAINTS: Be specific, reference artifact content where possible, score against requirements not general quality, output ONLY JSON`;
```
### Step 3.4: Execute via ccw cli Gemini with Resume
```javascript
function escapeForShell(str) {
return str.replace(/"/g, '\\"').replace(/\$/g, '\\$').replace(/`/g, '\\`');
}
// Build CLI command with optional resume
let cliCommand = `ccw cli -p "${escapeForShell(analysisPrompt)}" --tool gemini --mode analysis`;
// Resume from previous step's analysis session (maintains context chain)
if (state.analysis_session_id) {
cliCommand += ` --resume ${state.analysis_session_id}`;
}
Bash({
command: cliCommand,
run_in_background: true,
timeout: 300000 // 5 minutes
});
// STOP — wait for hook callback
```
### Step 3.5: Parse Results and Update Process Log
After CLI completes:
```javascript
const rawOutput = /* CLI output from callback */;
// Extract session ID from CLI output for resume chain
const sessionIdMatch = rawOutput.match(/\[CCW_EXEC_ID=([^\]]+)\]/);
if (sessionIdMatch) {
state.analysis_session_id = sessionIdMatch[1];
}
// Parse JSON
const jsonMatch = rawOutput.match(/\{[\s\S]*\}/);
let analysis;
if (jsonMatch) {
try {
analysis = JSON.parse(jsonMatch[0]);
} catch (e) {
// Fallback: extract score heuristically
const scoreMatch = rawOutput.match(/"quality_score"\s*:\s*(\d+)/);
analysis = {
quality_score: scoreMatch ? parseInt(scoreMatch[1]) : 50,
execution_assessment: { success: step.execution.success, completeness: 'unknown', notes: 'Parse failed' },
artifact_assessment: { count: manifest.artifacts.length, quality: 'unknown', key_outputs: [], missing_outputs: [] },
handoff_assessment: { ready: true, next_step_compatible: null, handoff_notes: '' },
issues: [{ severity: 'low', description: 'Analysis output parsing failed', suggestion: 'Review raw output' }],
optimization_opportunities: [],
step_summary: 'Analysis parsing failed — raw output saved for manual review'
};
}
} else {
analysis = {
quality_score: 50,
step_summary: 'No structured analysis output received'
};
}
// Write step analysis file
const reqMatch = analysis.requirement_match;
const reqMatchSection = reqMatch ? `
## Requirement Match — ${reqMatch.pass ? 'PASS ✓' : 'FAIL ✗'}
### Criteria Met
${(reqMatch.criteria_met || []).map(c => `- ✓ ${c}`).join('\n') || '- None'}
### Criteria Missed
${(reqMatch.criteria_missed || []).map(c => `- ✗ ${c}`).join('\n') || '- None'}
### Expected Outputs
- Found: ${(reqMatch.expected_outputs_found || []).join(', ') || 'None'}
- Missing: ${(reqMatch.expected_outputs_missing || []).join(', ') || 'None'}
### Content Signals
- Detected: ${(reqMatch.content_signals_found || []).join(', ') || 'None'}
- Missing: ${(reqMatch.content_signals_missing || []).join(', ') || 'None'}
### Fail Signals
${(reqMatch.fail_signals_detected || []).length > 0
? (reqMatch.fail_signals_detected || []).map(f => `- ⚠ ${f}`).join('\n')
: '- None detected'}
` : '';
const stepAnalysisReport = `# Step ${stepIdx + 1} Analysis: ${step.name}
**Quality Score**: ${analysis.quality_score}/100
**Requirement Match**: ${reqMatch ? (reqMatch.pass ? 'PASS' : 'FAIL') : 'N/A (no test requirements)'}
**Date**: ${new Date().toISOString()}
${reqMatchSection}
## Execution
- Success: ${analysis.execution_assessment?.success}
- Completeness: ${analysis.execution_assessment?.completeness}
- Notes: ${analysis.execution_assessment?.notes}
## Artifacts
- Count: ${analysis.artifact_assessment?.count}
- Quality: ${analysis.artifact_assessment?.quality}
- Key Outputs: ${analysis.artifact_assessment?.key_outputs?.join(', ') || 'N/A'}
- Missing: ${analysis.artifact_assessment?.missing_outputs?.join(', ') || 'None'}
## Handoff Readiness
- Ready: ${analysis.handoff_assessment?.ready}
- Contract Satisfied: ${analysis.handoff_assessment?.contract_satisfied}
- Next Step Compatible: ${analysis.handoff_assessment?.next_step_compatible}
- Notes: ${analysis.handoff_assessment?.handoff_notes}
## Issues
${(analysis.issues || []).map(i => `- [${i.severity}] ${i.description}${i.suggestion}`).join('\n') || 'None'}
## Optimization Opportunities
${(analysis.optimization_opportunities || []).map(o => `- [${o.impact}] ${o.area}: ${o.description}`).join('\n') || 'None'}
`;
Write(`${stepDir}/step-${stepIdx + 1}-analysis.md`, stepAnalysisReport);
// Append to process log
const reqPassStr = reqMatch ? (reqMatch.pass ? 'PASS' : 'FAIL') : 'N/A';
const processLogEntry = `
## Step ${stepIdx + 1}: ${step.name} — Score: ${analysis.quality_score}/100 | Req: ${reqPassStr}
**Command**: \`${step.command}\`
**Result**: ${analysis.execution_assessment?.completeness || 'unknown'} | ${analysis.artifact_assessment?.count || 0} artifacts
**Requirement Match**: ${reqPassStr}${reqMatch ? ` — Met: ${(reqMatch.criteria_met || []).length}, Missed: ${(reqMatch.criteria_missed || []).length}, Fail Signals: ${(reqMatch.fail_signals_detected || []).length}` : ''}
**Summary**: ${analysis.step_summary || 'No summary'}
**Issues**: ${(analysis.issues || []).filter(i => i.severity === 'high').map(i => i.description).join('; ') || 'None critical'}
**Handoff**: ${analysis.handoff_assessment?.contract_satisfied ? 'Contract satisfied' : analysis.handoff_assessment?.handoff_notes || 'Ready'}
---
`;
// Append to process-log.md
const currentLog = Read(`${state.work_dir}/process-log.md`);
Write(`${state.work_dir}/process-log.md`, currentLog + processLogEntry);
// Update state
state.steps[stepIdx].analysis = {
quality_score: analysis.quality_score,
requirement_pass: reqMatch?.pass ?? null,
criteria_met_count: (reqMatch?.criteria_met || []).length,
criteria_missed_count: (reqMatch?.criteria_missed || []).length,
fail_signals_count: (reqMatch?.fail_signals_detected || []).length,
key_outputs: analysis.artifact_assessment?.key_outputs || [],
handoff_notes: analysis.handoff_assessment?.handoff_notes || '',
contract_satisfied: analysis.handoff_assessment?.contract_satisfied ?? null,
issue_count: (analysis.issues || []).length,
high_issues: (analysis.issues || []).filter(i => i.severity === 'high').length,
optimization_count: (analysis.optimization_opportunities || []).length,
analysis_file: `${stepDir}/step-${stepIdx + 1}-analysis.md`
};
state.steps[stepIdx].status = 'analyzed';
state.process_log_entries.push({
step_index: stepIdx,
step_name: step.name,
quality_score: analysis.quality_score,
summary: analysis.step_summary,
timestamp: new Date().toISOString()
});
state.updated_at = new Date().toISOString();
Write(`${state.work_dir}/workflow-state.json`, JSON.stringify(state, null, 2));
```
## Error Handling
| Error | Recovery |
|-------|----------|
| CLI timeout | Retry once without --resume (fresh session) |
| Resume session not found | Start fresh analysis session, continue |
| JSON parse fails | Extract score heuristically, save raw output |
| No output | Default score 50, minimal process log entry |
## Output
- **Files**: `step-{N}-analysis.md`, updated `process-log.md`
- **State**: `steps[stepIdx].analysis` updated, `analysis_session_id` updated
- **Next**: Phase 2 for next step, or Phase 4 (Synthesize) if all steps done

View File

@@ -1,257 +0,0 @@
# Phase 4: Synthesize
> **COMPACT SENTINEL [Phase 4: Synthesize]**
> This phase contains 4 execution steps (Step 4.1 -- 4.4).
> If you can read this sentinel but cannot find the full Step protocol below, context has been compressed.
> Recovery: `Read("phases/04-synthesize.md")`
Synthesize all step analyses into cross-step insights. Evaluates the workflow as a whole: step ordering, handoff quality, redundancy, bottlenecks, and overall coherence.
## Objective
- Read complete process-log.md and all step analyses
- Build synthesis prompt with full workflow context
- Execute via ccw cli Gemini with resume chain
- Generate cross-step optimization insights
- Write synthesis.md
## Execution
### Step 4.1: Gather All Analyses
```javascript
// Read process log
const processLog = Read(`${state.work_dir}/process-log.md`);
// Read all step analysis files
const stepAnalyses = state.steps.map((step, i) => {
const analysisFile = `${state.work_dir}/steps/step-${i + 1}/step-${i + 1}-analysis.md`;
try {
return { step: step.name, index: i, content: Read(analysisFile) };
} catch {
return { step: step.name, index: i, content: '[Analysis not available]' };
}
});
// Build score summary
const scoreSummary = state.steps.map((s, i) =>
`Step ${i + 1} (${s.name}): ${s.analysis?.quality_score || '-'}/100 | Issues: ${s.analysis?.issue_count || 0} (${s.analysis?.high_issues || 0} high)`
).join('\n');
// Compute aggregate stats
const scores = state.steps.map(s => s.analysis?.quality_score).filter(Boolean);
const avgScore = scores.length > 0 ? Math.round(scores.reduce((a, b) => a + b, 0) / scores.length) : 0;
const minScore = scores.length > 0 ? Math.min(...scores) : 0;
const totalIssues = state.steps.reduce((sum, s) => sum + (s.analysis?.issue_count || 0), 0);
const totalHighIssues = state.steps.reduce((sum, s) => sum + (s.analysis?.high_issues || 0), 0);
```
### Step 4.2: Construct Synthesis Prompt
```javascript
// Ref: templates/synthesis-prompt.md
const synthesisPrompt = `PURPOSE: Synthesize all step analyses into a holistic workflow optimization assessment. Evaluate cross-step concerns: ordering, handoff quality, redundancy, bottlenecks, and overall workflow coherence.
WORKFLOW OVERVIEW:
Name: ${state.workflow_name}
Goal: ${state.workflow_context}
Steps: ${state.steps.length}
Average Quality: ${avgScore}/100
Weakest Step: ${minScore}/100
Total Issues: ${totalIssues} (${totalHighIssues} high severity)
SCORE SUMMARY:
${scoreSummary}
COMPLETE PROCESS LOG:
${processLog}
DETAILED STEP ANALYSES:
${stepAnalyses.map(a => `### ${a.step} (Step ${a.index + 1})\n${a.content}`).join('\n\n---\n\n')}
TASK:
1. **Workflow Coherence**: Do steps form a logical sequence? Any missing steps?
2. **Handoff Quality**: Are step outputs well-consumed by subsequent steps? Data format mismatches?
3. **Redundancy Detection**: Do any steps duplicate work? Overlapping concerns?
4. **Bottleneck Identification**: Which steps are bottlenecks (lowest quality, longest duration)?
5. **Step Ordering**: Would reordering steps improve outcomes?
6. **Missing Steps**: Are there gaps in the pipeline that need additional steps?
7. **Per-Step Optimization**: Top 3 improvements per underperforming step
8. **Workflow-Level Optimization**: Structural changes to the overall pipeline
EXPECTED OUTPUT (strict JSON, no markdown):
{
"workflow_score": <0-100>,
"coherence": {
"score": <0-100>,
"assessment": "<logical flow evaluation>",
"gaps": ["<missing step or transition>"]
},
"handoff_quality": {
"score": <0-100>,
"issues": [
{ "from_step": "<step name>", "to_step": "<step name>", "issue": "<description>", "fix": "<suggestion>" }
]
},
"redundancy": {
"found": <true|false>,
"items": [
{ "steps": ["<step1>", "<step2>"], "description": "<what overlaps>", "recommendation": "<merge or remove>" }
]
},
"bottlenecks": [
{ "step": "<step name>", "reason": "<why it's a bottleneck>", "impact": "high|medium|low", "fix": "<suggestion>" }
],
"ordering_suggestions": [
{ "current": "<current order description>", "proposed": "<new order>", "rationale": "<why>" }
],
"per_step_improvements": [
{ "step": "<step name>", "improvements": [
{ "priority": "high|medium|low", "description": "<what to change>", "rationale": "<why>" }
]}
],
"workflow_improvements": [
{ "priority": "high|medium|low", "category": "structure|handoff|performance|quality", "description": "<change>", "rationale": "<why>", "affected_steps": ["<step names>"] }
],
"summary": "<2-3 sentence executive summary of workflow health and top recommendations>"
}
CONSTRAINTS: Be specific, reference step names and artifact details, output ONLY JSON`;
```
### Step 4.3: Execute via ccw cli Gemini with Resume
```javascript
function escapeForShell(str) {
return str.replace(/"/g, '\\"').replace(/\$/g, '\\$').replace(/`/g, '\\`');
}
let cliCommand = `ccw cli -p "${escapeForShell(synthesisPrompt)}" --tool gemini --mode analysis`;
// Resume from the last step's analysis session
if (state.analysis_session_id) {
cliCommand += ` --resume ${state.analysis_session_id}`;
}
Bash({
command: cliCommand,
run_in_background: true,
timeout: 300000
});
// STOP — wait for hook callback
```
### Step 4.4: Parse Results and Write Synthesis
After CLI completes:
```javascript
const rawOutput = /* CLI output from callback */;
const jsonMatch = rawOutput.match(/\{[\s\S]*\}/);
let synthesis;
if (jsonMatch) {
try {
synthesis = JSON.parse(jsonMatch[0]);
} catch {
synthesis = {
workflow_score: avgScore,
summary: 'Synthesis parsing failed — individual step analyses available',
workflow_improvements: [],
per_step_improvements: [],
bottlenecks: [],
handoff_quality: { score: 0, issues: [] },
coherence: { score: 0, assessment: 'Parse error' },
redundancy: { found: false, items: [] },
ordering_suggestions: []
};
}
} else {
synthesis = {
workflow_score: avgScore,
summary: 'No synthesis output received',
workflow_improvements: [],
per_step_improvements: []
};
}
// Write synthesis report
const synthesisReport = `# Workflow Synthesis
**Workflow Score**: ${synthesis.workflow_score}/100
**Date**: ${new Date().toISOString()}
## Executive Summary
${synthesis.summary}
## Coherence (${synthesis.coherence?.score || '-'}/100)
${synthesis.coherence?.assessment || 'N/A'}
${(synthesis.coherence?.gaps || []).length > 0 ? '\n### Gaps\n' + synthesis.coherence.gaps.map(g => `- ${g}`).join('\n') : ''}
## Handoff Quality (${synthesis.handoff_quality?.score || '-'}/100)
${(synthesis.handoff_quality?.issues || []).map(i =>
`- **${i.from_step}${i.to_step}**: ${i.issue}\n Fix: ${i.fix}`
).join('\n') || 'No handoff issues'}
## Redundancy
${synthesis.redundancy?.found ? (synthesis.redundancy.items || []).map(r =>
`- Steps ${r.steps.join(', ')}: ${r.description}${r.recommendation}`
).join('\n') : 'No redundancy detected'}
## Bottlenecks
${(synthesis.bottlenecks || []).map(b =>
`- **${b.step}** [${b.impact}]: ${b.reason}\n Fix: ${b.fix}`
).join('\n') || 'No bottlenecks'}
## Ordering Suggestions
${(synthesis.ordering_suggestions || []).map(o =>
`- Current: ${o.current}\n Proposed: ${o.proposed}\n Rationale: ${o.rationale}`
).join('\n') || 'Current ordering is optimal'}
## Per-Step Improvements
${(synthesis.per_step_improvements || []).map(s =>
`### ${s.step}\n` + (s.improvements || []).map(i =>
`- [${i.priority}] ${i.description}${i.rationale}`
).join('\n')
).join('\n\n') || 'No per-step improvements'}
## Workflow-Level Improvements
${(synthesis.workflow_improvements || []).map((w, i) =>
`### ${i + 1}. [${w.priority}] ${w.description}\n- Category: ${w.category}\n- Rationale: ${w.rationale}\n- Affected: ${(w.affected_steps || []).join(', ')}`
).join('\n\n') || 'No workflow-level improvements'}
`;
Write(`${state.work_dir}/synthesis.md`, synthesisReport);
// Update state
state.synthesis = {
workflow_score: synthesis.workflow_score,
summary: synthesis.summary,
improvement_count: (synthesis.workflow_improvements || []).length +
(synthesis.per_step_improvements || []).reduce((sum, s) => sum + (s.improvements || []).length, 0),
high_priority_count: (synthesis.workflow_improvements || []).filter(w => w.priority === 'high').length,
bottleneck_count: (synthesis.bottlenecks || []).length,
handoff_issue_count: (synthesis.handoff_quality?.issues || []).length,
synthesis_file: `${state.work_dir}/synthesis.md`,
raw_data: synthesis
};
state.updated_at = new Date().toISOString();
Write(`${state.work_dir}/workflow-state.json`, JSON.stringify(state, null, 2));
```
## Error Handling
| Error | Recovery |
|-------|----------|
| CLI timeout | Generate synthesis from individual step analyses only (no cross-step) |
| Resume fails | Start fresh analysis session |
| JSON parse fails | Use step-level data to construct minimal synthesis |
## Output
- **Files**: `synthesis.md`
- **State**: `state.synthesis` updated
- **Next**: Phase 5 (Optimization Report)

View File

@@ -1,246 +0,0 @@
# Phase 5: Optimization Report
> **COMPACT SENTINEL [Phase 5: Report]**
> This phase contains 4 execution steps (Step 5.1 -- 5.4).
> If you can read this sentinel but cannot find the full Step protocol below, context has been compressed.
> Recovery: `Read("phases/05-optimize-report.md")`
Generate the final optimization report and optionally apply high-priority fixes.
## Objective
- Read complete state, process log, synthesis
- Generate structured final report
- Optionally apply auto-fix (if enabled)
- Write final-report.md
- Display summary to user
## Execution
### Step 5.1: Read Complete State
```javascript
const state = JSON.parse(Read(`${state.work_dir}/workflow-state.json`));
const processLog = Read(`${state.work_dir}/process-log.md`);
const synthesis = state.synthesis;
state.status = 'completed';
state.updated_at = new Date().toISOString();
```
### Step 5.2: Generate Report
```javascript
// Compute stats
const scores = state.steps.map(s => s.analysis?.quality_score).filter(Boolean);
const avgScore = scores.length > 0 ? Math.round(scores.reduce((a, b) => a + b, 0) / scores.length) : 0;
const minStep = state.steps.reduce((min, s) =>
(s.analysis?.quality_score || 100) < (min.analysis?.quality_score || 100) ? s : min
, state.steps[0]);
const totalIssues = state.steps.reduce((sum, s) => sum + (s.analysis?.issue_count || 0), 0);
const totalHighIssues = state.steps.reduce((sum, s) => sum + (s.analysis?.high_issues || 0), 0);
// Step quality table (with requirement match)
const stepTable = state.steps.map((s, i) => {
const reqPass = s.analysis?.requirement_pass;
const reqStr = reqPass === true ? 'PASS' : reqPass === false ? 'FAIL' : '-';
return `| ${i + 1} | ${s.name} | ${s.type} | ${s.execution?.success ? 'OK' : 'FAIL'} | ${reqStr} | ${s.analysis?.quality_score || '-'} | ${s.analysis?.issue_count || 0} | ${s.analysis?.high_issues || 0} |`;
}).join('\n');
// Collect all improvements (workflow-level + per-step)
const allImprovements = [];
if (synthesis?.raw_data?.workflow_improvements) {
synthesis.raw_data.workflow_improvements.forEach(w => {
allImprovements.push({
scope: 'workflow',
priority: w.priority,
description: w.description,
rationale: w.rationale,
category: w.category,
affected: w.affected_steps || []
});
});
}
if (synthesis?.raw_data?.per_step_improvements) {
synthesis.raw_data.per_step_improvements.forEach(s => {
(s.improvements || []).forEach(imp => {
allImprovements.push({
scope: s.step,
priority: imp.priority,
description: imp.description,
rationale: imp.rationale,
category: 'step',
affected: [s.step]
});
});
});
}
// Sort by priority
const priorityOrder = { high: 0, medium: 1, low: 2 };
allImprovements.sort((a, b) => (priorityOrder[a.priority] || 2) - (priorityOrder[b.priority] || 2));
const report = `# Workflow Tune — Final Report
## Summary
| Field | Value |
|-------|-------|
| **Workflow** | ${state.workflow_name} |
| **Goal** | ${state.workflow_context} |
| **Steps** | ${state.steps.length} |
| **Workflow Score** | ${synthesis?.workflow_score || avgScore}/100 |
| **Average Step Quality** | ${avgScore}/100 |
| **Weakest Step** | ${minStep.name} (${minStep.analysis?.quality_score || '-'}/100) |
| **Total Issues** | ${totalIssues} (${totalHighIssues} high severity) |
| **Analysis Depth** | ${state.analysis_depth} |
| **Started** | ${state.started_at} |
| **Completed** | ${state.updated_at} |
## Step Quality Matrix
| # | Step | Type | Exec | Req Match | Quality | Issues | High |
|---|------|------|------|-----------|---------|--------|------|
${stepTable}
## Workflow Flow Assessment
### Coherence: ${synthesis?.raw_data?.coherence?.score || '-'}/100
${synthesis?.raw_data?.coherence?.assessment || 'Not evaluated'}
### Handoff Quality: ${synthesis?.raw_data?.handoff_quality?.score || '-'}/100
${(synthesis?.raw_data?.handoff_quality?.issues || []).map(i =>
`- **${i.from_step}${i.to_step}**: ${i.issue}`
).join('\n') || 'No handoff issues'}
### Bottlenecks
${(synthesis?.raw_data?.bottlenecks || []).map(b =>
`- **${b.step}** [${b.impact}]: ${b.reason}`
).join('\n') || 'No bottlenecks identified'}
## Optimization Recommendations
### Priority: HIGH
${allImprovements.filter(i => i.priority === 'high').map((i, idx) =>
`${idx + 1}. **[${i.scope}]** ${i.description}\n - Rationale: ${i.rationale}\n - Affected: ${i.affected.join(', ')}`
).join('\n') || 'None'}
### Priority: MEDIUM
${allImprovements.filter(i => i.priority === 'medium').map((i, idx) =>
`${idx + 1}. **[${i.scope}]** ${i.description}\n - Rationale: ${i.rationale}`
).join('\n') || 'None'}
### Priority: LOW
${allImprovements.filter(i => i.priority === 'low').map((i, idx) =>
`${idx + 1}. **[${i.scope}]** ${i.description}`
).join('\n') || 'None'}
## Process Documentation
Full process log: \`${state.work_dir}/process-log.md\`
Synthesis: \`${state.work_dir}/synthesis.md\`
### Per-Step Analysis Files
| Step | Analysis File |
|------|---------------|
${state.steps.map((s, i) =>
`| ${s.name} | \`${state.work_dir}/steps/step-${i + 1}/step-${i + 1}-analysis.md\` |`
).join('\n')}
## Artifact Locations
| Path | Description |
|------|-------------|
| \`${state.work_dir}/workflow-state.json\` | Complete state |
| \`${state.work_dir}/process-log.md\` | Accumulated process log |
| \`${state.work_dir}/synthesis.md\` | Cross-step synthesis |
| \`${state.work_dir}/final-report.md\` | This report |
`;
Write(`${state.work_dir}/final-report.md`, report);
```
### Step 5.3: Optional Auto-Fix
```javascript
if (state.auto_fix && allImprovements.filter(i => i.priority === 'high').length > 0) {
const highPriorityFixes = allImprovements.filter(i => i.priority === 'high');
// ★ Safety: confirm with user before applying auto-fixes
const fixList = highPriorityFixes.map((f, i) =>
`${i + 1}. [${f.scope}] ${f.description}\n Affected: ${f.affected.join(', ')}`
).join('\n');
const autoFixConfirm = AskUserQuestion({
questions: [{
question: `以下 ${highPriorityFixes.length} 项高优先级优化将被自动应用:\n\n${fixList}\n\n确认应用?`,
header: "Auto-Fix Confirmation",
multiSelect: false,
options: [
{ label: "Apply (应用)", description: "自动应用以上高优先级修复" },
{ label: "Skip (跳过)", description: "跳过自动修复,仅保留报告" }
]
}]
});
if (autoFixConfirm["Auto-Fix Confirmation"].startsWith("Skip")) {
// Skip auto-fix, just log it
state.auto_fix_skipped = true;
} else {
Agent({
subagent_type: 'general-purpose',
run_in_background: false,
description: 'Apply high-priority workflow optimizations',
prompt: `## Task: Apply High-Priority Workflow Optimizations
You are applying the top optimization suggestions from a workflow analysis.
## Improvements to Apply (HIGH priority only)
${highPriorityFixes.map((f, i) =>
`${i + 1}. [${f.scope}] ${f.description}\n Rationale: ${f.rationale}\n Affected: ${f.affected.join(', ')}`
).join('\n')}
## Workflow Steps
${state.steps.map((s, i) => `${i + 1}. ${s.name} (${s.type}): ${s.command}`).join('\n')}
## Rules
1. Read each affected file BEFORE modifying
2. Apply ONLY the high-priority suggestions
3. Preserve existing code style
4. Write a changes summary to: ${state.work_dir}/auto-fix-changes.md
`
});
} // end Apply branch
}
```
### Step 5.4: Display Summary
Output to user:
```
Workflow Tune Complete!
Workflow: {name}
Steps: {count}
Workflow Score: {score}/100
Average Step Quality: {avgScore}/100
Weakest Step: {name} ({score}/100)
Step Scores: {step1}={score1} → {step2}={score2} → ... → {stepN}={scoreN}
Issues: {total} ({high} high priority)
Improvements: {count} ({highCount} high priority)
Full report: {workDir}/final-report.md
Process log: {workDir}/process-log.md
```
## Output
- **Files**: `final-report.md`, optionally `auto-fix-changes.md`
- **State**: `status = completed`
- **Next**: Workflow complete. Return control to user.

View File

@@ -1,57 +0,0 @@
# Workflow Evaluation Criteria
Workflow 调优评估标准,由 Phase 03 (Analyze Step) 和 Phase 04 (Synthesize) 引用。
## Per-Step Dimensions
| Dimension | Description |
|-----------|-------------|
| Execution Success | 命令是否成功执行,退出码是否正确 |
| Output Completeness | 产物是否齐全,预期文件是否生成 |
| Artifact Quality | 产物内容质量 — 非空、格式正确、内容有意义 |
| Handoff Readiness | 产物是否满足下一步的输入要求,格式兼容性 |
## Per-Step Scoring Guide
| Range | Level | Description |
|-------|-------|-------------|
| 90-100 | Excellent | 执行完美,产物高质量,下游可直接消费 |
| 80-89 | Good | 执行成功,产物基本完整,微调即可衔接 |
| 70-79 | Adequate | 执行成功但产物有缺失或质量一般 |
| 60-69 | Needs Work | 部分失败或产物质量差,衔接困难 |
| 0-59 | Poor | 执行失败或产物无法使用 |
## Workflow-Level Dimensions
| Dimension | Description |
|-----------|-------------|
| Coherence | 步骤间的逻辑顺序是否合理,是否形成完整流程 |
| Handoff Quality | 步骤间的数据传递是否顺畅,格式是否匹配 |
| Redundancy | 是否存在步骤间的工作重叠或重复 |
| Efficiency | 整体流程是否高效,有无不必要的步骤 |
| Completeness | 是否覆盖所有必要环节,有无遗漏 |
## Analysis Depth Profiles
### Quick
- 每步 3-5 要点
- 关注: 执行成功、产出完整、明显问题
- 跨步骤: 基本衔接检查
### Standard
- 每步详细评估
- 关注: 执行质量、产出完整性、产物质量、衔接就绪度、潜在问题
- 跨步骤: 衔接质量、冗余检测、瓶颈识别
### Deep
- 每步深度审查
- 关注: 执行质量、产出正确性、结构质量、衔接完整性、错误处理、性能信号、架构影响、边界情况
- 跨步骤: 全面流程优化、重排建议、缺失步骤检测、架构改进
## Issue Severity Guide
| Severity | Description | Example |
|----------|-------------|---------|
| High | 阻断流程或导致错误结果 | 步骤执行失败、产物格式不兼容、关键数据丢失 |
| Medium | 影响质量但不阻断 | 产物不完整、衔接需手动调整、冗余步骤 |
| Low | 可改进但不影响功能 | 输出格式不一致、可优化的步骤顺序 |

View File

@@ -1,88 +0,0 @@
# Step Analysis Prompt Template
Phase 03 使用此模板构造 ccw cli 提示词,让 Gemini 分析单个步骤的执行结果和产物质量。
## Template
```
PURPOSE: Analyze the output of workflow step "${stepName}" (step ${stepIndex}/${totalSteps}) to assess quality, identify issues, and evaluate handoff readiness for the next step.
WORKFLOW CONTEXT:
Name: ${workflowName}
Goal: ${workflowContext}
Step Chain:
${stepChainContext}
CURRENT STEP:
Name: ${stepName}
Type: ${stepType}
Command: ${stepCommand}
${successCriteria}
EXECUTION RESULT:
${execSummary}
${handoffContext}
STEP ARTIFACTS:
${artifactSummary}
ANALYSIS DEPTH: ${analysisDepth}
${depthInstructions}
TASK:
1. Assess step execution quality (did it succeed? complete output?)
2. Evaluate artifact quality (content correctness, completeness, format)
3. Check handoff readiness (can the next step consume this output?)
4. Identify issues, risks, or optimization opportunities
5. Rate overall step quality 0-100
EXPECTED OUTPUT (strict JSON, no markdown):
{
"quality_score": <0-100>,
"execution_assessment": {
"success": <true|false>,
"completeness": "<complete|partial|failed>",
"notes": "<brief assessment>"
},
"artifact_assessment": {
"count": <number>,
"quality": "<high|medium|low>",
"key_outputs": ["<main output 1>", "<main output 2>"],
"missing_outputs": ["<expected but missing>"]
},
"handoff_assessment": {
"ready": <true|false>,
"next_step_compatible": <true|false|null>,
"handoff_notes": "<what next step should know>"
},
"issues": [
{ "severity": "high|medium|low", "description": "<issue>", "suggestion": "<fix>" }
],
"optimization_opportunities": [
{ "area": "<area>", "description": "<opportunity>", "impact": "high|medium|low" }
],
"step_summary": "<1-2 sentence summary for process log>"
}
CONSTRAINTS: Be specific, reference artifact content where possible, output ONLY JSON
```
## Variable Substitution
| Variable | Source | Description |
|----------|--------|-------------|
| `${stepName}` | workflow-state.json | 当前步骤名称 |
| `${stepIndex}` | orchestrator loop | 当前步骤序号 (1-based) |
| `${totalSteps}` | workflow-state.json | 总步骤数 |
| `${workflowName}` | workflow-state.json | Workflow 名称 |
| `${workflowContext}` | workflow-state.json | Workflow 目标描述 |
| `${stepChainContext}` | Phase 03 builds | 所有步骤状态概览 |
| `${stepType}` | workflow-state.json | 步骤类型 (skill/ccw-cli/command) |
| `${stepCommand}` | workflow-state.json | 步骤命令 |
| `${successCriteria}` | workflow-state.json | 成功标准 (如有) |
| `${execSummary}` | Phase 03 builds | 执行结果摘要 |
| `${handoffContext}` | Phase 03 builds | 上一步的产出摘要 (非首步) |
| `${artifactSummary}` | Phase 03 builds | 产物内容摘要 |
| `${analysisDepth}` | workflow-state.json | 分析深度 (quick/standard/deep) |
| `${depthInstructions}` | Phase 03 maps | 对应深度的分析指令 |

View File

@@ -1,90 +0,0 @@
# Synthesis Prompt Template
Phase 04 使用此模板构造 ccw cli 提示词,让 Gemini 综合所有步骤分析,产出跨步骤优化建议。
## Template
```
PURPOSE: Synthesize all step analyses into a holistic workflow optimization assessment. Evaluate cross-step concerns: ordering, handoff quality, redundancy, bottlenecks, and overall workflow coherence.
WORKFLOW OVERVIEW:
Name: ${workflowName}
Goal: ${workflowContext}
Steps: ${stepCount}
Average Quality: ${avgScore}/100
Weakest Step: ${minScore}/100
Total Issues: ${totalIssues} (${totalHighIssues} high severity)
SCORE SUMMARY:
${scoreSummary}
COMPLETE PROCESS LOG:
${processLog}
DETAILED STEP ANALYSES:
${stepAnalyses}
TASK:
1. **Workflow Coherence**: Do steps form a logical sequence? Any missing steps?
2. **Handoff Quality**: Are step outputs well-consumed by subsequent steps? Data format mismatches?
3. **Redundancy Detection**: Do any steps duplicate work? Overlapping concerns?
4. **Bottleneck Identification**: Which steps are bottlenecks (lowest quality, longest duration)?
5. **Step Ordering**: Would reordering steps improve outcomes?
6. **Missing Steps**: Are there gaps in the pipeline that need additional steps?
7. **Per-Step Optimization**: Top 3 improvements per underperforming step
8. **Workflow-Level Optimization**: Structural changes to the overall pipeline
EXPECTED OUTPUT (strict JSON, no markdown):
{
"workflow_score": <0-100>,
"coherence": {
"score": <0-100>,
"assessment": "<logical flow evaluation>",
"gaps": ["<missing step or transition>"]
},
"handoff_quality": {
"score": <0-100>,
"issues": [
{ "from_step": "<step name>", "to_step": "<step name>", "issue": "<description>", "fix": "<suggestion>" }
]
},
"redundancy": {
"found": <true|false>,
"items": [
{ "steps": ["<step1>", "<step2>"], "description": "<what overlaps>", "recommendation": "<merge or remove>" }
]
},
"bottlenecks": [
{ "step": "<step name>", "reason": "<why it's a bottleneck>", "impact": "high|medium|low", "fix": "<suggestion>" }
],
"ordering_suggestions": [
{ "current": "<current order description>", "proposed": "<new order>", "rationale": "<why>" }
],
"per_step_improvements": [
{ "step": "<step name>", "improvements": [
{ "priority": "high|medium|low", "description": "<what to change>", "rationale": "<why>" }
]}
],
"workflow_improvements": [
{ "priority": "high|medium|low", "category": "structure|handoff|performance|quality", "description": "<change>", "rationale": "<why>", "affected_steps": ["<step names>"] }
],
"summary": "<2-3 sentence executive summary of workflow health and top recommendations>"
}
CONSTRAINTS: Be specific, reference step names and artifact details, output ONLY JSON
```
## Variable Substitution
| Variable | Source | Description |
|----------|--------|-------------|
| `${workflowName}` | workflow-state.json | Workflow 名称 |
| `${workflowContext}` | workflow-state.json | Workflow 目标 |
| `${stepCount}` | workflow-state.json | 总步骤数 |
| `${avgScore}` | Phase 04 computes | 所有步骤平均分 |
| `${minScore}` | Phase 04 computes | 最低步骤分 |
| `${totalIssues}` | Phase 04 computes | 总问题数 |
| `${totalHighIssues}` | Phase 04 computes | 高优先级问题数 |
| `${scoreSummary}` | Phase 04 builds | 每步分数一行 |
| `${processLog}` | process-log.md | 完整过程日志 |
| `${stepAnalyses}` | Phase 04 reads | 所有 step-N-analysis.md 内容 |

3
.gitignore vendored
View File

@@ -136,6 +136,9 @@ ccw/.tmp-ccw-auth-home/
.claude/skills_lib/team-skill-designer/templates/role-template.md .claude/skills_lib/team-skill-designer/templates/role-template.md
.claude/skills_lib/team-skill-designer/templates/skill-router-template.md .claude/skills_lib/team-skill-designer/templates/skill-router-template.md
# Workflow tune command (local only)
.claude/commands/workflow-tune.md
# Skills library (local only) # Skills library (local only)
.claude/skills_lib/ .claude/skills_lib/

View File

@@ -85,3 +85,4 @@ codex-lens/.workflow/
# Claude skills (development only) # Claude skills (development only)
.claude/skills/team-designer/ .claude/skills/team-designer/
.claude/commands/workflow-tune.md

Binary file not shown.

Before

Width:  |  Height:  |  Size: 229 KiB

After

Width:  |  Height:  |  Size: 171 KiB

View File

@@ -1,6 +1,6 @@
{ {
"name": "claude-code-workflow", "name": "claude-code-workflow",
"version": "7.2.11", "version": "7.2.13",
"description": "JSON-driven multi-agent development framework with intelligent CLI orchestration (Gemini/Qwen/Codex), context-first architecture, and automated workflow execution", "description": "JSON-driven multi-agent development framework with intelligent CLI orchestration (Gemini/Qwen/Codex), context-first architecture, and automated workflow execution",
"type": "module", "type": "module",
"main": "ccw/dist/index.js", "main": "ccw/dist/index.js",