Remove IDAW run and status commands, consolidating functionality and streamlining task execution and progress tracking.

This commit is contained in:
catlog22
2026-03-21 16:18:15 +08:00
parent 5d0000bcc5
commit fab07c2e97
14 changed files with 0 additions and 5014 deletions

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
```