claude-code-workflow 6.3.36 → 6.3.37
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/.claude/commands/workflow/lite-fix.md +108 -9
- package/.claude/skills/ccw-loop/README.md +303 -0
- package/.claude/skills/ccw-loop/SKILL.md +259 -0
- package/.claude/skills/ccw-loop/phases/actions/action-complete.md +320 -0
- package/.claude/skills/ccw-loop/phases/actions/action-debug-with-file.md +485 -0
- package/.claude/skills/ccw-loop/phases/actions/action-develop-with-file.md +365 -0
- package/.claude/skills/ccw-loop/phases/actions/action-init.md +200 -0
- package/.claude/skills/ccw-loop/phases/actions/action-menu.md +192 -0
- package/.claude/skills/ccw-loop/phases/actions/action-validate-with-file.md +307 -0
- package/.claude/skills/ccw-loop/phases/orchestrator.md +486 -0
- package/.claude/skills/ccw-loop/phases/state-schema.md +474 -0
- package/.claude/skills/ccw-loop/specs/action-catalog.md +300 -0
- package/.claude/skills/ccw-loop/specs/loop-requirements.md +192 -0
- package/.claude/skills/ccw-loop/templates/progress-template.md +175 -0
- package/.claude/skills/ccw-loop/templates/understanding-template.md +303 -0
- package/.claude/skills/ccw-loop/templates/validation-template.md +258 -0
- package/ccw/dist/cli.d.ts.map +1 -1
- package/ccw/dist/cli.js +8 -1
- package/ccw/dist/cli.js.map +1 -1
- package/ccw/dist/commands/cli.d.ts.map +1 -1
- package/ccw/dist/commands/cli.js +14 -1
- package/ccw/dist/commands/cli.js.map +1 -1
- package/ccw/dist/commands/loop.d.ts +10 -0
- package/ccw/dist/commands/loop.d.ts.map +1 -0
- package/ccw/dist/commands/loop.js +289 -0
- package/ccw/dist/commands/loop.js.map +1 -0
- package/ccw/dist/core/dashboard-generator.d.ts.map +1 -1
- package/ccw/dist/core/dashboard-generator.js +4 -1
- package/ccw/dist/core/dashboard-generator.js.map +1 -1
- package/ccw/dist/core/routes/claude-routes.d.ts.map +1 -1
- package/ccw/dist/core/routes/claude-routes.js +5 -3
- package/ccw/dist/core/routes/claude-routes.js.map +1 -1
- package/ccw/dist/core/routes/cli-routes.d.ts +6 -0
- package/ccw/dist/core/routes/cli-routes.d.ts.map +1 -1
- package/ccw/dist/core/routes/cli-routes.js +42 -13
- package/ccw/dist/core/routes/cli-routes.js.map +1 -1
- package/ccw/dist/core/routes/cli-settings-routes.d.ts.map +1 -1
- package/ccw/dist/core/routes/cli-settings-routes.js +44 -0
- package/ccw/dist/core/routes/cli-settings-routes.js.map +1 -1
- package/ccw/dist/core/routes/codexlens/semantic-handlers.d.ts.map +1 -1
- package/ccw/dist/core/routes/codexlens/semantic-handlers.js +3 -2
- package/ccw/dist/core/routes/codexlens/semantic-handlers.js.map +1 -1
- package/ccw/dist/core/routes/core-memory-routes.d.ts.map +1 -1
- package/ccw/dist/core/routes/core-memory-routes.js +4 -2
- package/ccw/dist/core/routes/core-memory-routes.js.map +1 -1
- package/ccw/dist/core/routes/files-routes.d.ts.map +1 -1
- package/ccw/dist/core/routes/files-routes.js +4 -2
- package/ccw/dist/core/routes/files-routes.js.map +1 -1
- package/ccw/dist/core/routes/loop-routes.d.ts +24 -0
- package/ccw/dist/core/routes/loop-routes.d.ts.map +1 -0
- package/ccw/dist/core/routes/loop-routes.js +334 -0
- package/ccw/dist/core/routes/loop-routes.js.map +1 -0
- package/ccw/dist/core/routes/loop-v2-routes.d.ts +35 -0
- package/ccw/dist/core/routes/loop-v2-routes.d.ts.map +1 -0
- package/ccw/dist/core/routes/loop-v2-routes.js +1208 -0
- package/ccw/dist/core/routes/loop-v2-routes.js.map +1 -0
- package/ccw/dist/core/routes/memory-routes.d.ts.map +1 -1
- package/ccw/dist/core/routes/memory-routes.js +2 -1
- package/ccw/dist/core/routes/memory-routes.js.map +1 -1
- package/ccw/dist/core/routes/task-routes.d.ts +12 -0
- package/ccw/dist/core/routes/task-routes.d.ts.map +1 -0
- package/ccw/dist/core/routes/task-routes.js +321 -0
- package/ccw/dist/core/routes/task-routes.js.map +1 -0
- package/ccw/dist/core/routes/test-loop-routes.d.ts +11 -0
- package/ccw/dist/core/routes/test-loop-routes.d.ts.map +1 -0
- package/ccw/dist/core/routes/test-loop-routes.js +298 -0
- package/ccw/dist/core/routes/test-loop-routes.js.map +1 -0
- package/ccw/dist/core/server.d.ts.map +1 -1
- package/ccw/dist/core/server.js +43 -3
- package/ccw/dist/core/server.js.map +1 -1
- package/ccw/dist/core/websocket.d.ts +59 -0
- package/ccw/dist/core/websocket.d.ts.map +1 -1
- package/ccw/dist/core/websocket.js +34 -0
- package/ccw/dist/core/websocket.js.map +1 -1
- package/ccw/dist/tools/claude-cli-tools.d.ts +40 -0
- package/ccw/dist/tools/claude-cli-tools.d.ts.map +1 -1
- package/ccw/dist/tools/claude-cli-tools.js +119 -0
- package/ccw/dist/tools/claude-cli-tools.js.map +1 -1
- package/ccw/dist/tools/loop-manager.d.ts +84 -0
- package/ccw/dist/tools/loop-manager.d.ts.map +1 -0
- package/ccw/dist/tools/loop-manager.js +425 -0
- package/ccw/dist/tools/loop-manager.js.map +1 -0
- package/ccw/dist/tools/loop-state-manager.d.ts +47 -0
- package/ccw/dist/tools/loop-state-manager.d.ts.map +1 -0
- package/ccw/dist/tools/loop-state-manager.js +149 -0
- package/ccw/dist/tools/loop-state-manager.js.map +1 -0
- package/ccw/dist/tools/loop-task-manager.d.ts +138 -0
- package/ccw/dist/tools/loop-task-manager.d.ts.map +1 -0
- package/ccw/dist/tools/loop-task-manager.js +270 -0
- package/ccw/dist/tools/loop-task-manager.js.map +1 -0
- package/ccw/dist/types/index.d.ts +1 -0
- package/ccw/dist/types/index.d.ts.map +1 -1
- package/ccw/dist/types/index.js +1 -0
- package/ccw/dist/types/index.js.map +1 -1
- package/ccw/dist/types/loop.d.ts +257 -0
- package/ccw/dist/types/loop.d.ts.map +1 -0
- package/ccw/dist/types/loop.js +17 -0
- package/ccw/dist/types/loop.js.map +1 -0
- package/ccw/src/cli.ts +9 -1
- package/ccw/src/commands/cli.ts +14 -1
- package/ccw/src/commands/loop.ts +344 -0
- package/ccw/src/core/dashboard-generator.ts +4 -1
- package/ccw/src/core/routes/claude-routes.ts +5 -3
- package/ccw/src/core/routes/cli-routes.ts +47 -15
- package/ccw/src/core/routes/cli-settings-routes.ts +47 -0
- package/ccw/src/core/routes/codexlens/semantic-handlers.ts +3 -2
- package/ccw/src/core/routes/core-memory-routes.ts +4 -2
- package/ccw/src/core/routes/files-routes.ts +4 -2
- package/ccw/src/core/routes/loop-routes.ts +386 -0
- package/ccw/src/core/routes/loop-v2-routes.ts +1412 -0
- package/ccw/src/core/routes/memory-routes.ts +2 -1
- package/ccw/src/core/routes/task-routes.ts +361 -0
- package/ccw/src/core/routes/test-loop-routes.ts +312 -0
- package/ccw/src/core/server.ts +44 -3
- package/ccw/src/core/websocket.ts +104 -0
- package/ccw/src/templates/dashboard-css/12-cli-legacy.css +56 -0
- package/ccw/src/templates/dashboard-css/33-cli-stream-viewer.css +55 -0
- package/ccw/src/templates/dashboard-css/36-loop-monitor.css +1896 -0
- package/ccw/src/templates/dashboard-css/36-loop-monitor.css.backup +1877 -0
- package/ccw/src/templates/dashboard-js/components/cli-status.js +64 -3
- package/ccw/src/templates/dashboard-js/components/cli-stream-viewer.js +251 -110
- package/ccw/src/templates/dashboard-js/components/navigation.js +10 -0
- package/ccw/src/templates/dashboard-js/components/notifications.js +16 -0
- package/ccw/src/templates/dashboard-js/i18n.js +475 -1
- package/ccw/src/templates/dashboard-js/views/cli-manager.js +3 -2
- package/ccw/src/templates/dashboard-js/views/loop-monitor.js +3244 -0
- package/ccw/src/templates/dashboard.html +20 -2
- package/ccw/src/tools/claude-cli-tools.ts +143 -0
- package/ccw/src/tools/loop-manager.ts +519 -0
- package/ccw/src/tools/loop-state-manager.ts +173 -0
- package/ccw/src/tools/loop-task-manager.ts +380 -0
- package/ccw/src/types/index.ts +1 -0
- package/ccw/src/types/loop.ts +316 -0
- package/package.json +1 -1
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Loop System Type Definitions
|
|
3
|
+
* CCW Loop System - JSON-based state management for multi-CLI orchestration
|
|
4
|
+
* Reference: .workflow/.scratchpad/loop-system-complete-design-20260121.md
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Loop status enumeration
|
|
8
|
+
*/
|
|
9
|
+
export declare enum LoopStatus {
|
|
10
|
+
CREATED = "created",
|
|
11
|
+
RUNNING = "running",
|
|
12
|
+
PAUSED = "paused",
|
|
13
|
+
COMPLETED = "completed",
|
|
14
|
+
FAILED = "failed"
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* CLI step configuration
|
|
18
|
+
* Defines a single step in the CLI execution sequence
|
|
19
|
+
*/
|
|
20
|
+
export interface CliStepConfig {
|
|
21
|
+
/** Step unique identifier */
|
|
22
|
+
step_id: string;
|
|
23
|
+
/** CLI tool name */
|
|
24
|
+
tool: 'bash' | 'gemini' | 'codex' | 'qwen' | string;
|
|
25
|
+
/** Execution mode (for gemini/codex/claude) */
|
|
26
|
+
mode?: 'analysis' | 'write' | 'review';
|
|
27
|
+
/** Bash command (when tool='bash') */
|
|
28
|
+
command?: string;
|
|
29
|
+
/** Prompt template with variable replacement support */
|
|
30
|
+
prompt_template?: string;
|
|
31
|
+
/** Step failure behavior */
|
|
32
|
+
on_error?: 'continue' | 'pause' | 'fail_fast';
|
|
33
|
+
/** Custom parameters */
|
|
34
|
+
custom_args?: Record<string, unknown>;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Error policy configuration
|
|
38
|
+
*/
|
|
39
|
+
export interface ErrorPolicy {
|
|
40
|
+
/** Failure behavior */
|
|
41
|
+
on_failure: 'pause' | 'retry' | 'fail_fast';
|
|
42
|
+
/** Retry count */
|
|
43
|
+
retry_count: number;
|
|
44
|
+
/** Maximum retries (optional) */
|
|
45
|
+
max_retries?: number;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Loop state - complete definition
|
|
49
|
+
* Single source of truth stored in loop-state.json
|
|
50
|
+
*/
|
|
51
|
+
export interface LoopState {
|
|
52
|
+
/** Loop unique identifier */
|
|
53
|
+
loop_id: string;
|
|
54
|
+
/** Associated task ID */
|
|
55
|
+
task_id: string;
|
|
56
|
+
/** Current status */
|
|
57
|
+
status: LoopStatus;
|
|
58
|
+
/** Current iteration (1-indexed) */
|
|
59
|
+
current_iteration: number;
|
|
60
|
+
/** Maximum iterations */
|
|
61
|
+
max_iterations: number;
|
|
62
|
+
/** Current CLI step index (0-indexed) */
|
|
63
|
+
current_cli_step: number;
|
|
64
|
+
/** CLI execution sequence */
|
|
65
|
+
cli_sequence: CliStepConfig[];
|
|
66
|
+
/**
|
|
67
|
+
* Session mapping table
|
|
68
|
+
* Key format: {tool}_{step_index}
|
|
69
|
+
* Value: conversation_id or execution_id
|
|
70
|
+
*/
|
|
71
|
+
session_mapping: Record<string, string>;
|
|
72
|
+
/**
|
|
73
|
+
* State variables
|
|
74
|
+
* Key format: {step_id}_{stdout|stderr}
|
|
75
|
+
* Value: corresponding output content
|
|
76
|
+
*/
|
|
77
|
+
state_variables: Record<string, string>;
|
|
78
|
+
/** Success condition expression (JavaScript) */
|
|
79
|
+
success_condition?: string;
|
|
80
|
+
/** Error policy */
|
|
81
|
+
error_policy: ErrorPolicy;
|
|
82
|
+
/** Creation timestamp */
|
|
83
|
+
created_at: string;
|
|
84
|
+
/** Last update timestamp */
|
|
85
|
+
updated_at: string;
|
|
86
|
+
/** Completion timestamp (if applicable) */
|
|
87
|
+
completed_at?: string;
|
|
88
|
+
/** Failure reason (if applicable) */
|
|
89
|
+
failure_reason?: string;
|
|
90
|
+
/** Execution history (optional) */
|
|
91
|
+
execution_history?: ExecutionRecord[];
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Execution record for history tracking
|
|
95
|
+
*/
|
|
96
|
+
export interface ExecutionRecord {
|
|
97
|
+
iteration: number;
|
|
98
|
+
step_index: number;
|
|
99
|
+
step_id: string;
|
|
100
|
+
tool: string;
|
|
101
|
+
conversation_id: string;
|
|
102
|
+
exit_code: number;
|
|
103
|
+
duration_ms: number;
|
|
104
|
+
timestamp: string;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Skill State - Extension fields managed by ccw-loop skill
|
|
108
|
+
* Stored in .workflow/.loop/{loopId}.json alongside API fields
|
|
109
|
+
*/
|
|
110
|
+
export interface SkillState {
|
|
111
|
+
/** Current action being executed */
|
|
112
|
+
current_action: 'init' | 'develop' | 'debug' | 'validate' | 'complete' | null;
|
|
113
|
+
/** Last completed action */
|
|
114
|
+
last_action: string | null;
|
|
115
|
+
/** List of completed action names */
|
|
116
|
+
completed_actions: string[];
|
|
117
|
+
/** Execution mode */
|
|
118
|
+
mode: 'interactive' | 'auto';
|
|
119
|
+
/** Development phase state */
|
|
120
|
+
develop: {
|
|
121
|
+
total: number;
|
|
122
|
+
completed: number;
|
|
123
|
+
current_task?: string;
|
|
124
|
+
tasks: DevelopTask[];
|
|
125
|
+
last_progress_at: string | null;
|
|
126
|
+
};
|
|
127
|
+
/** Debug phase state */
|
|
128
|
+
debug: {
|
|
129
|
+
active_bug?: string;
|
|
130
|
+
hypotheses_count: number;
|
|
131
|
+
hypotheses: Hypothesis[];
|
|
132
|
+
confirmed_hypothesis: string | null;
|
|
133
|
+
iteration: number;
|
|
134
|
+
last_analysis_at: string | null;
|
|
135
|
+
};
|
|
136
|
+
/** Validation phase state */
|
|
137
|
+
validate: {
|
|
138
|
+
pass_rate: number;
|
|
139
|
+
coverage: number;
|
|
140
|
+
test_results: TestResult[];
|
|
141
|
+
passed: boolean;
|
|
142
|
+
failed_tests: string[];
|
|
143
|
+
last_run_at: string | null;
|
|
144
|
+
};
|
|
145
|
+
/** Error tracking */
|
|
146
|
+
errors: Array<{
|
|
147
|
+
action: string;
|
|
148
|
+
message: string;
|
|
149
|
+
timestamp: string;
|
|
150
|
+
}>;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Development task
|
|
154
|
+
*/
|
|
155
|
+
export interface DevelopTask {
|
|
156
|
+
id: string;
|
|
157
|
+
description: string;
|
|
158
|
+
tool: 'gemini' | 'qwen' | 'codex' | 'bash';
|
|
159
|
+
mode: 'analysis' | 'write';
|
|
160
|
+
status: 'pending' | 'in_progress' | 'completed' | 'failed';
|
|
161
|
+
files_changed?: string[];
|
|
162
|
+
created_at: string;
|
|
163
|
+
completed_at?: string;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Debug hypothesis
|
|
167
|
+
*/
|
|
168
|
+
export interface Hypothesis {
|
|
169
|
+
id: string;
|
|
170
|
+
description: string;
|
|
171
|
+
testable_condition: string;
|
|
172
|
+
logging_point: string;
|
|
173
|
+
evidence_criteria: {
|
|
174
|
+
confirm: string;
|
|
175
|
+
reject: string;
|
|
176
|
+
};
|
|
177
|
+
likelihood: number;
|
|
178
|
+
status: 'pending' | 'confirmed' | 'rejected' | 'inconclusive';
|
|
179
|
+
evidence?: Record<string, unknown>;
|
|
180
|
+
verdict_reason?: string;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Test result
|
|
184
|
+
*/
|
|
185
|
+
export interface TestResult {
|
|
186
|
+
test_name: string;
|
|
187
|
+
suite: string;
|
|
188
|
+
status: 'passed' | 'failed' | 'skipped';
|
|
189
|
+
duration_ms: number;
|
|
190
|
+
error_message?: string;
|
|
191
|
+
stack_trace?: string;
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* V2 Loop Storage Format (simplified, for Dashboard API)
|
|
195
|
+
* This is the unified state structure used by both API and ccw-loop skill
|
|
196
|
+
*/
|
|
197
|
+
export interface V2LoopState {
|
|
198
|
+
loop_id: string;
|
|
199
|
+
title: string;
|
|
200
|
+
description: string;
|
|
201
|
+
max_iterations: number;
|
|
202
|
+
status: LoopStatus;
|
|
203
|
+
current_iteration: number;
|
|
204
|
+
created_at: string;
|
|
205
|
+
updated_at: string;
|
|
206
|
+
completed_at?: string;
|
|
207
|
+
failure_reason?: string;
|
|
208
|
+
skill_state?: SkillState;
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Task Loop control configuration
|
|
212
|
+
* Extension to Task JSON schema
|
|
213
|
+
*/
|
|
214
|
+
export interface TaskLoopControl {
|
|
215
|
+
/** Enable loop */
|
|
216
|
+
enabled: boolean;
|
|
217
|
+
/** Loop description */
|
|
218
|
+
description: string;
|
|
219
|
+
/** Maximum iterations */
|
|
220
|
+
max_iterations: number;
|
|
221
|
+
/** Success condition (JavaScript expression) */
|
|
222
|
+
success_condition: string;
|
|
223
|
+
/** Error policy */
|
|
224
|
+
error_policy: {
|
|
225
|
+
on_failure: 'pause' | 'retry' | 'fail_fast';
|
|
226
|
+
max_retries?: number;
|
|
227
|
+
};
|
|
228
|
+
/** CLI execution sequence */
|
|
229
|
+
cli_sequence: CliStepConfig[];
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Minimal Task interface for loop operations
|
|
233
|
+
* Compatible with task JSON schema
|
|
234
|
+
*/
|
|
235
|
+
export interface Task {
|
|
236
|
+
/** Task ID */
|
|
237
|
+
id: string;
|
|
238
|
+
/** Task title */
|
|
239
|
+
title?: string;
|
|
240
|
+
/** Task description */
|
|
241
|
+
description?: string;
|
|
242
|
+
/** Task status */
|
|
243
|
+
status?: string;
|
|
244
|
+
/** Task metadata */
|
|
245
|
+
meta?: {
|
|
246
|
+
type?: string;
|
|
247
|
+
created_by?: string;
|
|
248
|
+
};
|
|
249
|
+
/** Task context */
|
|
250
|
+
context?: {
|
|
251
|
+
requirements?: string[];
|
|
252
|
+
acceptance?: string[];
|
|
253
|
+
};
|
|
254
|
+
/** Loop control configuration */
|
|
255
|
+
loop_control?: TaskLoopControl;
|
|
256
|
+
}
|
|
257
|
+
//# sourceMappingURL=loop.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loop.d.ts","sourceRoot":"","sources":["../../src/types/loop.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Loop System Type Definitions
|
|
3
|
+
* CCW Loop System - JSON-based state management for multi-CLI orchestration
|
|
4
|
+
* Reference: .workflow/.scratchpad/loop-system-complete-design-20260121.md
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Loop status enumeration
|
|
8
|
+
*/
|
|
9
|
+
export var LoopStatus;
|
|
10
|
+
(function (LoopStatus) {
|
|
11
|
+
LoopStatus["CREATED"] = "created";
|
|
12
|
+
LoopStatus["RUNNING"] = "running";
|
|
13
|
+
LoopStatus["PAUSED"] = "paused";
|
|
14
|
+
LoopStatus["COMPLETED"] = "completed";
|
|
15
|
+
LoopStatus["FAILED"] = "failed";
|
|
16
|
+
})(LoopStatus || (LoopStatus = {}));
|
|
17
|
+
//# sourceMappingURL=loop.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loop.js","sourceRoot":"","sources":["../../src/types/loop.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;GAEG;AACH,MAAM,CAAN,IAAY,UAMX;AAND,WAAY,UAAU;IACpB,iCAAmB,CAAA;IACnB,iCAAmB,CAAA;IACnB,+BAAiB,CAAA;IACjB,qCAAuB,CAAA;IACvB,+BAAiB,CAAA;AACnB,CAAC,EANW,UAAU,KAAV,UAAU,QAMrB"}
|
package/ccw/src/cli.ts
CHANGED
|
@@ -14,6 +14,7 @@ import { coreMemoryCommand } from './commands/core-memory.js';
|
|
|
14
14
|
import { hookCommand } from './commands/hook.js';
|
|
15
15
|
import { issueCommand } from './commands/issue.js';
|
|
16
16
|
import { workflowCommand } from './commands/workflow.js';
|
|
17
|
+
import { loopCommand } from './commands/loop.js';
|
|
17
18
|
import { readFileSync, existsSync } from 'fs';
|
|
18
19
|
import { fileURLToPath } from 'url';
|
|
19
20
|
import { dirname, join } from 'path';
|
|
@@ -172,7 +173,7 @@ export function run(argv: string[]): void {
|
|
|
172
173
|
.description('Unified CLI tool executor (gemini/qwen/codex/claude)')
|
|
173
174
|
.option('-p, --prompt <prompt>', 'Prompt text (alternative to positional argument)')
|
|
174
175
|
.option('-f, --file <file>', 'Read prompt from file (best for multi-line prompts)')
|
|
175
|
-
.option('--tool <tool>', 'CLI tool to use
|
|
176
|
+
.option('--tool <tool>', 'CLI tool to use (reads from cli-settings.json defaultTool if not specified)')
|
|
176
177
|
.option('--mode <mode>', 'Execution mode: analysis, write, auto', 'analysis')
|
|
177
178
|
.option('-d, --debug', 'Enable debug logging for troubleshooting')
|
|
178
179
|
.option('--model <model>', 'Model override')
|
|
@@ -301,6 +302,13 @@ export function run(argv: string[]): void {
|
|
|
301
302
|
.option('--queue <queue-id>', 'Target queue ID for multi-queue operations')
|
|
302
303
|
.action((subcommand, args, options) => issueCommand(subcommand, args, options));
|
|
303
304
|
|
|
305
|
+
// Loop command - Loop management for multi-CLI orchestration
|
|
306
|
+
program
|
|
307
|
+
.command('loop [subcommand] [args...]')
|
|
308
|
+
.description('Loop management for automated multi-CLI execution')
|
|
309
|
+
.option('--session <name>', 'Specify workflow session')
|
|
310
|
+
.action((subcommand, args, options) => loopCommand(subcommand, args, options));
|
|
311
|
+
|
|
304
312
|
// Workflow command - Workflow installation and management
|
|
305
313
|
program
|
|
306
314
|
.command('workflow [subcommand] [args...]')
|
package/ccw/src/commands/cli.ts
CHANGED
|
@@ -30,6 +30,7 @@ import {
|
|
|
30
30
|
} from '../tools/storage-manager.js';
|
|
31
31
|
import { getHistoryStore } from '../tools/cli-history-store.js';
|
|
32
32
|
import { createSpinner } from '../utils/ui.js';
|
|
33
|
+
import { loadClaudeCliSettings } from '../tools/claude-cli-tools.js';
|
|
33
34
|
|
|
34
35
|
// Dashboard notification settings
|
|
35
36
|
const DASHBOARD_PORT = process.env.CCW_PORT || 3456;
|
|
@@ -548,7 +549,19 @@ async function statusAction(debug?: boolean): Promise<void> {
|
|
|
548
549
|
* @param {Object} options - CLI options
|
|
549
550
|
*/
|
|
550
551
|
async function execAction(positionalPrompt: string | undefined, options: CliExecOptions): Promise<void> {
|
|
551
|
-
const { prompt: optionPrompt, file, tool
|
|
552
|
+
const { prompt: optionPrompt, file, tool: userTool, mode = 'analysis', model, cd, includeDirs, stream, resume, id, noNative, cache, injectMode, debug, uncommitted, base, commit, title, rule } = options;
|
|
553
|
+
|
|
554
|
+
// Determine the tool to use: explicit --tool option, or defaultTool from config
|
|
555
|
+
let tool = userTool;
|
|
556
|
+
if (!tool) {
|
|
557
|
+
try {
|
|
558
|
+
const settings = loadClaudeCliSettings(cd || process.cwd());
|
|
559
|
+
tool = settings.defaultTool || 'gemini';
|
|
560
|
+
} catch {
|
|
561
|
+
// Fallback to gemini if config cannot be loaded
|
|
562
|
+
tool = 'gemini';
|
|
563
|
+
}
|
|
564
|
+
}
|
|
552
565
|
|
|
553
566
|
// Enable debug mode if --debug flag is set
|
|
554
567
|
if (debug) {
|
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Loop Command
|
|
3
|
+
* CCW Loop System - CLI interface for loop management
|
|
4
|
+
* Reference: .workflow/.scratchpad/loop-system-complete-design-20260121.md section 4.3
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import chalk from 'chalk';
|
|
8
|
+
import { readFile } from 'fs/promises';
|
|
9
|
+
import { join, resolve } from 'path';
|
|
10
|
+
import { existsSync } from 'fs';
|
|
11
|
+
import { LoopManager } from '../tools/loop-manager.js';
|
|
12
|
+
import type { TaskLoopControl } from '../types/loop.js';
|
|
13
|
+
|
|
14
|
+
// Minimal Task interface for task config files
|
|
15
|
+
interface Task {
|
|
16
|
+
id: string;
|
|
17
|
+
title?: string;
|
|
18
|
+
loop_control?: TaskLoopControl;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Read task configuration
|
|
23
|
+
*/
|
|
24
|
+
async function readTaskConfig(taskId: string, workflowDir: string): Promise<Task> {
|
|
25
|
+
const taskFile = join(workflowDir, '.task', `${taskId}.json`);
|
|
26
|
+
|
|
27
|
+
if (!existsSync(taskFile)) {
|
|
28
|
+
throw new Error(`Task file not found: ${taskFile}`);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const content = await readFile(taskFile, 'utf-8');
|
|
32
|
+
return JSON.parse(content) as Task;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Find active workflow session
|
|
37
|
+
*/
|
|
38
|
+
function findActiveSession(cwd: string): string | null {
|
|
39
|
+
const workflowDir = join(cwd, '.workflow', 'active');
|
|
40
|
+
|
|
41
|
+
if (!existsSync(workflowDir)) {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const { readdirSync } = require('fs');
|
|
46
|
+
const sessions = readdirSync(workflowDir).filter((d: string) => d.startsWith('WFS-'));
|
|
47
|
+
|
|
48
|
+
if (sessions.length === 0) {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (sessions.length === 1) {
|
|
53
|
+
return join(cwd, '.workflow', 'active', sessions[0]);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Multiple sessions, require user to specify
|
|
57
|
+
console.error(chalk.red('\n Error: Multiple active sessions found:'));
|
|
58
|
+
sessions.forEach((s: string) => console.error(chalk.gray(` - ${s}`)));
|
|
59
|
+
console.error(chalk.yellow('\n Please specify session with --session <name>\n'));
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Get status badge with color
|
|
65
|
+
*/
|
|
66
|
+
function getStatusBadge(status: string): string {
|
|
67
|
+
switch (status) {
|
|
68
|
+
case 'created':
|
|
69
|
+
return chalk.gray('○ created');
|
|
70
|
+
case 'running':
|
|
71
|
+
return chalk.cyan('● running');
|
|
72
|
+
case 'paused':
|
|
73
|
+
return chalk.yellow('⏸ paused');
|
|
74
|
+
case 'completed':
|
|
75
|
+
return chalk.green('✓ completed');
|
|
76
|
+
case 'failed':
|
|
77
|
+
return chalk.red('✗ failed');
|
|
78
|
+
default:
|
|
79
|
+
return status;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Format time ago
|
|
85
|
+
*/
|
|
86
|
+
function timeAgo(timestamp: string): string {
|
|
87
|
+
const now = Date.now();
|
|
88
|
+
const then = new Date(timestamp).getTime();
|
|
89
|
+
const diff = Math.floor((now - then) / 1000);
|
|
90
|
+
|
|
91
|
+
if (diff < 60) return `${diff}s ago`;
|
|
92
|
+
if (diff < 3600) return `${Math.floor(diff / 60)}m ago`;
|
|
93
|
+
if (diff < 86400) return `${Math.floor(diff / 3600)}h ago`;
|
|
94
|
+
return `${Math.floor(diff / 86400)}d ago`;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Start action
|
|
99
|
+
*/
|
|
100
|
+
async function startAction(taskId: string, options: { session?: string }): Promise<void> {
|
|
101
|
+
const currentCwd = process.cwd();
|
|
102
|
+
|
|
103
|
+
// Find workflow session
|
|
104
|
+
let sessionDir: string | null;
|
|
105
|
+
|
|
106
|
+
if (options.session) {
|
|
107
|
+
sessionDir = join(currentCwd, '.workflow', 'active', options.session);
|
|
108
|
+
if (!existsSync(sessionDir)) {
|
|
109
|
+
console.error(chalk.red(`\n Error: Session not found: ${options.session}\n`));
|
|
110
|
+
process.exit(1);
|
|
111
|
+
}
|
|
112
|
+
} else {
|
|
113
|
+
sessionDir = findActiveSession(currentCwd);
|
|
114
|
+
if (!sessionDir) {
|
|
115
|
+
console.error(chalk.red('\n Error: No active workflow session found.'));
|
|
116
|
+
console.error(chalk.gray(' Run "ccw workflow:plan" first to create a session.\n'));
|
|
117
|
+
process.exit(1);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
console.log(chalk.cyan(` Using session: ${sessionDir.split(/[\\/]/).pop()}`));
|
|
122
|
+
|
|
123
|
+
// Read task config
|
|
124
|
+
const task = await readTaskConfig(taskId, sessionDir);
|
|
125
|
+
|
|
126
|
+
if (!task.loop_control?.enabled) {
|
|
127
|
+
console.error(chalk.red(`\n Error: Task ${taskId} does not have loop enabled.\n`));
|
|
128
|
+
process.exit(1);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Start loop
|
|
132
|
+
const loopManager = new LoopManager(sessionDir);
|
|
133
|
+
const loopId = await loopManager.startLoop(task as any); // Task interface compatible
|
|
134
|
+
|
|
135
|
+
console.log(chalk.green(`\n ✓ Loop started: ${loopId}`));
|
|
136
|
+
console.log(chalk.dim(` Status: ccw loop status ${loopId}`));
|
|
137
|
+
console.log(chalk.dim(` Pause: ccw loop pause ${loopId}`));
|
|
138
|
+
console.log(chalk.dim(` Stop: ccw loop stop ${loopId}\n`));
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Status action
|
|
143
|
+
*/
|
|
144
|
+
async function statusAction(loopId: string | undefined, options: { session?: string }): Promise<void> {
|
|
145
|
+
const currentCwd = process.cwd();
|
|
146
|
+
const sessionDir = options?.session
|
|
147
|
+
? join(currentCwd, '.workflow', 'active', options.session)
|
|
148
|
+
: findActiveSession(currentCwd);
|
|
149
|
+
|
|
150
|
+
if (!sessionDir) {
|
|
151
|
+
console.error(chalk.red('\n Error: No active session found.\n'));
|
|
152
|
+
process.exit(1);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const loopManager = new LoopManager(sessionDir);
|
|
156
|
+
|
|
157
|
+
if (loopId) {
|
|
158
|
+
// Show single loop detail
|
|
159
|
+
const state = await loopManager.getStatus(loopId);
|
|
160
|
+
|
|
161
|
+
console.log(chalk.bold.cyan('\n Loop Status\n'));
|
|
162
|
+
console.log(` ${chalk.gray('ID:')} ${state.loop_id}`);
|
|
163
|
+
console.log(` ${chalk.gray('Task:')} ${state.task_id}`);
|
|
164
|
+
console.log(` ${chalk.gray('Status:')} ${getStatusBadge(state.status)}`);
|
|
165
|
+
console.log(` ${chalk.gray('Iteration:')} ${state.current_iteration}/${state.max_iterations}`);
|
|
166
|
+
console.log(` ${chalk.gray('Step:')} ${state.current_cli_step + 1}/${state.cli_sequence.length}`);
|
|
167
|
+
console.log(` ${chalk.gray('Created:')} ${state.created_at}`);
|
|
168
|
+
console.log(` ${chalk.gray('Updated:')} ${state.updated_at}`);
|
|
169
|
+
|
|
170
|
+
if (state.failure_reason) {
|
|
171
|
+
console.log(` ${chalk.gray('Reason:')} ${chalk.red(state.failure_reason)}`);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
console.log(chalk.bold.cyan('\n CLI Sequence\n'));
|
|
175
|
+
state.cli_sequence.forEach((step, i) => {
|
|
176
|
+
const current = i === state.current_cli_step ? chalk.cyan('→') : ' ';
|
|
177
|
+
console.log(` ${current} ${i + 1}. ${chalk.bold(step.step_id)} (${step.tool})`);
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
if (state.execution_history && state.execution_history.length > 0) {
|
|
181
|
+
console.log(chalk.bold.cyan('\n Recent Executions\n'));
|
|
182
|
+
const recent = state.execution_history.slice(-5);
|
|
183
|
+
recent.forEach(exec => {
|
|
184
|
+
const status = exec.exit_code === 0 ? chalk.green('✓') : chalk.red('✗');
|
|
185
|
+
console.log(` ${status} ${exec.step_id} (${exec.tool}) - ${(exec.duration_ms / 1000).toFixed(1)}s`);
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
console.log();
|
|
190
|
+
} else {
|
|
191
|
+
// List all loops
|
|
192
|
+
const loops = await loopManager.listLoops();
|
|
193
|
+
|
|
194
|
+
if (loops.length === 0) {
|
|
195
|
+
console.log(chalk.yellow('\n No loops found.\n'));
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
console.log(chalk.bold.cyan('\n Active Loops\n'));
|
|
200
|
+
console.log(chalk.gray(' Status ID Iteration Task'));
|
|
201
|
+
console.log(chalk.gray(' ' + '─'.repeat(70)));
|
|
202
|
+
|
|
203
|
+
loops.forEach(loop => {
|
|
204
|
+
const status = getStatusBadge(loop.status);
|
|
205
|
+
const iteration = `${loop.current_iteration}/${loop.max_iterations}`;
|
|
206
|
+
console.log(` ${status} ${chalk.dim(loop.loop_id.padEnd(35))} ${iteration.padEnd(9)} ${loop.task_id}`);
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
console.log();
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Pause action
|
|
215
|
+
*/
|
|
216
|
+
async function pauseAction(loopId: string, options: { session?: string }): Promise<void> {
|
|
217
|
+
const currentCwd = process.cwd();
|
|
218
|
+
const sessionDir = options.session
|
|
219
|
+
? join(currentCwd, '.workflow', 'active', options.session)
|
|
220
|
+
: findActiveSession(currentCwd);
|
|
221
|
+
|
|
222
|
+
if (!sessionDir) {
|
|
223
|
+
console.error(chalk.red('\n Error: No active session found.\n'));
|
|
224
|
+
process.exit(1);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
const loopManager = new LoopManager(sessionDir);
|
|
228
|
+
await loopManager.pauseLoop(loopId);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Resume action
|
|
233
|
+
*/
|
|
234
|
+
async function resumeAction(loopId: string, options: { session?: string }): Promise<void> {
|
|
235
|
+
const currentCwd = process.cwd();
|
|
236
|
+
const sessionDir = options.session
|
|
237
|
+
? join(currentCwd, '.workflow', 'active', options.session)
|
|
238
|
+
: findActiveSession(currentCwd);
|
|
239
|
+
|
|
240
|
+
if (!sessionDir) {
|
|
241
|
+
console.error(chalk.red('\n Error: No active session found.\n'));
|
|
242
|
+
process.exit(1);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
const loopManager = new LoopManager(sessionDir);
|
|
246
|
+
await loopManager.resumeLoop(loopId);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Stop action
|
|
251
|
+
*/
|
|
252
|
+
async function stopAction(loopId: string, options: { session?: string }): Promise<void> {
|
|
253
|
+
const currentCwd = process.cwd();
|
|
254
|
+
const sessionDir = options.session
|
|
255
|
+
? join(currentCwd, '.workflow', 'active', options.session)
|
|
256
|
+
: findActiveSession(currentCwd);
|
|
257
|
+
|
|
258
|
+
if (!sessionDir) {
|
|
259
|
+
console.error(chalk.red('\n Error: No active session found.\n'));
|
|
260
|
+
process.exit(1);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
const loopManager = new LoopManager(sessionDir);
|
|
264
|
+
await loopManager.stopLoop(loopId);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Loop command entry point
|
|
269
|
+
*/
|
|
270
|
+
export async function loopCommand(
|
|
271
|
+
subcommand: string,
|
|
272
|
+
args: string | string[],
|
|
273
|
+
options: any
|
|
274
|
+
): Promise<void> {
|
|
275
|
+
const argsArray = Array.isArray(args) ? args : (args ? [args] : []);
|
|
276
|
+
|
|
277
|
+
try {
|
|
278
|
+
switch (subcommand) {
|
|
279
|
+
case 'start':
|
|
280
|
+
if (!argsArray[0]) {
|
|
281
|
+
console.error(chalk.red('\n Error: Task ID is required\n'));
|
|
282
|
+
console.error(chalk.gray(' Usage: ccw loop start <task-id> [--session <name>]\n'));
|
|
283
|
+
process.exit(1);
|
|
284
|
+
}
|
|
285
|
+
await startAction(argsArray[0], options);
|
|
286
|
+
break;
|
|
287
|
+
|
|
288
|
+
case 'status':
|
|
289
|
+
await statusAction(argsArray[0], options);
|
|
290
|
+
break;
|
|
291
|
+
|
|
292
|
+
case 'pause':
|
|
293
|
+
if (!argsArray[0]) {
|
|
294
|
+
console.error(chalk.red('\n Error: Loop ID is required\n'));
|
|
295
|
+
console.error(chalk.gray(' Usage: ccw loop pause <loop-id>\n'));
|
|
296
|
+
process.exit(1);
|
|
297
|
+
}
|
|
298
|
+
await pauseAction(argsArray[0], options);
|
|
299
|
+
break;
|
|
300
|
+
|
|
301
|
+
case 'resume':
|
|
302
|
+
if (!argsArray[0]) {
|
|
303
|
+
console.error(chalk.red('\n Error: Loop ID is required\n'));
|
|
304
|
+
console.error(chalk.gray(' Usage: ccw loop resume <loop-id>\n'));
|
|
305
|
+
process.exit(1);
|
|
306
|
+
}
|
|
307
|
+
await resumeAction(argsArray[0], options);
|
|
308
|
+
break;
|
|
309
|
+
|
|
310
|
+
case 'stop':
|
|
311
|
+
if (!argsArray[0]) {
|
|
312
|
+
console.error(chalk.red('\n Error: Loop ID is required\n'));
|
|
313
|
+
console.error(chalk.gray(' Usage: ccw loop stop <loop-id>\n'));
|
|
314
|
+
process.exit(1);
|
|
315
|
+
}
|
|
316
|
+
await stopAction(argsArray[0], options);
|
|
317
|
+
break;
|
|
318
|
+
|
|
319
|
+
default:
|
|
320
|
+
// Show help
|
|
321
|
+
console.log(chalk.bold.cyan('\n CCW Loop System\n'));
|
|
322
|
+
console.log(' Manage automated CLI execution loops\n');
|
|
323
|
+
console.log(' Subcommands:');
|
|
324
|
+
console.log(chalk.gray(' start <task-id> Start a new loop from task configuration'));
|
|
325
|
+
console.log(chalk.gray(' status [loop-id] Show loop status (all or specific)'));
|
|
326
|
+
console.log(chalk.gray(' pause <loop-id> Pause a running loop'));
|
|
327
|
+
console.log(chalk.gray(' resume <loop-id> Resume a paused loop'));
|
|
328
|
+
console.log(chalk.gray(' stop <loop-id> Stop a loop'));
|
|
329
|
+
console.log();
|
|
330
|
+
console.log(' Options:');
|
|
331
|
+
console.log(chalk.gray(' --session <name> Specify workflow session'));
|
|
332
|
+
console.log();
|
|
333
|
+
console.log(' Examples:');
|
|
334
|
+
console.log(chalk.gray(' ccw loop start IMPL-3'));
|
|
335
|
+
console.log(chalk.gray(' ccw loop status'));
|
|
336
|
+
console.log(chalk.gray(' ccw loop status loop-IMPL-3-20260121120000'));
|
|
337
|
+
console.log(chalk.gray(' ccw loop pause loop-IMPL-3-20260121120000'));
|
|
338
|
+
console.log();
|
|
339
|
+
}
|
|
340
|
+
} catch (error) {
|
|
341
|
+
console.error(chalk.red(`\n ✗ Error: ${error instanceof Error ? error.message : error}\n`));
|
|
342
|
+
process.exit(1);
|
|
343
|
+
}
|
|
344
|
+
}
|