@fermindi/pwn-cli 0.1.1 → 0.2.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 (46) 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 +98 -91
  6. package/cli/inject.js +78 -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/status.js +91 -91
  12. package/cli/validate.js +61 -61
  13. package/package.json +70 -70
  14. package/src/core/inject.js +208 -204
  15. package/src/core/state.js +91 -91
  16. package/src/core/validate.js +202 -202
  17. package/src/core/workspace.js +176 -176
  18. package/src/index.js +20 -20
  19. package/src/knowledge/gc.js +308 -308
  20. package/src/knowledge/lifecycle.js +401 -401
  21. package/src/knowledge/promote.js +364 -364
  22. package/src/knowledge/references.js +342 -342
  23. package/src/patterns/matcher.js +218 -218
  24. package/src/patterns/registry.js +375 -375
  25. package/src/patterns/triggers.js +423 -423
  26. package/src/services/batch-service.js +849 -849
  27. package/src/services/notification-service.js +342 -342
  28. package/templates/codespaces/devcontainer.json +52 -52
  29. package/templates/codespaces/setup.sh +70 -70
  30. package/templates/workspace/.ai/README.md +164 -164
  31. package/templates/workspace/.ai/agents/README.md +204 -204
  32. package/templates/workspace/.ai/agents/claude.md +625 -625
  33. package/templates/workspace/.ai/config/README.md +79 -79
  34. package/templates/workspace/.ai/config/notifications.template.json +20 -20
  35. package/templates/workspace/.ai/memory/deadends.md +79 -79
  36. package/templates/workspace/.ai/memory/decisions.md +58 -58
  37. package/templates/workspace/.ai/memory/patterns.md +65 -65
  38. package/templates/workspace/.ai/patterns/backend/README.md +126 -126
  39. package/templates/workspace/.ai/patterns/frontend/README.md +103 -103
  40. package/templates/workspace/.ai/patterns/index.md +256 -256
  41. package/templates/workspace/.ai/patterns/triggers.json +1087 -1087
  42. package/templates/workspace/.ai/patterns/universal/README.md +141 -141
  43. package/templates/workspace/.ai/state.template.json +8 -8
  44. package/templates/workspace/.ai/tasks/active.md +77 -77
  45. package/templates/workspace/.ai/tasks/backlog.md +95 -95
  46. 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
+ }