@fermindi/pwn-cli 0.1.1 → 0.3.0

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 (48) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +265 -251
  3. package/cli/batch.js +333 -333
  4. package/cli/codespaces.js +303 -303
  5. package/cli/index.js +112 -91
  6. package/cli/inject.js +90 -67
  7. package/cli/knowledge.js +531 -531
  8. package/cli/migrate.js +466 -0
  9. package/cli/notify.js +135 -135
  10. package/cli/patterns.js +665 -665
  11. package/cli/save.js +206 -0
  12. package/cli/status.js +91 -91
  13. package/cli/update.js +189 -0
  14. package/cli/validate.js +61 -61
  15. package/package.json +70 -70
  16. package/src/core/inject.js +300 -204
  17. package/src/core/state.js +91 -91
  18. package/src/core/validate.js +202 -202
  19. package/src/core/workspace.js +176 -176
  20. package/src/index.js +20 -20
  21. package/src/knowledge/gc.js +308 -308
  22. package/src/knowledge/lifecycle.js +401 -401
  23. package/src/knowledge/promote.js +364 -364
  24. package/src/knowledge/references.js +342 -342
  25. package/src/patterns/matcher.js +218 -218
  26. package/src/patterns/registry.js +375 -375
  27. package/src/patterns/triggers.js +423 -423
  28. package/src/services/batch-service.js +849 -849
  29. package/src/services/notification-service.js +342 -342
  30. package/templates/codespaces/devcontainer.json +52 -52
  31. package/templates/codespaces/setup.sh +70 -70
  32. package/templates/workspace/.ai/README.md +164 -164
  33. package/templates/workspace/.ai/agents/README.md +204 -204
  34. package/templates/workspace/.ai/agents/claude.md +625 -625
  35. package/templates/workspace/.ai/config/README.md +79 -79
  36. package/templates/workspace/.ai/config/notifications.template.json +20 -20
  37. package/templates/workspace/.ai/memory/deadends.md +79 -79
  38. package/templates/workspace/.ai/memory/decisions.md +58 -58
  39. package/templates/workspace/.ai/memory/patterns.md +65 -65
  40. package/templates/workspace/.ai/patterns/backend/README.md +126 -126
  41. package/templates/workspace/.ai/patterns/frontend/README.md +103 -103
  42. package/templates/workspace/.ai/patterns/index.md +256 -256
  43. package/templates/workspace/.ai/patterns/triggers.json +1087 -1087
  44. package/templates/workspace/.ai/patterns/universal/README.md +141 -141
  45. package/templates/workspace/.ai/state.template.json +8 -8
  46. package/templates/workspace/.ai/tasks/active.md +77 -77
  47. package/templates/workspace/.ai/tasks/backlog.md +95 -95
  48. package/templates/workspace/.ai/workflows/batch-task.md +356 -356
package/cli/batch.js CHANGED
@@ -1,333 +1,333 @@
1
- #!/usr/bin/env node
2
- import * as batch from '../src/services/batch-service.js';
3
- import { hasWorkspace } from '../src/core/state.js';
4
-
5
- export default async function batchCommand(args = []) {
6
- // Check for help first (doesn't require workspace)
7
- if (args.includes('--help') || args.includes('-h')) {
8
- showHelp();
9
- return;
10
- }
11
-
12
- // Check for workspace
13
- if (!hasWorkspace()) {
14
- console.log('❌ No PWN workspace found\n');
15
- console.log(' Run: pwn inject');
16
- process.exit(1);
17
- }
18
-
19
- const subcommand = args[0];
20
-
21
- // Handle subcommands
22
- if (subcommand === 'status' || args.includes('--status')) {
23
- return showStatus();
24
- }
25
-
26
- if (subcommand === 'config' || args.includes('--config')) {
27
- return showConfig();
28
- }
29
-
30
- // Parse options
31
- const options = parseOptions(args);
32
-
33
- // Handle actions
34
- if (options.resume) {
35
- return resumeBatch(options);
36
- }
37
-
38
- if (options.dryRun) {
39
- return dryRun(options);
40
- }
41
-
42
- // Default: start batch
43
- return startBatch(options);
44
- }
45
-
46
- /**
47
- * Parse command line options
48
- */
49
- function parseOptions(args) {
50
- const options = {};
51
-
52
- for (let i = 0; i < args.length; i++) {
53
- const arg = args[i];
54
-
55
- if (arg === '--count' || arg === '-n') {
56
- options.count = parseInt(args[++i], 10);
57
- } else if (arg === '--dry-run' || arg === '-d') {
58
- options.dryRun = true;
59
- } else if (arg === '--priority' || arg === '-p') {
60
- options.priority = args[++i]?.toLowerCase();
61
- } else if (arg === '--resume' || arg === '-r') {
62
- options.resume = true;
63
- } else if (arg === '--skip') {
64
- options.skip = true;
65
- } else if (arg === '--force' || arg === '-f') {
66
- options.skipGates = true;
67
- } else if (arg === '--continue') {
68
- options.continueOnError = true;
69
- } else if (arg === '--no-commit') {
70
- options.skipCommit = true;
71
- } else if (arg === '--no-branch') {
72
- options.skipBranch = true;
73
- } else if (arg === '--help' || arg === '-h') {
74
- showHelp();
75
- process.exit(0);
76
- }
77
- }
78
-
79
- return options;
80
- }
81
-
82
- /**
83
- * Show batch status
84
- */
85
- function showStatus() {
86
- const status = batch.getStatus();
87
-
88
- if (!status.hasWorkspace) {
89
- console.log('❌ No PWN workspace found');
90
- process.exit(1);
91
- }
92
-
93
- console.log('📋 Batch Status\n');
94
-
95
- // Running state
96
- if (status.isRunning) {
97
- console.log(` Status: 🔄 Running`);
98
- console.log(` Current Task: ${status.currentTask || '(selecting)'}`);
99
- } else if (status.isPaused) {
100
- console.log(` Status: ⏸️ Paused`);
101
- console.log(` Current Task: ${status.currentTask}`);
102
- console.log(` Reason: ${status.pauseReason}`);
103
- console.log('\n Resume with: pwn batch --resume');
104
- console.log(' Skip task: pwn batch --resume --skip');
105
- } else {
106
- console.log(' Status: ⏹️ Idle');
107
- }
108
-
109
- // Task counts
110
- console.log('\n📝 Tasks\n');
111
- console.log(` Active: ${status.tasks.activePending} pending, ${status.tasks.activeCompleted} completed`);
112
- console.log(` Backlog: ${status.tasks.backlogTotal} total`);
113
- if (status.tasks.backlogTotal > 0) {
114
- console.log(` - High: ${status.tasks.backlogHigh}`);
115
- console.log(` - Medium: ${status.tasks.backlogMedium}`);
116
- console.log(` - Low: ${status.tasks.backlogLow}`);
117
- }
118
-
119
- // Batch history
120
- if (status.batchState?.completed?.length > 0) {
121
- console.log('\n✅ Completed this batch\n');
122
- for (const taskId of status.batchState.completed) {
123
- console.log(` - ${taskId}`);
124
- }
125
- }
126
-
127
- // Next task preview
128
- const nextTask = batch.selectNextTask();
129
- if (nextTask) {
130
- console.log('\n🎯 Next Task\n');
131
- console.log(` ${nextTask.id}: ${nextTask.title}`);
132
- if (nextTask.priority) {
133
- console.log(` Priority: ${nextTask.priority}`);
134
- }
135
- } else {
136
- console.log('\n No tasks available in backlog');
137
- }
138
- }
139
-
140
- /**
141
- * Show batch configuration
142
- */
143
- function showConfig() {
144
- const config = batch.loadConfig();
145
-
146
- console.log('⚙️ Batch Configuration\n');
147
- console.log(` Max Tasks: ${config.max_tasks}`);
148
- console.log(` Max Duration: ${config.max_duration_hours} hours`);
149
- console.log(` Selection: ${config.selection_strategy}`);
150
- console.log(`\n Quality Gates: ${config.quality_gates.join(', ') || '(none)'}`);
151
- if (config.skip_gates.length > 0) {
152
- console.log(` Skip Gates: ${config.skip_gates.join(', ')}`);
153
- }
154
- console.log(`\n Auto Commit: ${config.auto_commit ? 'Yes' : 'No'}`);
155
- console.log(` Auto Push: ${config.auto_push ? 'Yes' : 'No'}`);
156
- console.log(` Create PR: ${config.create_pr ? 'Yes' : 'No'}`);
157
- console.log(` Branch Format: ${config.branch_format}`);
158
- console.log(` Commit Format: ${config.commit_format}`);
159
- console.log(`\n Notify Complete: ${config.notify_on_complete ? 'Yes' : 'No'}`);
160
- console.log(` Notify Error: ${config.notify_on_error ? 'Yes' : 'No'}`);
161
- console.log('\n📁 Config location: .ai/state.json (batch_config)');
162
- }
163
-
164
- /**
165
- * Dry run - show what would execute
166
- */
167
- async function dryRun(options) {
168
- console.log('🔍 Dry Run - Preview batch execution\n');
169
-
170
- const config = batch.loadConfig();
171
- const count = options.count || config.max_tasks;
172
-
173
- console.log(` Would execute up to ${count} tasks\n`);
174
-
175
- // Show tasks that would be selected
176
- const tasks = [];
177
- for (let i = 0; i < count; i++) {
178
- // Note: This is a simplified preview - actual selection happens one at a time
179
- const task = batch.selectNextTask(process.cwd(), { priority: options.priority });
180
- if (!task) break;
181
-
182
- // Skip already seen tasks for preview
183
- if (tasks.find(t => t.id === task.id)) break;
184
- tasks.push(task);
185
- }
186
-
187
- if (tasks.length === 0) {
188
- console.log(' No tasks available in backlog');
189
- return;
190
- }
191
-
192
- console.log(' Tasks to execute:\n');
193
- for (let i = 0; i < tasks.length; i++) {
194
- const task = tasks[i];
195
- const priority = task.priority ? ` (${task.priority})` : '';
196
- console.log(` ${i + 1}. ${task.id}: ${task.title}${priority}`);
197
- }
198
-
199
- console.log('\n Quality gates that would run:');
200
- for (const gate of config.quality_gates) {
201
- if (config.skip_gates.includes(gate)) {
202
- console.log(` ⏭️ ${gate} (skipped)`);
203
- } else {
204
- console.log(` ✓ ${gate}`);
205
- }
206
- }
207
-
208
- if (options.skipGates) {
209
- console.log('\n ⚠️ Gates would be skipped due to --force flag');
210
- }
211
-
212
- console.log('\n Run without --dry-run to execute');
213
- }
214
-
215
- /**
216
- * Start batch execution
217
- */
218
- async function startBatch(options) {
219
- const config = batch.loadConfig();
220
- const count = options.count || config.max_tasks;
221
-
222
- console.log('🚀 Starting batch execution\n');
223
- console.log(` Max tasks: ${count}`);
224
- console.log(` Quality gates: ${options.skipGates ? 'Skipped' : config.quality_gates.join(', ')}`);
225
- console.log('');
226
-
227
- const startTime = Date.now();
228
-
229
- const result = await batch.startBatch({
230
- count,
231
- priority: options.priority,
232
- skipGates: options.skipGates,
233
- skipCommit: options.skipCommit,
234
- skipBranch: options.skipBranch,
235
- continueOnError: options.continueOnError
236
- });
237
-
238
- const duration = Math.round((Date.now() - startTime) / 1000);
239
-
240
- console.log('');
241
-
242
- if (result.completed.length > 0) {
243
- console.log('✅ Completed tasks:\n');
244
- for (const task of result.completed) {
245
- console.log(` - ${task.id}: ${task.title}`);
246
- }
247
- }
248
-
249
- if (result.errors.length > 0) {
250
- console.log('\n❌ Failed tasks:\n');
251
- for (const error of result.errors) {
252
- console.log(` - ${error.id}: ${error.error}`);
253
- }
254
- }
255
-
256
- console.log(`\n⏱️ Duration: ${duration}s`);
257
- console.log(`📊 Summary: ${result.completed.length} completed, ${result.errors.length} failed`);
258
-
259
- if (!result.success) {
260
- console.log('\n💡 To resume: pwn batch --resume');
261
- console.log(' To skip: pwn batch --resume --skip');
262
- process.exit(1);
263
- }
264
- }
265
-
266
- /**
267
- * Resume paused batch
268
- */
269
- async function resumeBatch(options) {
270
- const status = batch.getStatus();
271
-
272
- if (!status.isPaused) {
273
- console.log('❌ No paused batch to resume\n');
274
- console.log(' Current status:', status.isRunning ? 'Running' : 'Idle');
275
- process.exit(1);
276
- }
277
-
278
- console.log('▶️ Resuming batch execution\n');
279
-
280
- if (options.skip) {
281
- console.log(` Skipping task: ${status.currentTask}`);
282
- }
283
-
284
- console.log('');
285
-
286
- const result = await batch.resumeBatch({
287
- skip: options.skip,
288
- skipGates: options.skipGates
289
- });
290
-
291
- if (!result.success) {
292
- console.log(`❌ ${result.message}`);
293
- process.exit(1);
294
- }
295
-
296
- console.log(`\n✅ Batch resumed`);
297
- console.log(` Completed: ${result.completed?.length || 0} tasks`);
298
- }
299
-
300
- /**
301
- * Show help
302
- */
303
- function showHelp() {
304
- console.log('🚀 PWN Batch Execution\n');
305
- console.log('Usage: pwn batch [command] [options]\n');
306
- console.log('Commands:');
307
- console.log(' (default) Execute next available task(s)');
308
- console.log(' status Show batch status');
309
- console.log(' config Show batch configuration\n');
310
- console.log('Options:');
311
- console.log(' --count, -n <num> Execute specific number of tasks');
312
- console.log(' --dry-run, -d Preview what would execute');
313
- console.log(' --priority, -p <level> Filter by priority (high, medium, low)');
314
- console.log(' --resume, -r Resume interrupted batch');
315
- console.log(' --skip Skip current task when resuming');
316
- console.log(' --force, -f Skip quality gates');
317
- console.log(' --continue Continue on errors');
318
- console.log(' --no-commit Skip auto-commit');
319
- console.log(' --no-branch Skip branch creation');
320
- console.log(' --help, -h Show this help\n');
321
- console.log('Examples:');
322
- console.log(' pwn batch # Execute next task');
323
- console.log(' pwn batch --count 5 # Execute 5 tasks');
324
- console.log(' pwn batch --dry-run # Preview execution');
325
- console.log(' pwn batch --priority high # Only high priority');
326
- console.log(' pwn batch --resume # Resume paused batch');
327
- console.log(' pwn batch --resume --skip # Resume, skip current');
328
- console.log(' pwn batch status # Show status');
329
- console.log(' pwn batch config # Show configuration\n');
330
- console.log('Configuration:');
331
- console.log(' Edit .ai/state.json and add batch_config object.');
332
- console.log(' See .ai/workflows/batch-task.md for full documentation.');
333
- }
1
+ #!/usr/bin/env node
2
+ import * as batch from '../src/services/batch-service.js';
3
+ import { hasWorkspace } from '../src/core/state.js';
4
+
5
+ export default async function batchCommand(args = []) {
6
+ // Check for help first (doesn't require workspace)
7
+ if (args.includes('--help') || args.includes('-h')) {
8
+ showHelp();
9
+ return;
10
+ }
11
+
12
+ // Check for workspace
13
+ if (!hasWorkspace()) {
14
+ console.log('❌ No PWN workspace found\n');
15
+ console.log(' Run: pwn inject');
16
+ process.exit(1);
17
+ }
18
+
19
+ const subcommand = args[0];
20
+
21
+ // Handle subcommands
22
+ if (subcommand === 'status' || args.includes('--status')) {
23
+ return showStatus();
24
+ }
25
+
26
+ if (subcommand === 'config' || args.includes('--config')) {
27
+ return showConfig();
28
+ }
29
+
30
+ // Parse options
31
+ const options = parseOptions(args);
32
+
33
+ // Handle actions
34
+ if (options.resume) {
35
+ return resumeBatch(options);
36
+ }
37
+
38
+ if (options.dryRun) {
39
+ return dryRun(options);
40
+ }
41
+
42
+ // Default: start batch
43
+ return startBatch(options);
44
+ }
45
+
46
+ /**
47
+ * Parse command line options
48
+ */
49
+ function parseOptions(args) {
50
+ const options = {};
51
+
52
+ for (let i = 0; i < args.length; i++) {
53
+ const arg = args[i];
54
+
55
+ if (arg === '--count' || arg === '-n') {
56
+ options.count = parseInt(args[++i], 10);
57
+ } else if (arg === '--dry-run' || arg === '-d') {
58
+ options.dryRun = true;
59
+ } else if (arg === '--priority' || arg === '-p') {
60
+ options.priority = args[++i]?.toLowerCase();
61
+ } else if (arg === '--resume' || arg === '-r') {
62
+ options.resume = true;
63
+ } else if (arg === '--skip') {
64
+ options.skip = true;
65
+ } else if (arg === '--force' || arg === '-f') {
66
+ options.skipGates = true;
67
+ } else if (arg === '--continue') {
68
+ options.continueOnError = true;
69
+ } else if (arg === '--no-commit') {
70
+ options.skipCommit = true;
71
+ } else if (arg === '--no-branch') {
72
+ options.skipBranch = true;
73
+ } else if (arg === '--help' || arg === '-h') {
74
+ showHelp();
75
+ process.exit(0);
76
+ }
77
+ }
78
+
79
+ return options;
80
+ }
81
+
82
+ /**
83
+ * Show batch status
84
+ */
85
+ function showStatus() {
86
+ const status = batch.getStatus();
87
+
88
+ if (!status.hasWorkspace) {
89
+ console.log('❌ No PWN workspace found');
90
+ process.exit(1);
91
+ }
92
+
93
+ console.log('📋 Batch Status\n');
94
+
95
+ // Running state
96
+ if (status.isRunning) {
97
+ console.log(` Status: 🔄 Running`);
98
+ console.log(` Current Task: ${status.currentTask || '(selecting)'}`);
99
+ } else if (status.isPaused) {
100
+ console.log(` Status: ⏸️ Paused`);
101
+ console.log(` Current Task: ${status.currentTask}`);
102
+ console.log(` Reason: ${status.pauseReason}`);
103
+ console.log('\n Resume with: pwn batch --resume');
104
+ console.log(' Skip task: pwn batch --resume --skip');
105
+ } else {
106
+ console.log(' Status: ⏹️ Idle');
107
+ }
108
+
109
+ // Task counts
110
+ console.log('\n📝 Tasks\n');
111
+ console.log(` Active: ${status.tasks.activePending} pending, ${status.tasks.activeCompleted} completed`);
112
+ console.log(` Backlog: ${status.tasks.backlogTotal} total`);
113
+ if (status.tasks.backlogTotal > 0) {
114
+ console.log(` - High: ${status.tasks.backlogHigh}`);
115
+ console.log(` - Medium: ${status.tasks.backlogMedium}`);
116
+ console.log(` - Low: ${status.tasks.backlogLow}`);
117
+ }
118
+
119
+ // Batch history
120
+ if (status.batchState?.completed?.length > 0) {
121
+ console.log('\n✅ Completed this batch\n');
122
+ for (const taskId of status.batchState.completed) {
123
+ console.log(` - ${taskId}`);
124
+ }
125
+ }
126
+
127
+ // Next task preview
128
+ const nextTask = batch.selectNextTask();
129
+ if (nextTask) {
130
+ console.log('\n🎯 Next Task\n');
131
+ console.log(` ${nextTask.id}: ${nextTask.title}`);
132
+ if (nextTask.priority) {
133
+ console.log(` Priority: ${nextTask.priority}`);
134
+ }
135
+ } else {
136
+ console.log('\n No tasks available in backlog');
137
+ }
138
+ }
139
+
140
+ /**
141
+ * Show batch configuration
142
+ */
143
+ function showConfig() {
144
+ const config = batch.loadConfig();
145
+
146
+ console.log('⚙️ Batch Configuration\n');
147
+ console.log(` Max Tasks: ${config.max_tasks}`);
148
+ console.log(` Max Duration: ${config.max_duration_hours} hours`);
149
+ console.log(` Selection: ${config.selection_strategy}`);
150
+ console.log(`\n Quality Gates: ${config.quality_gates.join(', ') || '(none)'}`);
151
+ if (config.skip_gates.length > 0) {
152
+ console.log(` Skip Gates: ${config.skip_gates.join(', ')}`);
153
+ }
154
+ console.log(`\n Auto Commit: ${config.auto_commit ? 'Yes' : 'No'}`);
155
+ console.log(` Auto Push: ${config.auto_push ? 'Yes' : 'No'}`);
156
+ console.log(` Create PR: ${config.create_pr ? 'Yes' : 'No'}`);
157
+ console.log(` Branch Format: ${config.branch_format}`);
158
+ console.log(` Commit Format: ${config.commit_format}`);
159
+ console.log(`\n Notify Complete: ${config.notify_on_complete ? 'Yes' : 'No'}`);
160
+ console.log(` Notify Error: ${config.notify_on_error ? 'Yes' : 'No'}`);
161
+ console.log('\n📁 Config location: .ai/state.json (batch_config)');
162
+ }
163
+
164
+ /**
165
+ * Dry run - show what would execute
166
+ */
167
+ async function dryRun(options) {
168
+ console.log('🔍 Dry Run - Preview batch execution\n');
169
+
170
+ const config = batch.loadConfig();
171
+ const count = options.count || config.max_tasks;
172
+
173
+ console.log(` Would execute up to ${count} tasks\n`);
174
+
175
+ // Show tasks that would be selected
176
+ const tasks = [];
177
+ for (let i = 0; i < count; i++) {
178
+ // Note: This is a simplified preview - actual selection happens one at a time
179
+ const task = batch.selectNextTask(process.cwd(), { priority: options.priority });
180
+ if (!task) break;
181
+
182
+ // Skip already seen tasks for preview
183
+ if (tasks.find(t => t.id === task.id)) break;
184
+ tasks.push(task);
185
+ }
186
+
187
+ if (tasks.length === 0) {
188
+ console.log(' No tasks available in backlog');
189
+ return;
190
+ }
191
+
192
+ console.log(' Tasks to execute:\n');
193
+ for (let i = 0; i < tasks.length; i++) {
194
+ const task = tasks[i];
195
+ const priority = task.priority ? ` (${task.priority})` : '';
196
+ console.log(` ${i + 1}. ${task.id}: ${task.title}${priority}`);
197
+ }
198
+
199
+ console.log('\n Quality gates that would run:');
200
+ for (const gate of config.quality_gates) {
201
+ if (config.skip_gates.includes(gate)) {
202
+ console.log(` ⏭️ ${gate} (skipped)`);
203
+ } else {
204
+ console.log(` ✓ ${gate}`);
205
+ }
206
+ }
207
+
208
+ if (options.skipGates) {
209
+ console.log('\n ⚠️ Gates would be skipped due to --force flag');
210
+ }
211
+
212
+ console.log('\n Run without --dry-run to execute');
213
+ }
214
+
215
+ /**
216
+ * Start batch execution
217
+ */
218
+ async function startBatch(options) {
219
+ const config = batch.loadConfig();
220
+ const count = options.count || config.max_tasks;
221
+
222
+ console.log('🚀 Starting batch execution\n');
223
+ console.log(` Max tasks: ${count}`);
224
+ console.log(` Quality gates: ${options.skipGates ? 'Skipped' : config.quality_gates.join(', ')}`);
225
+ console.log('');
226
+
227
+ const startTime = Date.now();
228
+
229
+ const result = await batch.startBatch({
230
+ count,
231
+ priority: options.priority,
232
+ skipGates: options.skipGates,
233
+ skipCommit: options.skipCommit,
234
+ skipBranch: options.skipBranch,
235
+ continueOnError: options.continueOnError
236
+ });
237
+
238
+ const duration = Math.round((Date.now() - startTime) / 1000);
239
+
240
+ console.log('');
241
+
242
+ if (result.completed.length > 0) {
243
+ console.log('✅ Completed tasks:\n');
244
+ for (const task of result.completed) {
245
+ console.log(` - ${task.id}: ${task.title}`);
246
+ }
247
+ }
248
+
249
+ if (result.errors.length > 0) {
250
+ console.log('\n❌ Failed tasks:\n');
251
+ for (const error of result.errors) {
252
+ console.log(` - ${error.id}: ${error.error}`);
253
+ }
254
+ }
255
+
256
+ console.log(`\n⏱️ Duration: ${duration}s`);
257
+ console.log(`📊 Summary: ${result.completed.length} completed, ${result.errors.length} failed`);
258
+
259
+ if (!result.success) {
260
+ console.log('\n💡 To resume: pwn batch --resume');
261
+ console.log(' To skip: pwn batch --resume --skip');
262
+ process.exit(1);
263
+ }
264
+ }
265
+
266
+ /**
267
+ * Resume paused batch
268
+ */
269
+ async function resumeBatch(options) {
270
+ const status = batch.getStatus();
271
+
272
+ if (!status.isPaused) {
273
+ console.log('❌ No paused batch to resume\n');
274
+ console.log(' Current status:', status.isRunning ? 'Running' : 'Idle');
275
+ process.exit(1);
276
+ }
277
+
278
+ console.log('▶️ Resuming batch execution\n');
279
+
280
+ if (options.skip) {
281
+ console.log(` Skipping task: ${status.currentTask}`);
282
+ }
283
+
284
+ console.log('');
285
+
286
+ const result = await batch.resumeBatch({
287
+ skip: options.skip,
288
+ skipGates: options.skipGates
289
+ });
290
+
291
+ if (!result.success) {
292
+ console.log(`❌ ${result.message}`);
293
+ process.exit(1);
294
+ }
295
+
296
+ console.log(`\n✅ Batch resumed`);
297
+ console.log(` Completed: ${result.completed?.length || 0} tasks`);
298
+ }
299
+
300
+ /**
301
+ * Show help
302
+ */
303
+ function showHelp() {
304
+ console.log('🚀 PWN Batch Execution\n');
305
+ console.log('Usage: pwn batch [command] [options]\n');
306
+ console.log('Commands:');
307
+ console.log(' (default) Execute next available task(s)');
308
+ console.log(' status Show batch status');
309
+ console.log(' config Show batch configuration\n');
310
+ console.log('Options:');
311
+ console.log(' --count, -n <num> Execute specific number of tasks');
312
+ console.log(' --dry-run, -d Preview what would execute');
313
+ console.log(' --priority, -p <level> Filter by priority (high, medium, low)');
314
+ console.log(' --resume, -r Resume interrupted batch');
315
+ console.log(' --skip Skip current task when resuming');
316
+ console.log(' --force, -f Skip quality gates');
317
+ console.log(' --continue Continue on errors');
318
+ console.log(' --no-commit Skip auto-commit');
319
+ console.log(' --no-branch Skip branch creation');
320
+ console.log(' --help, -h Show this help\n');
321
+ console.log('Examples:');
322
+ console.log(' pwn batch # Execute next task');
323
+ console.log(' pwn batch --count 5 # Execute 5 tasks');
324
+ console.log(' pwn batch --dry-run # Preview execution');
325
+ console.log(' pwn batch --priority high # Only high priority');
326
+ console.log(' pwn batch --resume # Resume paused batch');
327
+ console.log(' pwn batch --resume --skip # Resume, skip current');
328
+ console.log(' pwn batch status # Show status');
329
+ console.log(' pwn batch config # Show configuration\n');
330
+ console.log('Configuration:');
331
+ console.log(' Edit .ai/state.json and add batch_config object.');
332
+ console.log(' See .ai/workflows/batch-task.md for full documentation.');
333
+ }