claude-code-workflow 6.3.38 → 6.3.39
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.codex/agents/ccw-loop-b-complete.md +227 -0
- package/.codex/agents/ccw-loop-b-debug.md +172 -0
- package/.codex/agents/ccw-loop-b-develop.md +147 -0
- package/.codex/agents/ccw-loop-b-init.md +82 -0
- package/.codex/agents/ccw-loop-b-validate.md +204 -0
- package/.codex/agents/ccw-loop-executor.md +4 -4
- package/.codex/prompts/clean.md +409 -0
- package/.codex/skills/ccw-loop/README.md +3 -3
- package/.codex/skills/ccw-loop/SKILL.md +16 -16
- package/.codex/skills/ccw-loop/phases/actions/action-complete.md +4 -4
- package/.codex/skills/ccw-loop/phases/actions/action-debug.md +3 -3
- package/.codex/skills/ccw-loop/phases/actions/action-develop.md +5 -5
- package/.codex/skills/ccw-loop/phases/actions/action-init.md +5 -5
- package/.codex/skills/ccw-loop/phases/actions/action-menu.md +2 -2
- package/.codex/skills/ccw-loop/phases/actions/action-validate.md +5 -5
- package/.codex/skills/ccw-loop/phases/orchestrator.md +6 -6
- package/.codex/skills/ccw-loop/phases/state-schema.md +11 -11
- package/.codex/skills/ccw-loop-b/README.md +260 -61
- package/.codex/skills/ccw-loop-b/SKILL.md +4 -4
- package/.codex/skills/ccw-loop-b/phases/orchestrator.md +2 -2
- package/.codex/skills/ccw-loop-b/phases/state-schema.md +3 -3
- package/.codex/skills/ccw-loop-b/specs/action-catalog.md +383 -0
- package/.codex/skills/parallel-dev-cycle/README.md +382 -0
- package/.codex/skills/parallel-dev-cycle/SKILL.md +512 -0
- package/.codex/skills/parallel-dev-cycle/phases/agents/code-developer.md +242 -0
- package/.codex/skills/parallel-dev-cycle/phases/agents/exploration-planner.md +285 -0
- package/.codex/skills/parallel-dev-cycle/phases/agents/requirements-analyst.md +285 -0
- package/.codex/skills/parallel-dev-cycle/phases/agents/validation-archivist.md +381 -0
- package/.codex/skills/parallel-dev-cycle/phases/orchestrator.md +696 -0
- package/.codex/skills/parallel-dev-cycle/phases/state-schema.md +436 -0
- package/.codex/skills/parallel-dev-cycle/specs/communication-optimization.md +423 -0
- package/.codex/skills/parallel-dev-cycle/specs/coordination-protocol.md +391 -0
- package/.codex/skills/parallel-dev-cycle/specs/versioning-strategy.md +330 -0
- package/ccw/dist/commands/install.js +1 -1
- package/ccw/dist/commands/install.js.map +1 -1
- package/ccw/dist/tools/claude-cli-tools.d.ts.map +1 -1
- package/ccw/dist/tools/claude-cli-tools.js +4 -3
- package/ccw/dist/tools/claude-cli-tools.js.map +1 -1
- package/ccw/dist/tools/cli-config-manager.d.ts +1 -0
- package/ccw/dist/tools/cli-config-manager.d.ts.map +1 -1
- package/ccw/dist/tools/cli-config-manager.js +2 -1
- package/ccw/dist/tools/cli-config-manager.js.map +1 -1
- package/ccw/src/commands/install.ts +1 -1
- package/ccw/src/tools/claude-cli-tools.ts +4 -3
- package/ccw/src/tools/cli-config-manager.ts +3 -1
- package/package.json +1 -1
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
# Worker: Validate (CCW Loop-B)
|
|
2
|
+
|
|
3
|
+
Execute validation: tests, coverage analysis, quality gates.
|
|
4
|
+
|
|
5
|
+
## Responsibilities
|
|
6
|
+
|
|
7
|
+
1. **Test execution**
|
|
8
|
+
- Run unit tests
|
|
9
|
+
- Run integration tests
|
|
10
|
+
- Check test results
|
|
11
|
+
|
|
12
|
+
2. **Coverage analysis**
|
|
13
|
+
- Measure coverage
|
|
14
|
+
- Identify gaps
|
|
15
|
+
- Suggest improvements
|
|
16
|
+
|
|
17
|
+
3. **Quality checks**
|
|
18
|
+
- Lint/format check
|
|
19
|
+
- Type checking
|
|
20
|
+
- Security scanning
|
|
21
|
+
|
|
22
|
+
4. **Results reporting**
|
|
23
|
+
- Document test results
|
|
24
|
+
- Flag failures
|
|
25
|
+
- Suggest improvements
|
|
26
|
+
|
|
27
|
+
## Input
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
LOOP CONTEXT:
|
|
31
|
+
- Files to validate
|
|
32
|
+
- Test configuration
|
|
33
|
+
- Coverage requirements
|
|
34
|
+
|
|
35
|
+
PROJECT CONTEXT:
|
|
36
|
+
- Tech stack
|
|
37
|
+
- Test framework
|
|
38
|
+
- CI/CD config
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Execution Steps
|
|
42
|
+
|
|
43
|
+
1. **Prepare environment**
|
|
44
|
+
- Identify test framework
|
|
45
|
+
- Check test configuration
|
|
46
|
+
- Build if needed
|
|
47
|
+
|
|
48
|
+
2. **Run tests**
|
|
49
|
+
- Execute unit tests
|
|
50
|
+
- Execute integration tests
|
|
51
|
+
- Capture results
|
|
52
|
+
|
|
53
|
+
3. **Analyze results**
|
|
54
|
+
- Count passed/failed
|
|
55
|
+
- Measure coverage
|
|
56
|
+
- Identify failure patterns
|
|
57
|
+
|
|
58
|
+
4. **Quality assessment**
|
|
59
|
+
- Check lint results
|
|
60
|
+
- Verify type safety
|
|
61
|
+
- Review security checks
|
|
62
|
+
|
|
63
|
+
5. **Generate report**
|
|
64
|
+
- Document findings
|
|
65
|
+
- Suggest fixes for failures
|
|
66
|
+
- Output recommendations
|
|
67
|
+
|
|
68
|
+
## Output Format
|
|
69
|
+
|
|
70
|
+
```
|
|
71
|
+
WORKER_RESULT:
|
|
72
|
+
- action: validate
|
|
73
|
+
- status: success | failed | needs_fix
|
|
74
|
+
- summary: "98 tests passed, 2 failed; coverage 85%"
|
|
75
|
+
- files_changed: []
|
|
76
|
+
- next_suggestion: develop (fix failures) | complete (all pass) | debug (investigate)
|
|
77
|
+
- loop_back_to: null
|
|
78
|
+
|
|
79
|
+
TEST_RESULTS:
|
|
80
|
+
unit_tests:
|
|
81
|
+
passed: 98
|
|
82
|
+
failed: 2
|
|
83
|
+
skipped: 0
|
|
84
|
+
duration: "12.5s"
|
|
85
|
+
|
|
86
|
+
integration_tests:
|
|
87
|
+
passed: 15
|
|
88
|
+
failed: 0
|
|
89
|
+
duration: "8.2s"
|
|
90
|
+
|
|
91
|
+
coverage:
|
|
92
|
+
overall: "85%"
|
|
93
|
+
lines: "88%"
|
|
94
|
+
branches: "82%"
|
|
95
|
+
functions: "90%"
|
|
96
|
+
statements: "87%"
|
|
97
|
+
|
|
98
|
+
FAILURES:
|
|
99
|
+
1. Test: "auth.login should reject invalid password"
|
|
100
|
+
Error: "Assertion failed: expected false to equal true"
|
|
101
|
+
Location: "tests/auth.test.ts:45"
|
|
102
|
+
Suggested fix: "Check password validation logic in src/auth.ts"
|
|
103
|
+
|
|
104
|
+
2. Test: "utils.formatDate should handle timezones"
|
|
105
|
+
Error: "Expected 2026-01-22T10:00 but got 2026-01-22T09:00"
|
|
106
|
+
Location: "tests/utils.test.ts:120"
|
|
107
|
+
Suggested fix: "Timezone conversion in formatDate needs UTC adjustment"
|
|
108
|
+
|
|
109
|
+
COVERAGE_GAPS:
|
|
110
|
+
- src/auth.ts (line 45-52): Error handling not covered
|
|
111
|
+
- src/utils.ts (line 100-105): Edge case handling missing
|
|
112
|
+
|
|
113
|
+
QUALITY_CHECKS:
|
|
114
|
+
lint: ✓ Passed (0 errors)
|
|
115
|
+
types: ✓ Passed (no type errors)
|
|
116
|
+
security: ✓ Passed (0 vulnerabilities)
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Progress File Template
|
|
120
|
+
|
|
121
|
+
```markdown
|
|
122
|
+
# Validate Progress - {timestamp}
|
|
123
|
+
|
|
124
|
+
## Test Execution Summary
|
|
125
|
+
|
|
126
|
+
### Unit Tests ✓
|
|
127
|
+
- **98 passed**, 2 failed, 0 skipped
|
|
128
|
+
- **Duration**: 12.5s
|
|
129
|
+
- **Status**: Needs fix
|
|
130
|
+
|
|
131
|
+
### Integration Tests ✓
|
|
132
|
+
- **15 passed**, 0 failed
|
|
133
|
+
- **Duration**: 8.2s
|
|
134
|
+
- **Status**: All pass
|
|
135
|
+
|
|
136
|
+
## Coverage Report
|
|
137
|
+
|
|
138
|
+
```
|
|
139
|
+
Statements : 87% ( 130/150 )
|
|
140
|
+
Branches : 82% ( 41/50 )
|
|
141
|
+
Functions : 90% ( 45/50 )
|
|
142
|
+
Lines : 88% ( 132/150 )
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
**Coverage Gaps**:
|
|
146
|
+
- `src/auth.ts` (lines 45-52): Error handling
|
|
147
|
+
- `src/utils.ts` (lines 100-105): Edge cases
|
|
148
|
+
|
|
149
|
+
## Test Failures
|
|
150
|
+
|
|
151
|
+
### Failure 1: auth.login should reject invalid password
|
|
152
|
+
- **Error**: Assertion failed
|
|
153
|
+
- **File**: `tests/auth.test.ts:45`
|
|
154
|
+
- **Root cause**: Password validation not working
|
|
155
|
+
- **Fix**: Check SHA256 hashing in `src/auth.ts:102`
|
|
156
|
+
|
|
157
|
+
### Failure 2: utils.formatDate should handle timezones
|
|
158
|
+
- **Error**: Expected 2026-01-22T10:00 but got 2026-01-22T09:00
|
|
159
|
+
- **File**: `tests/utils.test.ts:120`
|
|
160
|
+
- **Root cause**: UTC offset not applied correctly
|
|
161
|
+
- **Fix**: Update timezone calculation in `formatDate()`
|
|
162
|
+
|
|
163
|
+
## Quality Checks
|
|
164
|
+
|
|
165
|
+
| Check | Result | Status |
|
|
166
|
+
|-------|--------|--------|
|
|
167
|
+
| ESLint | 0 errors | ✓ Pass |
|
|
168
|
+
| TypeScript | No errors | ✓ Pass |
|
|
169
|
+
| Security Audit | 0 vulnerabilities | ✓ Pass |
|
|
170
|
+
|
|
171
|
+
## Recommendations
|
|
172
|
+
|
|
173
|
+
1. **Fix test failures** (2 tests failing)
|
|
174
|
+
2. **Improve coverage** for error handling paths
|
|
175
|
+
3. **Add integration tests** for critical flows
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## Rules
|
|
179
|
+
|
|
180
|
+
- **Run all tests**: Don't skip or filter
|
|
181
|
+
- **Be thorough**: Check coverage and quality metrics
|
|
182
|
+
- **Document failures**: Provide actionable suggestions
|
|
183
|
+
- **Test environment**: Use consistent configuration
|
|
184
|
+
- **No workarounds**: Fix real issues, don't skip tests
|
|
185
|
+
- **Verify fixes**: Re-run after changes
|
|
186
|
+
- **Clean reports**: Output clear, actionable results
|
|
187
|
+
|
|
188
|
+
## Error Handling
|
|
189
|
+
|
|
190
|
+
| Situation | Action |
|
|
191
|
+
|-----------|--------|
|
|
192
|
+
| Test framework not found | Identify from package.json, install if needed |
|
|
193
|
+
| Tests fail | Document failures, suggest fixes |
|
|
194
|
+
| Coverage below threshold | Flag coverage gaps, suggest tests |
|
|
195
|
+
| Build failure | Trace to source, suggest debugging |
|
|
196
|
+
|
|
197
|
+
## Best Practices
|
|
198
|
+
|
|
199
|
+
1. Run complete test suite
|
|
200
|
+
2. Measure coverage thoroughly
|
|
201
|
+
3. Document all failures clearly
|
|
202
|
+
4. Provide specific fix suggestions
|
|
203
|
+
5. Check quality metrics
|
|
204
|
+
6. Suggest follow-up validation steps
|
|
@@ -39,7 +39,7 @@ You are a CCW Loop Executor - a stateless iterative development specialist that
|
|
|
39
39
|
|
|
40
40
|
```javascript
|
|
41
41
|
// Read current state
|
|
42
|
-
const state = JSON.parse(Read('.loop/{loopId}.json'))
|
|
42
|
+
const state = JSON.parse(Read('.workflow/.loop/{loopId}.json'))
|
|
43
43
|
|
|
44
44
|
// Check control signals
|
|
45
45
|
if (state.status === 'paused') {
|
|
@@ -110,7 +110,7 @@ NEXT_ACTION_NEEDED: {action_name} | WAITING_INPUT | COMPLETED | PAUSED
|
|
|
110
110
|
|
|
111
111
|
```javascript
|
|
112
112
|
function updateState(loopId, skillStateUpdates) {
|
|
113
|
-
const state = JSON.parse(Read(`.loop/${loopId}.json`))
|
|
113
|
+
const state = JSON.parse(Read(`.workflow/.loop/${loopId}.json`))
|
|
114
114
|
state.updated_at = getUtc8ISOString()
|
|
115
115
|
state.skill_state = {
|
|
116
116
|
...state.skill_state,
|
|
@@ -118,7 +118,7 @@ function updateState(loopId, skillStateUpdates) {
|
|
|
118
118
|
last_action: currentAction,
|
|
119
119
|
completed_actions: [...state.skill_state.completed_actions, currentAction]
|
|
120
120
|
}
|
|
121
|
-
Write(`.loop/${loopId}.json`, JSON.stringify(state, null, 2))
|
|
121
|
+
Write(`.workflow/.loop/${loopId}.json`, JSON.stringify(state, null, 2))
|
|
122
122
|
}
|
|
123
123
|
```
|
|
124
124
|
|
|
@@ -136,7 +136,7 @@ function updateState(loopId, skillStateUpdates) {
|
|
|
136
136
|
5. Update state with skill_state
|
|
137
137
|
|
|
138
138
|
**Output**:
|
|
139
|
-
- `.loop/{loopId}.progress/develop.md` (initialized)
|
|
139
|
+
- `.workflow/.loop/{loopId}.progress/develop.md` (initialized)
|
|
140
140
|
- State: skill_state populated with tasks
|
|
141
141
|
|
|
142
142
|
### DEVELOP Action
|
|
@@ -0,0 +1,409 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Intelligent code cleanup with mainline detection, stale artifact discovery, and safe execution
|
|
3
|
+
argument-hint: [--dry-run] [FOCUS="<area>"]
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Workflow Clean Command
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
Evidence-based intelligent cleanup command. Systematically identifies stale artifacts through mainline analysis, discovers drift, and safely removes unused sessions, documents, and dead code.
|
|
11
|
+
|
|
12
|
+
**Core workflow**: Detect Mainline → Discover Drift → Confirm → Stage → Execute
|
|
13
|
+
|
|
14
|
+
## Target Cleanup
|
|
15
|
+
|
|
16
|
+
**Focus area**: $FOCUS (or entire project if not specified)
|
|
17
|
+
**Mode**: $ARGUMENTS
|
|
18
|
+
|
|
19
|
+
## Execution Process
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
Phase 0: Initialization
|
|
23
|
+
├─ Parse arguments (--dry-run, FOCUS)
|
|
24
|
+
├─ Setup session folder
|
|
25
|
+
└─ Initialize utility functions
|
|
26
|
+
|
|
27
|
+
Phase 1: Mainline Detection
|
|
28
|
+
├─ Analyze git history (30 days)
|
|
29
|
+
├─ Identify core modules (high commit frequency)
|
|
30
|
+
├─ Map active vs stale branches
|
|
31
|
+
└─ Build mainline profile
|
|
32
|
+
|
|
33
|
+
Phase 2: Drift Discovery (Subagent)
|
|
34
|
+
├─ spawn_agent with cli-explore-agent role
|
|
35
|
+
├─ Scan workflow sessions for orphaned artifacts
|
|
36
|
+
├─ Identify documents drifted from mainline
|
|
37
|
+
├─ Detect dead code and unused exports
|
|
38
|
+
└─ Generate cleanup manifest
|
|
39
|
+
|
|
40
|
+
Phase 3: Confirmation
|
|
41
|
+
├─ Validate manifest schema
|
|
42
|
+
├─ Display cleanup summary by category
|
|
43
|
+
├─ AskUser: Select categories and risk level
|
|
44
|
+
└─ Dry-run exit if --dry-run
|
|
45
|
+
|
|
46
|
+
Phase 4: Execution
|
|
47
|
+
├─ Validate paths (security check)
|
|
48
|
+
├─ Stage deletion (move to .trash)
|
|
49
|
+
├─ Update manifests
|
|
50
|
+
├─ Permanent deletion
|
|
51
|
+
└─ Report results
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Implementation
|
|
55
|
+
|
|
56
|
+
### Phase 0: Initialization
|
|
57
|
+
|
|
58
|
+
```javascript
|
|
59
|
+
const getUtc8ISOString = () => new Date(Date.now() + 8 * 60 * 60 * 1000).toISOString()
|
|
60
|
+
|
|
61
|
+
// Parse arguments
|
|
62
|
+
const args = "$ARGUMENTS"
|
|
63
|
+
const isDryRun = args.includes('--dry-run')
|
|
64
|
+
const focusMatch = args.match(/FOCUS="([^"]+)"/)
|
|
65
|
+
const focusArea = focusMatch ? focusMatch[1] : "$FOCUS" !== "$" + "FOCUS" ? "$FOCUS" : null
|
|
66
|
+
|
|
67
|
+
// Session setup
|
|
68
|
+
const dateStr = getUtc8ISOString().substring(0, 10)
|
|
69
|
+
const sessionId = `clean-${dateStr}`
|
|
70
|
+
const sessionFolder = `.workflow/.clean/${sessionId}`
|
|
71
|
+
const trashFolder = `${sessionFolder}/.trash`
|
|
72
|
+
const projectRoot = process.cwd()
|
|
73
|
+
|
|
74
|
+
bash(`mkdir -p ${sessionFolder}`)
|
|
75
|
+
bash(`mkdir -p ${trashFolder}`)
|
|
76
|
+
|
|
77
|
+
// Utility functions
|
|
78
|
+
function fileExists(p) {
|
|
79
|
+
try { return bash(`test -f "${p}" && echo "yes"`).includes('yes') } catch { return false }
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function dirExists(p) {
|
|
83
|
+
try { return bash(`test -d "${p}" && echo "yes"`).includes('yes') } catch { return false }
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function validatePath(targetPath) {
|
|
87
|
+
if (targetPath.includes('..')) return { valid: false, reason: 'Path traversal' }
|
|
88
|
+
|
|
89
|
+
const allowed = ['.workflow/', '.claude/rules/tech/', 'src/']
|
|
90
|
+
const dangerous = [/^\//, /^C:\\Windows/i, /node_modules/, /\.git$/]
|
|
91
|
+
|
|
92
|
+
if (!allowed.some(p => targetPath.startsWith(p))) {
|
|
93
|
+
return { valid: false, reason: 'Outside allowed directories' }
|
|
94
|
+
}
|
|
95
|
+
if (dangerous.some(p => p.test(targetPath))) {
|
|
96
|
+
return { valid: false, reason: 'Dangerous pattern' }
|
|
97
|
+
}
|
|
98
|
+
return { valid: true }
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
### Phase 1: Mainline Detection
|
|
105
|
+
|
|
106
|
+
```javascript
|
|
107
|
+
// Check git repository
|
|
108
|
+
const isGitRepo = bash('git rev-parse --git-dir 2>/dev/null && echo "yes"').includes('yes')
|
|
109
|
+
|
|
110
|
+
let mainlineProfile = {
|
|
111
|
+
coreModules: [],
|
|
112
|
+
activeFiles: [],
|
|
113
|
+
activeBranches: [],
|
|
114
|
+
staleThreshold: { sessions: 7, branches: 30, documents: 14 },
|
|
115
|
+
isGitRepo,
|
|
116
|
+
timestamp: getUtc8ISOString()
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (isGitRepo) {
|
|
120
|
+
// Commit frequency by directory (last 30 days)
|
|
121
|
+
const freq = bash('git log --since="30 days ago" --name-only --pretty=format: | grep -v "^$" | cut -d/ -f1-2 | sort | uniq -c | sort -rn | head -20')
|
|
122
|
+
|
|
123
|
+
// Parse core modules (>5 commits)
|
|
124
|
+
mainlineProfile.coreModules = freq.trim().split('\n')
|
|
125
|
+
.map(l => l.trim().match(/^(\d+)\s+(.+)$/))
|
|
126
|
+
.filter(m => m && parseInt(m[1]) >= 5)
|
|
127
|
+
.map(m => m[2])
|
|
128
|
+
|
|
129
|
+
// Recent branches
|
|
130
|
+
const branches = bash('git for-each-ref --sort=-committerdate refs/heads/ --format="%(refname:short)" | head -10')
|
|
131
|
+
mainlineProfile.activeBranches = branches.trim().split('\n').filter(Boolean)
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
Write(`${sessionFolder}/mainline-profile.json`, JSON.stringify(mainlineProfile, null, 2))
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
### Phase 2: Drift Discovery
|
|
140
|
+
|
|
141
|
+
```javascript
|
|
142
|
+
let exploreAgent = null
|
|
143
|
+
|
|
144
|
+
try {
|
|
145
|
+
// Launch cli-explore-agent
|
|
146
|
+
exploreAgent = spawn_agent({
|
|
147
|
+
message: `
|
|
148
|
+
## TASK ASSIGNMENT
|
|
149
|
+
|
|
150
|
+
### MANDATORY FIRST STEPS
|
|
151
|
+
1. Read: ~/.codex/agents/cli-explore-agent.md
|
|
152
|
+
2. Read: .workflow/project-tech.json (if exists)
|
|
153
|
+
|
|
154
|
+
## Task Objective
|
|
155
|
+
Discover stale artifacts for cleanup.
|
|
156
|
+
|
|
157
|
+
## Context
|
|
158
|
+
- Session: ${sessionFolder}
|
|
159
|
+
- Focus: ${focusArea || 'entire project'}
|
|
160
|
+
|
|
161
|
+
## Discovery Categories
|
|
162
|
+
|
|
163
|
+
### 1. Stale Workflow Sessions
|
|
164
|
+
Scan: .workflow/active/WFS-*, .workflow/archives/WFS-*, .workflow/.lite-plan/*, .workflow/.debug/DBG-*
|
|
165
|
+
Criteria: No modification >7 days + no related git commits
|
|
166
|
+
|
|
167
|
+
### 2. Drifted Documents
|
|
168
|
+
Scan: .claude/rules/tech/*, .workflow/.scratchpad/*
|
|
169
|
+
Criteria: >30% broken references to non-existent files
|
|
170
|
+
|
|
171
|
+
### 3. Dead Code
|
|
172
|
+
Scan: Unused exports, orphan files (not imported anywhere)
|
|
173
|
+
Criteria: No importers in import graph
|
|
174
|
+
|
|
175
|
+
## Output
|
|
176
|
+
Write to: ${sessionFolder}/cleanup-manifest.json
|
|
177
|
+
|
|
178
|
+
Format:
|
|
179
|
+
{
|
|
180
|
+
"generated_at": "ISO",
|
|
181
|
+
"discoveries": {
|
|
182
|
+
"stale_sessions": [{ "path": "...", "age_days": N, "reason": "...", "risk": "low|medium|high" }],
|
|
183
|
+
"drifted_documents": [{ "path": "...", "drift_percentage": N, "reason": "...", "risk": "..." }],
|
|
184
|
+
"dead_code": [{ "path": "...", "type": "orphan_file", "reason": "...", "risk": "..." }]
|
|
185
|
+
},
|
|
186
|
+
"summary": { "total_items": N, "by_category": {...}, "by_risk": {...} }
|
|
187
|
+
}
|
|
188
|
+
`
|
|
189
|
+
})
|
|
190
|
+
|
|
191
|
+
// Wait with timeout handling
|
|
192
|
+
let result = wait({ ids: [exploreAgent], timeout_ms: 600000 })
|
|
193
|
+
|
|
194
|
+
if (result.timed_out) {
|
|
195
|
+
send_input({ id: exploreAgent, message: 'Complete now and write cleanup-manifest.json.' })
|
|
196
|
+
result = wait({ ids: [exploreAgent], timeout_ms: 300000 })
|
|
197
|
+
if (result.timed_out) throw new Error('Agent timeout')
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (!fileExists(`${sessionFolder}/cleanup-manifest.json`)) {
|
|
201
|
+
throw new Error('Manifest not generated')
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
} finally {
|
|
205
|
+
if (exploreAgent) close_agent({ id: exploreAgent })
|
|
206
|
+
}
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
### Phase 3: Confirmation
|
|
212
|
+
|
|
213
|
+
```javascript
|
|
214
|
+
// Load and validate manifest
|
|
215
|
+
const manifest = JSON.parse(Read(`${sessionFolder}/cleanup-manifest.json`))
|
|
216
|
+
|
|
217
|
+
// Display summary
|
|
218
|
+
console.log(`
|
|
219
|
+
## Cleanup Discovery Report
|
|
220
|
+
|
|
221
|
+
| Category | Count | Risk |
|
|
222
|
+
|----------|-------|------|
|
|
223
|
+
| Sessions | ${manifest.summary.by_category.stale_sessions} | ${getRiskSummary('sessions')} |
|
|
224
|
+
| Documents | ${manifest.summary.by_category.drifted_documents} | ${getRiskSummary('documents')} |
|
|
225
|
+
| Dead Code | ${manifest.summary.by_category.dead_code} | ${getRiskSummary('code')} |
|
|
226
|
+
|
|
227
|
+
**Total**: ${manifest.summary.total_items} items
|
|
228
|
+
`)
|
|
229
|
+
|
|
230
|
+
// Dry-run exit
|
|
231
|
+
if (isDryRun) {
|
|
232
|
+
console.log(`
|
|
233
|
+
**Dry-run mode**: No changes made.
|
|
234
|
+
Manifest: ${sessionFolder}/cleanup-manifest.json
|
|
235
|
+
`)
|
|
236
|
+
return
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// User confirmation
|
|
240
|
+
const selection = AskUser({
|
|
241
|
+
questions: [
|
|
242
|
+
{
|
|
243
|
+
question: "Which categories to clean?",
|
|
244
|
+
header: "Categories",
|
|
245
|
+
multiSelect: true,
|
|
246
|
+
options: [
|
|
247
|
+
{ label: "Sessions", description: `${manifest.summary.by_category.stale_sessions} stale sessions` },
|
|
248
|
+
{ label: "Documents", description: `${manifest.summary.by_category.drifted_documents} drifted docs` },
|
|
249
|
+
{ label: "Dead Code", description: `${manifest.summary.by_category.dead_code} unused files` }
|
|
250
|
+
]
|
|
251
|
+
},
|
|
252
|
+
{
|
|
253
|
+
question: "Risk level?",
|
|
254
|
+
header: "Risk",
|
|
255
|
+
options: [
|
|
256
|
+
{ label: "Low only", description: "Safest (Recommended)" },
|
|
257
|
+
{ label: "Low + Medium", description: "Includes likely unused" },
|
|
258
|
+
{ label: "All", description: "Aggressive" }
|
|
259
|
+
]
|
|
260
|
+
}
|
|
261
|
+
]
|
|
262
|
+
})
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
---
|
|
266
|
+
|
|
267
|
+
### Phase 4: Execution
|
|
268
|
+
|
|
269
|
+
```javascript
|
|
270
|
+
const riskFilter = {
|
|
271
|
+
'Low only': ['low'],
|
|
272
|
+
'Low + Medium': ['low', 'medium'],
|
|
273
|
+
'All': ['low', 'medium', 'high']
|
|
274
|
+
}[selection.risk]
|
|
275
|
+
|
|
276
|
+
// Collect items to clean
|
|
277
|
+
const items = []
|
|
278
|
+
if (selection.categories.includes('Sessions')) {
|
|
279
|
+
items.push(...manifest.discoveries.stale_sessions.filter(s => riskFilter.includes(s.risk)))
|
|
280
|
+
}
|
|
281
|
+
if (selection.categories.includes('Documents')) {
|
|
282
|
+
items.push(...manifest.discoveries.drifted_documents.filter(d => riskFilter.includes(d.risk)))
|
|
283
|
+
}
|
|
284
|
+
if (selection.categories.includes('Dead Code')) {
|
|
285
|
+
items.push(...manifest.discoveries.dead_code.filter(c => riskFilter.includes(c.risk)))
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
const results = { staged: [], deleted: [], failed: [], skipped: [] }
|
|
289
|
+
|
|
290
|
+
// Validate and stage
|
|
291
|
+
for (const item of items) {
|
|
292
|
+
const validation = validatePath(item.path)
|
|
293
|
+
if (!validation.valid) {
|
|
294
|
+
results.skipped.push({ path: item.path, reason: validation.reason })
|
|
295
|
+
continue
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
if (!fileExists(item.path) && !dirExists(item.path)) {
|
|
299
|
+
results.skipped.push({ path: item.path, reason: 'Not found' })
|
|
300
|
+
continue
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
try {
|
|
304
|
+
const trashTarget = `${trashFolder}/${item.path.replace(/\//g, '_')}`
|
|
305
|
+
bash(`mv "${item.path}" "${trashTarget}"`)
|
|
306
|
+
results.staged.push({ path: item.path, trashPath: trashTarget })
|
|
307
|
+
} catch (e) {
|
|
308
|
+
results.failed.push({ path: item.path, error: e.message })
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
// Permanent deletion
|
|
313
|
+
for (const staged of results.staged) {
|
|
314
|
+
try {
|
|
315
|
+
bash(`rm -rf "${staged.trashPath}"`)
|
|
316
|
+
results.deleted.push(staged.path)
|
|
317
|
+
} catch (e) {
|
|
318
|
+
console.error(`Failed: ${staged.path}`)
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// Cleanup empty trash
|
|
323
|
+
bash(`rmdir "${trashFolder}" 2>/dev/null || true`)
|
|
324
|
+
|
|
325
|
+
// Report
|
|
326
|
+
console.log(`
|
|
327
|
+
## Cleanup Complete
|
|
328
|
+
|
|
329
|
+
**Deleted**: ${results.deleted.length}
|
|
330
|
+
**Failed**: ${results.failed.length}
|
|
331
|
+
**Skipped**: ${results.skipped.length}
|
|
332
|
+
|
|
333
|
+
### Deleted
|
|
334
|
+
${results.deleted.map(p => `- ${p}`).join('\n') || '(none)'}
|
|
335
|
+
|
|
336
|
+
${results.failed.length > 0 ? `### Failed\n${results.failed.map(f => `- ${f.path}: ${f.error}`).join('\n')}` : ''}
|
|
337
|
+
|
|
338
|
+
Report: ${sessionFolder}/cleanup-report.json
|
|
339
|
+
`)
|
|
340
|
+
|
|
341
|
+
Write(`${sessionFolder}/cleanup-report.json`, JSON.stringify({
|
|
342
|
+
timestamp: getUtc8ISOString(),
|
|
343
|
+
results,
|
|
344
|
+
summary: {
|
|
345
|
+
deleted: results.deleted.length,
|
|
346
|
+
failed: results.failed.length,
|
|
347
|
+
skipped: results.skipped.length
|
|
348
|
+
}
|
|
349
|
+
}, null, 2))
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
---
|
|
353
|
+
|
|
354
|
+
## Session Folder
|
|
355
|
+
|
|
356
|
+
```
|
|
357
|
+
.workflow/.clean/clean-{YYYY-MM-DD}/
|
|
358
|
+
├── mainline-profile.json # Git history analysis
|
|
359
|
+
├── cleanup-manifest.json # Discovery results
|
|
360
|
+
├── cleanup-report.json # Execution results
|
|
361
|
+
└── .trash/ # Staging area (temporary)
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
## Risk Levels
|
|
365
|
+
|
|
366
|
+
| Risk | Description | Examples |
|
|
367
|
+
|------|-------------|----------|
|
|
368
|
+
| **Low** | Safe to delete | Empty sessions, scratchpad files |
|
|
369
|
+
| **Medium** | Likely unused | Orphan files, old archives |
|
|
370
|
+
| **High** | May have dependencies | Files with some imports |
|
|
371
|
+
|
|
372
|
+
## Security Features
|
|
373
|
+
|
|
374
|
+
| Feature | Protection |
|
|
375
|
+
|---------|------------|
|
|
376
|
+
| Path Validation | Whitelist directories, reject traversal |
|
|
377
|
+
| Staged Deletion | Move to .trash before permanent delete |
|
|
378
|
+
| Dangerous Patterns | Block system dirs, node_modules, .git |
|
|
379
|
+
|
|
380
|
+
## Iteration Flow
|
|
381
|
+
|
|
382
|
+
```
|
|
383
|
+
First Call (/prompts:clean):
|
|
384
|
+
├─ Detect mainline from git history
|
|
385
|
+
├─ Discover stale artifacts via subagent
|
|
386
|
+
├─ Display summary, await user selection
|
|
387
|
+
└─ Execute cleanup with staging
|
|
388
|
+
|
|
389
|
+
Dry-Run (/prompts:clean --dry-run):
|
|
390
|
+
├─ All phases except execution
|
|
391
|
+
└─ Manifest saved for review
|
|
392
|
+
|
|
393
|
+
Focused (/prompts:clean FOCUS="auth"):
|
|
394
|
+
└─ Discovery limited to specified area
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
## Error Handling
|
|
398
|
+
|
|
399
|
+
| Situation | Action |
|
|
400
|
+
|-----------|--------|
|
|
401
|
+
| No git repo | Use file timestamps only |
|
|
402
|
+
| Agent timeout | Retry once with prompt, then abort |
|
|
403
|
+
| Path validation fail | Skip item, report reason |
|
|
404
|
+
| Manifest parse error | Abort with error |
|
|
405
|
+
| Empty discovery | Report "codebase is clean" |
|
|
406
|
+
|
|
407
|
+
---
|
|
408
|
+
|
|
409
|
+
**Now execute cleanup workflow** with focus: $FOCUS
|
|
@@ -68,7 +68,7 @@ Files are in `.codex/skills/ccw-loop/`:
|
|
|
68
68
|
|
|
69
69
|
```
|
|
70
70
|
1. Parse arguments (task or --loop-id)
|
|
71
|
-
2. Create/read state from .loop/{loopId}.json
|
|
71
|
+
2. Create/read state from .workflow/.loop/{loopId}.json
|
|
72
72
|
3. spawn_agent with ccw-loop-executor role
|
|
73
73
|
4. Main loop:
|
|
74
74
|
a. wait() for agent output
|
|
@@ -84,7 +84,7 @@ Files are in `.codex/skills/ccw-loop/`:
|
|
|
84
84
|
## Session Files
|
|
85
85
|
|
|
86
86
|
```
|
|
87
|
-
.loop/
|
|
87
|
+
.workflow/.loop/
|
|
88
88
|
+-- {loopId}.json # Master state (API + Skill)
|
|
89
89
|
+-- {loopId}.progress/
|
|
90
90
|
+-- develop.md # Development timeline
|
|
@@ -157,7 +157,7 @@ spawn_agent({
|
|
|
157
157
|
Works with CCW Dashboard Loop Monitor:
|
|
158
158
|
- Dashboard creates loop via API
|
|
159
159
|
- API triggers this skill with `--loop-id`
|
|
160
|
-
- Skill reads/writes `.loop/{loopId}.json`
|
|
160
|
+
- Skill reads/writes `.workflow/.loop/{loopId}.json`
|
|
161
161
|
- Dashboard polls state for real-time updates
|
|
162
162
|
|
|
163
163
|
### Control Signals
|