claude-code-workflow 6.3.37 → 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.
Files changed (173) hide show
  1. package/.claude/commands/workflow/lite-execute.md +2 -0
  2. package/.codex/agents/action-planning-agent.md +885 -0
  3. package/.codex/agents/ccw-loop-b-complete.md +227 -0
  4. package/.codex/agents/ccw-loop-b-debug.md +172 -0
  5. package/.codex/agents/ccw-loop-b-develop.md +147 -0
  6. package/.codex/agents/ccw-loop-b-init.md +82 -0
  7. package/.codex/agents/ccw-loop-b-validate.md +204 -0
  8. package/.codex/agents/ccw-loop-executor.md +260 -0
  9. package/.codex/agents/cli-discuss-agent.md +391 -0
  10. package/.codex/agents/cli-execution-agent.md +333 -0
  11. package/.codex/agents/cli-explore-agent.md +186 -0
  12. package/.codex/agents/cli-lite-planning-agent.md +736 -0
  13. package/.codex/agents/cli-planning-agent.md +562 -0
  14. package/.codex/agents/code-developer.md +408 -0
  15. package/.codex/agents/conceptual-planning-agent.md +321 -0
  16. package/.codex/agents/context-search-agent.md +585 -0
  17. package/.codex/agents/debug-explore-agent.md +436 -0
  18. package/.codex/agents/doc-generator.md +334 -0
  19. package/.codex/agents/issue-plan-agent.md +417 -0
  20. package/.codex/agents/issue-queue-agent.md +311 -0
  21. package/.codex/agents/memory-bridge.md +96 -0
  22. package/.codex/agents/test-context-search-agent.md +402 -0
  23. package/.codex/agents/test-fix-agent.md +359 -0
  24. package/.codex/agents/ui-design-agent.md +595 -0
  25. package/.codex/agents/universal-executor.md +135 -0
  26. package/.codex/prompts/clean.md +409 -0
  27. package/.codex/prompts/issue-discover-by-prompt.md +364 -0
  28. package/.codex/prompts/issue-discover.md +261 -0
  29. package/.codex/prompts/issue-execute.md +10 -0
  30. package/.codex/prompts/issue-new.md +285 -0
  31. package/.codex/prompts/issue-plan.md +161 -63
  32. package/.codex/prompts/issue-queue.md +298 -288
  33. package/.codex/prompts/lite-execute.md +627 -133
  34. package/.codex/prompts/lite-fix.md +670 -0
  35. package/.codex/prompts/lite-plan-a.md +337 -0
  36. package/.codex/prompts/lite-plan-b.md +485 -0
  37. package/.codex/prompts/{lite-plan.md → lite-plan-c.md} +601 -469
  38. package/.codex/skills/ccw-loop/README.md +171 -0
  39. package/.codex/skills/ccw-loop/SKILL.md +349 -0
  40. package/.codex/skills/ccw-loop/phases/actions/action-complete.md +269 -0
  41. package/.codex/skills/ccw-loop/phases/actions/action-debug.md +286 -0
  42. package/.codex/skills/ccw-loop/phases/actions/action-develop.md +183 -0
  43. package/.codex/skills/ccw-loop/phases/actions/action-init.md +164 -0
  44. package/.codex/skills/ccw-loop/phases/actions/action-menu.md +205 -0
  45. package/.codex/skills/ccw-loop/phases/actions/action-validate.md +250 -0
  46. package/.codex/skills/ccw-loop/phases/orchestrator.md +416 -0
  47. package/.codex/skills/ccw-loop/phases/state-schema.md +388 -0
  48. package/.codex/skills/ccw-loop/specs/action-catalog.md +182 -0
  49. package/.codex/skills/ccw-loop-b/README.md +301 -0
  50. package/.codex/skills/ccw-loop-b/SKILL.md +322 -0
  51. package/.codex/skills/ccw-loop-b/phases/orchestrator.md +257 -0
  52. package/.codex/skills/ccw-loop-b/phases/state-schema.md +181 -0
  53. package/.codex/skills/ccw-loop-b/specs/action-catalog.md +383 -0
  54. package/.codex/skills/parallel-dev-cycle/README.md +382 -0
  55. package/.codex/skills/parallel-dev-cycle/SKILL.md +512 -0
  56. package/.codex/skills/parallel-dev-cycle/phases/agents/code-developer.md +242 -0
  57. package/.codex/skills/parallel-dev-cycle/phases/agents/exploration-planner.md +285 -0
  58. package/.codex/skills/parallel-dev-cycle/phases/agents/requirements-analyst.md +285 -0
  59. package/.codex/skills/parallel-dev-cycle/phases/agents/validation-archivist.md +381 -0
  60. package/.codex/skills/parallel-dev-cycle/phases/orchestrator.md +696 -0
  61. package/.codex/skills/parallel-dev-cycle/phases/state-schema.md +436 -0
  62. package/.codex/skills/parallel-dev-cycle/specs/communication-optimization.md +423 -0
  63. package/.codex/skills/parallel-dev-cycle/specs/coordination-protocol.md +391 -0
  64. package/.codex/skills/parallel-dev-cycle/specs/versioning-strategy.md +330 -0
  65. package/ccw/dist/cli.d.ts.map +1 -1
  66. package/ccw/dist/cli.js +4 -0
  67. package/ccw/dist/cli.js.map +1 -1
  68. package/ccw/dist/commands/install.d.ts.map +1 -1
  69. package/ccw/dist/commands/install.js +39 -8
  70. package/ccw/dist/commands/install.js.map +1 -1
  71. package/ccw/dist/commands/issue.d.ts +3 -0
  72. package/ccw/dist/commands/issue.d.ts.map +1 -1
  73. package/ccw/dist/commands/issue.js +107 -0
  74. package/ccw/dist/commands/issue.js.map +1 -1
  75. package/ccw/dist/commands/upgrade.js +1 -1
  76. package/ccw/dist/commands/upgrade.js.map +1 -1
  77. package/ccw/dist/config/litellm-api-config-manager.d.ts.map +1 -1
  78. package/ccw/dist/config/litellm-api-config-manager.js +3 -2
  79. package/ccw/dist/config/litellm-api-config-manager.js.map +1 -1
  80. package/ccw/dist/core/memory-embedder-bridge.d.ts.map +1 -1
  81. package/ccw/dist/core/memory-embedder-bridge.js +2 -5
  82. package/ccw/dist/core/memory-embedder-bridge.js.map +1 -1
  83. package/ccw/dist/core/routes/cli-routes.js.map +1 -1
  84. package/ccw/dist/core/routes/codexlens/config-handlers.d.ts.map +1 -1
  85. package/ccw/dist/core/routes/codexlens/config-handlers.js +7 -6
  86. package/ccw/dist/core/routes/codexlens/config-handlers.js.map +1 -1
  87. package/ccw/dist/core/routes/codexlens/semantic-handlers.d.ts.map +1 -1
  88. package/ccw/dist/core/routes/codexlens/semantic-handlers.js +2 -2
  89. package/ccw/dist/core/routes/codexlens/semantic-handlers.js.map +1 -1
  90. package/ccw/dist/core/routes/graph-routes.d.ts.map +1 -1
  91. package/ccw/dist/core/routes/graph-routes.js +17 -2
  92. package/ccw/dist/core/routes/graph-routes.js.map +1 -1
  93. package/ccw/dist/core/routes/issue-routes.d.ts.map +1 -1
  94. package/ccw/dist/core/routes/issue-routes.js +280 -33
  95. package/ccw/dist/core/routes/issue-routes.js.map +1 -1
  96. package/ccw/dist/core/routes/loop-v2-routes.d.ts +9 -0
  97. package/ccw/dist/core/routes/loop-v2-routes.d.ts.map +1 -1
  98. package/ccw/dist/core/routes/loop-v2-routes.js +56 -4
  99. package/ccw/dist/core/routes/loop-v2-routes.js.map +1 -1
  100. package/ccw/dist/core/routes/system-routes.d.ts.map +1 -1
  101. package/ccw/dist/core/routes/system-routes.js +3 -2
  102. package/ccw/dist/core/routes/system-routes.js.map +1 -1
  103. package/ccw/dist/core/server.d.ts.map +1 -1
  104. package/ccw/dist/core/server.js +5 -3
  105. package/ccw/dist/core/server.js.map +1 -1
  106. package/ccw/dist/tools/claude-cli-tools.d.ts.map +1 -1
  107. package/ccw/dist/tools/claude-cli-tools.js +4 -3
  108. package/ccw/dist/tools/claude-cli-tools.js.map +1 -1
  109. package/ccw/dist/tools/cli-config-manager.d.ts +1 -0
  110. package/ccw/dist/tools/cli-config-manager.d.ts.map +1 -1
  111. package/ccw/dist/tools/cli-config-manager.js +2 -1
  112. package/ccw/dist/tools/cli-config-manager.js.map +1 -1
  113. package/ccw/dist/tools/codex-lens-lsp.d.ts.map +1 -1
  114. package/ccw/dist/tools/codex-lens-lsp.js +2 -5
  115. package/ccw/dist/tools/codex-lens-lsp.js.map +1 -1
  116. package/ccw/dist/tools/codex-lens.d.ts.map +1 -1
  117. package/ccw/dist/tools/codex-lens.js +22 -32
  118. package/ccw/dist/tools/codex-lens.js.map +1 -1
  119. package/ccw/dist/tools/litellm-client.d.ts +6 -0
  120. package/ccw/dist/tools/litellm-client.d.ts.map +1 -1
  121. package/ccw/dist/tools/litellm-client.js +15 -2
  122. package/ccw/dist/tools/litellm-client.js.map +1 -1
  123. package/ccw/dist/tools/loop-task-manager.d.ts +13 -2
  124. package/ccw/dist/tools/loop-task-manager.d.ts.map +1 -1
  125. package/ccw/dist/tools/loop-task-manager.js.map +1 -1
  126. package/ccw/dist/tools/native-session-discovery.d.ts.map +1 -1
  127. package/ccw/dist/tools/native-session-discovery.js +35 -7
  128. package/ccw/dist/tools/native-session-discovery.js.map +1 -1
  129. package/ccw/dist/utils/codexlens-path.d.ts +36 -0
  130. package/ccw/dist/utils/codexlens-path.d.ts.map +1 -0
  131. package/ccw/dist/utils/codexlens-path.js +56 -0
  132. package/ccw/dist/utils/codexlens-path.js.map +1 -0
  133. package/ccw/dist/utils/uv-manager.d.ts.map +1 -1
  134. package/ccw/dist/utils/uv-manager.js +3 -2
  135. package/ccw/dist/utils/uv-manager.js.map +1 -1
  136. package/ccw/src/cli.ts +4 -0
  137. package/ccw/src/commands/install.ts +51 -8
  138. package/ccw/src/commands/issue.ts +119 -0
  139. package/ccw/src/commands/upgrade.ts +1 -1
  140. package/ccw/src/config/litellm-api-config-manager.ts +3 -2
  141. package/ccw/src/core/memory-embedder-bridge.ts +2 -6
  142. package/ccw/src/core/routes/cli-routes.ts +1 -1
  143. package/ccw/src/core/routes/codexlens/config-handlers.ts +7 -6
  144. package/ccw/src/core/routes/codexlens/semantic-handlers.ts +2 -2
  145. package/ccw/src/core/routes/graph-routes.ts +18 -2
  146. package/ccw/src/core/routes/issue-routes.ts +308 -33
  147. package/ccw/src/core/routes/loop-v2-routes.ts +64 -6
  148. package/ccw/src/core/routes/system-routes.ts +3 -2
  149. package/ccw/src/core/server.ts +6 -3
  150. package/ccw/src/templates/dashboard-css/02-session.css +2 -0
  151. package/ccw/src/templates/dashboard-css/04-lite-tasks.css +103 -1
  152. package/ccw/src/templates/dashboard-css/32-issue-manager.css +32 -0
  153. package/ccw/src/templates/dashboard-js/components/cli-history.js +48 -48
  154. package/ccw/src/templates/dashboard-js/components/navigation.js +6 -0
  155. package/ccw/src/templates/dashboard-js/components/notifications.js +6 -0
  156. package/ccw/src/templates/dashboard-js/components/version-check.js +38 -0
  157. package/ccw/src/templates/dashboard-js/i18n.js +126 -0
  158. package/ccw/src/templates/dashboard-js/state.js +2 -0
  159. package/ccw/src/templates/dashboard-js/views/cli-manager.js +1 -1
  160. package/ccw/src/templates/dashboard-js/views/issue-manager.js +183 -1
  161. package/ccw/src/templates/dashboard-js/views/lite-tasks.js +55 -11
  162. package/ccw/src/templates/dashboard-js/views/loop-monitor.js +112 -11
  163. package/ccw/src/templates/dashboard.html +48 -2
  164. package/ccw/src/tools/claude-cli-tools.ts +4 -3
  165. package/ccw/src/tools/cli-config-manager.ts +3 -1
  166. package/ccw/src/tools/codex-lens-lsp.ts +2 -5
  167. package/ccw/src/tools/codex-lens.ts +27 -38
  168. package/ccw/src/tools/litellm-client.ts +16 -2
  169. package/ccw/src/tools/loop-task-manager.ts +13 -2
  170. package/ccw/src/tools/native-session-discovery.ts +38 -7
  171. package/ccw/src/utils/codexlens-path.ts +60 -0
  172. package/ccw/src/utils/uv-manager.ts +3 -2
  173. package/package.json +1 -1
@@ -0,0 +1,250 @@
1
+ # Action: VALIDATE
2
+
3
+ Run tests and verify implementation, record results to validate.md.
4
+
5
+ ## Purpose
6
+
7
+ - Run unit tests
8
+ - Run integration tests
9
+ - Check code coverage
10
+ - Generate validation report
11
+ - Determine pass/fail status
12
+
13
+ ## Preconditions
14
+
15
+ - [ ] state.status === 'running'
16
+ - [ ] state.skill_state !== null
17
+ - [ ] (develop.completed > 0) OR (debug.confirmed_hypothesis !== null)
18
+
19
+ ## Execution Steps
20
+
21
+ ### Step 1: Verify Control Signals
22
+
23
+ ```javascript
24
+ const state = JSON.parse(Read(`.workflow/.loop/${loopId}.json`))
25
+
26
+ if (state.status !== 'running') {
27
+ return {
28
+ action: 'VALIDATE',
29
+ status: 'failed',
30
+ message: `Cannot validate: status is ${state.status}`,
31
+ next_action: state.status === 'paused' ? 'PAUSED' : 'STOPPED'
32
+ }
33
+ }
34
+ ```
35
+
36
+ ### Step 2: Detect Test Framework
37
+
38
+ ```javascript
39
+ const packageJson = JSON.parse(Read('package.json') || '{}')
40
+ const testScript = packageJson.scripts?.test || 'npm test'
41
+ const coverageScript = packageJson.scripts?.['test:coverage']
42
+ ```
43
+
44
+ ### Step 3: Run Tests
45
+
46
+ ```javascript
47
+ const testResult = await Bash({
48
+ command: testScript,
49
+ timeout: 300000 // 5 minutes
50
+ })
51
+
52
+ // Parse test output based on framework
53
+ const testResults = parseTestOutput(testResult.stdout, testResult.stderr)
54
+ ```
55
+
56
+ ### Step 4: Run Coverage (if available)
57
+
58
+ ```javascript
59
+ let coverageData = null
60
+
61
+ if (coverageScript) {
62
+ const coverageResult = await Bash({
63
+ command: coverageScript,
64
+ timeout: 300000
65
+ })
66
+
67
+ coverageData = parseCoverageReport(coverageResult.stdout)
68
+ Write(`${progressDir}/coverage.json`, JSON.stringify(coverageData, null, 2))
69
+ }
70
+ ```
71
+
72
+ ### Step 5: Generate Validation Report
73
+
74
+ ```javascript
75
+ const timestamp = getUtc8ISOString()
76
+ const iteration = (state.skill_state.validate.test_results?.length || 0) + 1
77
+
78
+ const validationReport = `# Validation Report
79
+
80
+ **Loop ID**: ${loopId}
81
+ **Task**: ${state.description}
82
+ **Validated**: ${timestamp}
83
+
84
+ ---
85
+
86
+ ## Iteration ${iteration} - Validation Run
87
+
88
+ ### Test Execution Summary
89
+
90
+ | Metric | Value |
91
+ |--------|-------|
92
+ | Total Tests | ${testResults.total} |
93
+ | Passed | ${testResults.passed} |
94
+ | Failed | ${testResults.failed} |
95
+ | Skipped | ${testResults.skipped} |
96
+ | Duration | ${testResults.duration_ms}ms |
97
+ | **Pass Rate** | **${((testResults.passed / testResults.total) * 100).toFixed(1)}%** |
98
+
99
+ ### Coverage Report
100
+
101
+ ${coverageData ? `
102
+ | File | Statements | Branches | Functions | Lines |
103
+ |------|------------|----------|-----------|-------|
104
+ ${coverageData.files.map(f => `| ${f.path} | ${f.statements}% | ${f.branches}% | ${f.functions}% | ${f.lines}% |`).join('\n')}
105
+
106
+ **Overall Coverage**: ${coverageData.overall.statements}%
107
+ ` : '_No coverage data available_'}
108
+
109
+ ### Failed Tests
110
+
111
+ ${testResults.failed > 0 ? testResults.failures.map(f => `
112
+ #### ${f.test_name}
113
+
114
+ - **Suite**: ${f.suite}
115
+ - **Error**: ${f.error_message}
116
+ `).join('\n') : '_All tests passed_'}
117
+
118
+ ---
119
+
120
+ ## Validation Decision
121
+
122
+ **Result**: ${testResults.failed === 0 ? 'PASS' : 'FAIL'}
123
+
124
+ ${testResults.failed > 0 ? `
125
+ ### Next Actions
126
+
127
+ 1. Review failed tests
128
+ 2. Debug failures using DEBUG action
129
+ 3. Fix issues and re-run validation
130
+ ` : `
131
+ ### Next Actions
132
+
133
+ 1. Consider code review
134
+ 2. Complete loop
135
+ `}
136
+ `
137
+
138
+ Write(`${progressDir}/validate.md`, validationReport)
139
+ ```
140
+
141
+ ### Step 6: Save Test Results
142
+
143
+ ```javascript
144
+ const testResultsData = {
145
+ iteration,
146
+ timestamp,
147
+ summary: {
148
+ total: testResults.total,
149
+ passed: testResults.passed,
150
+ failed: testResults.failed,
151
+ skipped: testResults.skipped,
152
+ pass_rate: ((testResults.passed / testResults.total) * 100).toFixed(1),
153
+ duration_ms: testResults.duration_ms
154
+ },
155
+ tests: testResults.tests,
156
+ failures: testResults.failures,
157
+ coverage: coverageData?.overall || null
158
+ }
159
+
160
+ Write(`${progressDir}/test-results.json`, JSON.stringify(testResultsData, null, 2))
161
+ ```
162
+
163
+ ### Step 7: Update State
164
+
165
+ ```javascript
166
+ const validationPassed = testResults.failed === 0 && testResults.passed > 0
167
+
168
+ state.skill_state.validate.test_results.push(testResultsData)
169
+ state.skill_state.validate.pass_rate = parseFloat(testResultsData.summary.pass_rate)
170
+ state.skill_state.validate.coverage = coverageData?.overall?.statements || 0
171
+ state.skill_state.validate.passed = validationPassed
172
+ state.skill_state.validate.failed_tests = testResults.failures.map(f => f.test_name)
173
+ state.skill_state.validate.last_run_at = timestamp
174
+
175
+ state.skill_state.last_action = 'VALIDATE'
176
+ state.updated_at = timestamp
177
+ Write(`.workflow/.loop/${loopId}.json`, JSON.stringify(state, null, 2))
178
+ ```
179
+
180
+ ## Output Format
181
+
182
+ ```
183
+ ACTION_RESULT:
184
+ - action: VALIDATE
185
+ - status: success
186
+ - message: Validation {PASSED | FAILED} - {pass_count}/{total_count} tests passed
187
+ - state_updates: {
188
+ "validate.passed": {true | false},
189
+ "validate.pass_rate": {N},
190
+ "validate.failed_tests": [{list}]
191
+ }
192
+
193
+ FILES_UPDATED:
194
+ - .workflow/.loop/{loopId}.progress/validate.md: Validation report created
195
+ - .workflow/.loop/{loopId}.progress/test-results.json: Test results saved
196
+ - .workflow/.loop/{loopId}.progress/coverage.json: Coverage data saved (if available)
197
+
198
+ NEXT_ACTION_NEEDED: {COMPLETE | DEBUG | DEVELOP | MENU}
199
+ ```
200
+
201
+ ## Next Action Selection
202
+
203
+ ```javascript
204
+ if (validationPassed) {
205
+ const pendingTasks = state.skill_state.develop.tasks.filter(t => t.status === 'pending')
206
+ if (pendingTasks.length === 0) {
207
+ return 'COMPLETE'
208
+ } else {
209
+ return 'DEVELOP'
210
+ }
211
+ } else {
212
+ // Tests failed - need debugging
213
+ return 'DEBUG'
214
+ }
215
+ ```
216
+
217
+ ## Test Output Parsers
218
+
219
+ ### Jest/Vitest Parser
220
+
221
+ ```javascript
222
+ function parseJestOutput(stdout) {
223
+ const summaryMatch = stdout.match(/Tests:\s+(\d+)\s+passed.*?(\d+)\s+failed.*?(\d+)\s+total/)
224
+ // ... implementation
225
+ }
226
+ ```
227
+
228
+ ### Pytest Parser
229
+
230
+ ```javascript
231
+ function parsePytestOutput(stdout) {
232
+ const summaryMatch = stdout.match(/(\d+)\s+passed.*?(\d+)\s+failed/)
233
+ // ... implementation
234
+ }
235
+ ```
236
+
237
+ ## Error Handling
238
+
239
+ | Error Type | Recovery |
240
+ |------------|----------|
241
+ | Tests don't run | Check test script config, report error |
242
+ | All tests fail | Suggest DEBUG action |
243
+ | Coverage tool missing | Skip coverage, run tests only |
244
+ | Timeout | Increase timeout or split tests |
245
+
246
+ ## Next Actions
247
+
248
+ - Validation passed, no pending: `COMPLETE`
249
+ - Validation passed, has pending: `DEVELOP`
250
+ - Validation failed: `DEBUG`
@@ -0,0 +1,416 @@
1
+ # Orchestrator (Codex Pattern)
2
+
3
+ Orchestrate CCW Loop using Codex subagent pattern: `spawn_agent -> wait -> send_input -> close_agent`.
4
+
5
+ ## Role
6
+
7
+ Check control signals -> Read file state -> Select action -> Execute via agent -> Update files -> Loop until complete or paused/stopped.
8
+
9
+ ## Codex Pattern Overview
10
+
11
+ ```
12
+ +-- spawn_agent (ccw-loop-executor role) --+
13
+ | |
14
+ | Phase 1: INIT or first action |
15
+ | | |
16
+ | v |
17
+ | wait() -> get result |
18
+ | | |
19
+ | v |
20
+ | [If needs input] Collect user input |
21
+ | | |
22
+ | v |
23
+ | send_input(user choice + next action) |
24
+ | | |
25
+ | v |
26
+ | wait() -> get result |
27
+ | | |
28
+ | v |
29
+ | [Loop until COMPLETED/PAUSED/STOPPED] |
30
+ | | |
31
+ +----------v-------------------------------+
32
+ |
33
+ close_agent()
34
+ ```
35
+
36
+ ## State Management (Unified Location)
37
+
38
+ ### Read State
39
+
40
+ ```javascript
41
+ const getUtc8ISOString = () => new Date(Date.now() + 8 * 60 * 60 * 1000).toISOString()
42
+
43
+ /**
44
+ * Read loop state (unified location)
45
+ * @param loopId - Loop ID (e.g., "loop-v2-20260122-abc123")
46
+ */
47
+ function readLoopState(loopId) {
48
+ const stateFile = `.workflow/.loop/${loopId}.json`
49
+
50
+ if (!fs.existsSync(stateFile)) {
51
+ return null
52
+ }
53
+
54
+ const state = JSON.parse(Read(stateFile))
55
+ return state
56
+ }
57
+ ```
58
+
59
+ ### Create New Loop State (Direct Call)
60
+
61
+ ```javascript
62
+ /**
63
+ * Create new loop state (only for direct calls, API triggers have existing state)
64
+ */
65
+ function createLoopState(loopId, taskDescription) {
66
+ const stateFile = `.workflow/.loop/${loopId}.json`
67
+ const now = getUtc8ISOString()
68
+
69
+ const state = {
70
+ // API compatible fields
71
+ loop_id: loopId,
72
+ title: taskDescription.substring(0, 100),
73
+ description: taskDescription,
74
+ max_iterations: 10,
75
+ status: 'running', // Direct call sets to running
76
+ current_iteration: 0,
77
+ created_at: now,
78
+ updated_at: now,
79
+
80
+ // Skill extension fields
81
+ skill_state: null // Initialized by INIT action
82
+ }
83
+
84
+ // Ensure directories exist
85
+ mkdir -p ".loop"
86
+ mkdir -p ".workflow/.loop/${loopId}.progress"
87
+
88
+ Write(stateFile, JSON.stringify(state, null, 2))
89
+ return state
90
+ }
91
+ ```
92
+
93
+ ## Main Execution Flow (Codex Subagent)
94
+
95
+ ```javascript
96
+ /**
97
+ * Run CCW Loop orchestrator using Codex subagent pattern
98
+ * @param options.loopId - Existing Loop ID (API trigger)
99
+ * @param options.task - Task description (direct call)
100
+ * @param options.mode - 'interactive' | 'auto'
101
+ */
102
+ async function runOrchestrator(options = {}) {
103
+ const { loopId: existingLoopId, task, mode = 'interactive' } = options
104
+
105
+ console.log('=== CCW Loop Orchestrator (Codex) Started ===')
106
+
107
+ // 1. Determine loopId and initial state
108
+ let loopId
109
+ let state
110
+
111
+ if (existingLoopId) {
112
+ // API trigger: use existing loopId
113
+ loopId = existingLoopId
114
+ state = readLoopState(loopId)
115
+
116
+ if (!state) {
117
+ console.error(`Loop not found: ${loopId}`)
118
+ return { status: 'error', message: 'Loop not found' }
119
+ }
120
+
121
+ console.log(`Resuming loop: ${loopId}`)
122
+ console.log(`Status: ${state.status}`)
123
+
124
+ } else if (task) {
125
+ // Direct call: create new loopId
126
+ const timestamp = getUtc8ISOString().replace(/[-:]/g, '').split('.')[0]
127
+ const random = Math.random().toString(36).substring(2, 10)
128
+ loopId = `loop-v2-${timestamp}-${random}`
129
+
130
+ console.log(`Creating new loop: ${loopId}`)
131
+ console.log(`Task: ${task}`)
132
+
133
+ state = createLoopState(loopId, task)
134
+
135
+ } else {
136
+ console.error('Either --loop-id or task description is required')
137
+ return { status: 'error', message: 'Missing loopId or task' }
138
+ }
139
+
140
+ const progressDir = `.workflow/.loop/${loopId}.progress`
141
+
142
+ // 2. Create executor agent (single agent for entire loop)
143
+ const agent = spawn_agent({
144
+ message: `
145
+ ## TASK ASSIGNMENT
146
+
147
+ ### MANDATORY FIRST STEPS (Agent Execute)
148
+ 1. **Read role definition**: ~/.codex/agents/ccw-loop-executor.md (MUST read first)
149
+ 2. Read: .workflow/project-tech.json (if exists)
150
+ 3. Read: .workflow/project-guidelines.json (if exists)
151
+
152
+ ---
153
+
154
+ ## LOOP CONTEXT
155
+
156
+ - **Loop ID**: ${loopId}
157
+ - **State File**: .workflow/.loop/${loopId}.json
158
+ - **Progress Dir**: ${progressDir}
159
+ - **Mode**: ${mode}
160
+
161
+ ## CURRENT STATE
162
+
163
+ ${JSON.stringify(state, null, 2)}
164
+
165
+ ## TASK DESCRIPTION
166
+
167
+ ${state.description || task}
168
+
169
+ ## FIRST ACTION
170
+
171
+ ${!state.skill_state ? 'Execute: INIT' : mode === 'auto' ? 'Auto-select next action' : 'Show MENU'}
172
+
173
+ Read the role definition first, then execute the appropriate action.
174
+ `
175
+ })
176
+
177
+ // 3. Main orchestration loop
178
+ let iteration = state.current_iteration || 0
179
+ const maxIterations = state.max_iterations || 10
180
+ let continueLoop = true
181
+
182
+ while (continueLoop && iteration < maxIterations) {
183
+ iteration++
184
+
185
+ // Wait for agent output
186
+ const result = wait({ ids: [agent], timeout_ms: 600000 })
187
+
188
+ // Check for timeout
189
+ if (result.timed_out) {
190
+ console.log('Agent timeout, requesting convergence...')
191
+ send_input({
192
+ id: agent,
193
+ message: `
194
+ ## TIMEOUT NOTIFICATION
195
+
196
+ Execution timeout reached. Please:
197
+ 1. Output current progress
198
+ 2. Save any pending state updates
199
+ 3. Return ACTION_RESULT with current status
200
+ `
201
+ })
202
+ continue
203
+ }
204
+
205
+ const output = result.status[agent].completed
206
+
207
+ // Parse action result
208
+ const actionResult = parseActionResult(output)
209
+
210
+ console.log(`\n[Iteration ${iteration}] Action: ${actionResult.action}, Status: ${actionResult.status}`)
211
+
212
+ // Update iteration in state
213
+ state = readLoopState(loopId)
214
+ state.current_iteration = iteration
215
+ state.updated_at = getUtc8ISOString()
216
+ Write(`.workflow/.loop/${loopId}.json`, JSON.stringify(state, null, 2))
217
+
218
+ // Handle different outcomes
219
+ switch (actionResult.next_action) {
220
+ case 'COMPLETED':
221
+ console.log('Loop completed successfully')
222
+ continueLoop = false
223
+ break
224
+
225
+ case 'PAUSED':
226
+ console.log('Loop paused by API, exiting gracefully')
227
+ continueLoop = false
228
+ break
229
+
230
+ case 'STOPPED':
231
+ console.log('Loop stopped by API')
232
+ continueLoop = false
233
+ break
234
+
235
+ case 'WAITING_INPUT':
236
+ // Interactive mode: display menu, get user choice
237
+ if (mode === 'interactive') {
238
+ const userChoice = await displayMenuAndGetChoice(actionResult)
239
+
240
+ // Send user choice back to agent
241
+ send_input({
242
+ id: agent,
243
+ message: `
244
+ ## USER INPUT RECEIVED
245
+
246
+ Action selected: ${userChoice.action}
247
+ ${userChoice.data ? `Additional data: ${JSON.stringify(userChoice.data)}` : ''}
248
+
249
+ ## EXECUTE SELECTED ACTION
250
+
251
+ Read action instructions and execute: ${userChoice.action}
252
+ Update state and progress files accordingly.
253
+ Output ACTION_RESULT when complete.
254
+ `
255
+ })
256
+ }
257
+ break
258
+
259
+ default:
260
+ // Continue with next action
261
+ if (actionResult.next_action && actionResult.next_action !== 'NONE') {
262
+ send_input({
263
+ id: agent,
264
+ message: `
265
+ ## CONTINUE EXECUTION
266
+
267
+ Previous action completed: ${actionResult.action}
268
+ Result: ${actionResult.status}
269
+ ${actionResult.message ? `Message: ${actionResult.message}` : ''}
270
+
271
+ ## EXECUTE NEXT ACTION
272
+
273
+ Continue with: ${actionResult.next_action}
274
+ Read action instructions and execute.
275
+ Output ACTION_RESULT when complete.
276
+ `
277
+ })
278
+ } else {
279
+ // No next action specified, check if should continue
280
+ if (actionResult.status === 'failed') {
281
+ console.log(`Action failed: ${actionResult.message}`)
282
+ }
283
+ continueLoop = false
284
+ }
285
+ }
286
+ }
287
+
288
+ // 4. Check iteration limit
289
+ if (iteration >= maxIterations) {
290
+ console.log(`\nReached maximum iterations (${maxIterations})`)
291
+ console.log('Consider breaking down the task or taking a break.')
292
+ }
293
+
294
+ // 5. Cleanup
295
+ close_agent({ id: agent })
296
+
297
+ console.log('\n=== CCW Loop Orchestrator (Codex) Finished ===')
298
+
299
+ // Return final state
300
+ const finalState = readLoopState(loopId)
301
+ return {
302
+ status: finalState.status,
303
+ loop_id: loopId,
304
+ iterations: iteration,
305
+ final_state: finalState
306
+ }
307
+ }
308
+
309
+ /**
310
+ * Parse action result from agent output
311
+ */
312
+ function parseActionResult(output) {
313
+ const result = {
314
+ action: 'unknown',
315
+ status: 'unknown',
316
+ message: '',
317
+ state_updates: {},
318
+ next_action: 'NONE'
319
+ }
320
+
321
+ // Parse ACTION_RESULT block
322
+ const actionMatch = output.match(/ACTION_RESULT:\s*([\s\S]*?)(?:FILES_UPDATED:|NEXT_ACTION_NEEDED:|$)/)
323
+ if (actionMatch) {
324
+ const lines = actionMatch[1].split('\n')
325
+ for (const line of lines) {
326
+ const match = line.match(/^-\s*(\w+):\s*(.+)$/)
327
+ if (match) {
328
+ const [, key, value] = match
329
+ if (key === 'state_updates') {
330
+ try {
331
+ result.state_updates = JSON.parse(value)
332
+ } catch (e) {
333
+ // Try parsing multi-line JSON
334
+ }
335
+ } else {
336
+ result[key] = value.trim()
337
+ }
338
+ }
339
+ }
340
+ }
341
+
342
+ // Parse NEXT_ACTION_NEEDED
343
+ const nextMatch = output.match(/NEXT_ACTION_NEEDED:\s*(\S+)/)
344
+ if (nextMatch) {
345
+ result.next_action = nextMatch[1]
346
+ }
347
+
348
+ return result
349
+ }
350
+
351
+ /**
352
+ * Display menu and get user choice (interactive mode)
353
+ */
354
+ async function displayMenuAndGetChoice(actionResult) {
355
+ // Parse MENU_OPTIONS from output
356
+ const menuMatch = actionResult.message.match(/MENU_OPTIONS:\s*([\s\S]*?)(?:WAITING_INPUT:|$)/)
357
+
358
+ if (menuMatch) {
359
+ console.log('\n' + menuMatch[1])
360
+ }
361
+
362
+ // Use AskUserQuestion to get choice
363
+ const response = await AskUserQuestion({
364
+ questions: [{
365
+ question: "Select next action:",
366
+ header: "Action",
367
+ multiSelect: false,
368
+ options: [
369
+ { label: "develop", description: "Continue development" },
370
+ { label: "debug", description: "Start debugging" },
371
+ { label: "validate", description: "Run validation" },
372
+ { label: "complete", description: "Complete loop" },
373
+ { label: "exit", description: "Exit and save" }
374
+ ]
375
+ }]
376
+ })
377
+
378
+ return { action: response["Action"] }
379
+ }
380
+ ```
381
+
382
+ ## Action Catalog
383
+
384
+ | Action | Purpose | Preconditions | Effects |
385
+ |--------|---------|---------------|---------|
386
+ | INIT | Initialize session | status=running, skill_state=null | skill_state initialized |
387
+ | MENU | Display menu | skill_state != null, mode=interactive | Wait for user input |
388
+ | DEVELOP | Execute dev task | pending tasks > 0 | Update progress.md |
389
+ | DEBUG | Hypothesis debug | needs debugging | Update understanding.md |
390
+ | VALIDATE | Run tests | needs validation | Update validation.md |
391
+ | COMPLETE | Finish loop | all done | status=completed |
392
+
393
+ ## Termination Conditions
394
+
395
+ 1. **API Paused**: `state.status === 'paused'` (Skill exits, wait for resume)
396
+ 2. **API Stopped**: `state.status === 'failed'` (Skill terminates)
397
+ 3. **Task Complete**: `NEXT_ACTION_NEEDED === 'COMPLETED'`
398
+ 4. **Iteration Limit**: `current_iteration >= max_iterations`
399
+ 5. **User Exit**: User selects 'exit' in interactive mode
400
+
401
+ ## Error Recovery
402
+
403
+ | Error Type | Recovery Strategy |
404
+ |------------|-------------------|
405
+ | Agent timeout | send_input requesting convergence |
406
+ | Action failed | Log error, continue or prompt user |
407
+ | State corrupted | Rebuild from progress files |
408
+ | Agent closed unexpectedly | Re-spawn with previous output in message |
409
+
410
+ ## Codex Best Practices Applied
411
+
412
+ 1. **Single Agent Pattern**: One agent handles entire loop lifecycle
413
+ 2. **Deep Interaction via send_input**: Multi-phase without context loss
414
+ 3. **Delayed close_agent**: Only after confirming no more interaction
415
+ 4. **Explicit wait()**: Always get results before proceeding
416
+ 5. **Role Path Passing**: Agent reads role file, no content embedding