@fermindi/pwn-cli 0.1.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 -0
  2. package/README.md +251 -0
  3. package/cli/batch.js +333 -0
  4. package/cli/codespaces.js +303 -0
  5. package/cli/index.js +91 -0
  6. package/cli/inject.js +53 -0
  7. package/cli/knowledge.js +531 -0
  8. package/cli/notify.js +135 -0
  9. package/cli/patterns.js +665 -0
  10. package/cli/status.js +91 -0
  11. package/cli/validate.js +61 -0
  12. package/package.json +70 -0
  13. package/src/core/inject.js +128 -0
  14. package/src/core/state.js +91 -0
  15. package/src/core/validate.js +202 -0
  16. package/src/core/workspace.js +176 -0
  17. package/src/index.js +20 -0
  18. package/src/knowledge/gc.js +308 -0
  19. package/src/knowledge/lifecycle.js +401 -0
  20. package/src/knowledge/promote.js +364 -0
  21. package/src/knowledge/references.js +342 -0
  22. package/src/patterns/matcher.js +218 -0
  23. package/src/patterns/registry.js +375 -0
  24. package/src/patterns/triggers.js +423 -0
  25. package/src/services/batch-service.js +849 -0
  26. package/src/services/notification-service.js +342 -0
  27. package/templates/codespaces/devcontainer.json +52 -0
  28. package/templates/codespaces/setup.sh +70 -0
  29. package/templates/workspace/.ai/README.md +164 -0
  30. package/templates/workspace/.ai/agents/README.md +204 -0
  31. package/templates/workspace/.ai/agents/claude.md +625 -0
  32. package/templates/workspace/.ai/config/.gitkeep +0 -0
  33. package/templates/workspace/.ai/config/README.md +79 -0
  34. package/templates/workspace/.ai/config/notifications.template.json +20 -0
  35. package/templates/workspace/.ai/memory/deadends.md +79 -0
  36. package/templates/workspace/.ai/memory/decisions.md +58 -0
  37. package/templates/workspace/.ai/memory/patterns.md +65 -0
  38. package/templates/workspace/.ai/patterns/backend/README.md +126 -0
  39. package/templates/workspace/.ai/patterns/frontend/README.md +103 -0
  40. package/templates/workspace/.ai/patterns/index.md +256 -0
  41. package/templates/workspace/.ai/patterns/triggers.json +1087 -0
  42. package/templates/workspace/.ai/patterns/universal/README.md +141 -0
  43. package/templates/workspace/.ai/state.template.json +8 -0
  44. package/templates/workspace/.ai/tasks/active.md +77 -0
  45. package/templates/workspace/.ai/tasks/backlog.md +95 -0
  46. package/templates/workspace/.ai/workflows/batch-task.md +356 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Diego Fernandes
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,251 @@
1
+ # PWN - Professional AI Workspace
2
+
3
+ **Inject structured memory and automation into any project for AI-powered development.**
4
+
5
+ PWN gives AI agents like Claude Code persistent memory, auto-applied patterns, and batch execution capabilities.
6
+
7
+ ## Quick Start
8
+
9
+ ```bash
10
+ # Install globally
11
+ npm install -g pwn-cli
12
+
13
+ # Inject into your project
14
+ cd your-project
15
+ pwn inject
16
+
17
+ # Check status
18
+ pwn status
19
+
20
+ # Add Codespaces support (optional)
21
+ pwn codespaces init
22
+ ```
23
+
24
+ ## What PWN Does
25
+
26
+ | Without PWN | With PWN |
27
+ |-------------|----------|
28
+ | AI forgets decisions between sessions | Decisions persist in `.ai/memory/` |
29
+ | Repeats failed approaches | Dead-ends documented and avoided |
30
+ | No project-specific patterns | Auto-applies patterns by context |
31
+ | Manual task tracking | Structured task management |
32
+ | No learning consolidation | Knowledge promotes to patterns |
33
+
34
+ ## Commands
35
+
36
+ ```bash
37
+ # Core
38
+ pwn inject # Inject .ai/ workspace
39
+ pwn status # Show workspace status
40
+ pwn validate # Validate structure
41
+
42
+ # Notifications
43
+ pwn notify test # Test notification channels
44
+ pwn notify send "msg" # Send notification
45
+
46
+ # Batch Execution
47
+ pwn batch # Execute next task
48
+ pwn batch --count 5 # Execute 5 tasks
49
+ pwn batch status # Show progress
50
+
51
+ # Patterns
52
+ pwn patterns list # List all patterns
53
+ pwn patterns eval file # Check triggers for file
54
+ pwn patterns search q # Search patterns
55
+
56
+ # Knowledge Lifecycle
57
+ pwn knowledge status # Show knowledge stats
58
+ pwn knowledge sync # Sync with markdown
59
+ pwn knowledge gc # Garbage collection
60
+ pwn knowledge promote # Promote to pattern
61
+
62
+ # Codespaces
63
+ pwn codespaces init # Add devcontainer
64
+ pwn codespaces status # Check config
65
+ pwn codespaces open # Open in Codespace
66
+ ```
67
+
68
+ ## Project Structure After Injection
69
+
70
+ ```
71
+ your-project/
72
+ ├── .ai/
73
+ │ ├── state.json # Session state (git-ignored)
74
+ │ ├── memory/
75
+ │ │ ├── decisions.md # Architectural decisions (DEC-XXX)
76
+ │ │ ├── patterns.md # Learned patterns
77
+ │ │ └── deadends.md # Failed approaches (DE-XXX)
78
+ │ ├── tasks/
79
+ │ │ ├── active.md # Current work
80
+ │ │ └── backlog.md # Future work
81
+ │ ├── patterns/
82
+ │ │ ├── index.md # Trigger mappings
83
+ │ │ ├── frontend/ # React, Vue, etc.
84
+ │ │ ├── backend/ # Express, FastAPI, etc.
85
+ │ │ └── universal/ # Testing, TypeScript, etc.
86
+ │ ├── workflows/
87
+ │ │ └── batch-task.md # Batch execution guide
88
+ │ ├── agents/
89
+ │ │ └── claude.md # Claude Code bootstrap (600+ lines)
90
+ │ └── config/ # Local config (git-ignored)
91
+ └── ... your project files
92
+ ```
93
+
94
+ ## Features
95
+
96
+ ### Memory System
97
+
98
+ Document decisions that AI agents will remember:
99
+
100
+ ```markdown
101
+ ## DEC-001: Use TypeScript Strict Mode
102
+ **Date:** 2026-01-22
103
+ **Status:** Active
104
+ **Context:** Need better type safety
105
+ **Decision:** Enable strict mode in tsconfig
106
+ **Rationale:** Catches bugs at compile time
107
+ ```
108
+
109
+ ### Pattern Auto-Apply
110
+
111
+ Triggers automatically load relevant patterns:
112
+
113
+ ```
114
+ *.tsx → frontend/react/
115
+ *.test.ts → universal/testing/
116
+ routes/*.ts → backend/express/
117
+ prisma/schema → backend/prisma/
118
+ ```
119
+
120
+ ### Knowledge Lifecycle
121
+
122
+ Knowledge evolves based on usage:
123
+
124
+ ```
125
+ CREATE → REFERENCE → EVOLVE → PROMOTE/GC
126
+ │ │ │ │
127
+ ▼ ▼ ▼ ▼
128
+ decisions tracking patterns cleanup
129
+ ```
130
+
131
+ - **Promote:** Applied 3+ times in 2+ contexts → becomes pattern
132
+ - **Archive:** No references for 30+ days
133
+ - **GC:** Orphaned with no related code
134
+
135
+ ### Batch Execution
136
+
137
+ Execute tasks autonomously:
138
+
139
+ ```bash
140
+ pwn batch --count 5 --priority high
141
+ ```
142
+
143
+ Features:
144
+ - Quality gates (lint, test, typecheck)
145
+ - Checkpoint-based pause/resume
146
+ - Auto-commit after each task
147
+ - Notifications on completion
148
+
149
+ ### Codespaces Integration
150
+
151
+ Work from anywhere (including mobile):
152
+
153
+ ```bash
154
+ pwn codespaces init
155
+ git push
156
+ # Open in GitHub Codespaces
157
+ ```
158
+
159
+ Pre-configured with:
160
+ - Node.js 22
161
+ - VSCode extensions (ESLint, Prettier, GitLens, Copilot, Claude)
162
+ - Bash aliases (`p`, `ps`, `pb`, `pk`)
163
+ - Auto PWN setup
164
+
165
+ ## Usage with Claude Code
166
+
167
+ After `pwn inject`, Claude Code will:
168
+
169
+ 1. Read `.ai/agents/claude.md` for bootstrap protocol
170
+ 2. Load memory (decisions, patterns, dead-ends)
171
+ 3. Check active tasks
172
+ 4. Auto-apply patterns based on context
173
+ 5. Reference decisions in responses
174
+
175
+ ## Installation
176
+
177
+ ```bash
178
+ # npm
179
+ npm install -g pwn-cli
180
+
181
+ # Or run directly
182
+ npx pwn-cli inject
183
+ ```
184
+
185
+ Requirements:
186
+ - Node.js 18+
187
+ - Git (for username detection)
188
+
189
+ ## Configuration
190
+
191
+ ### Notifications
192
+
193
+ Edit `.ai/config/notifications.json`:
194
+
195
+ ```json
196
+ {
197
+ "channels": {
198
+ "ntfy": {
199
+ "enabled": true,
200
+ "topic": "pwn-abc123"
201
+ }
202
+ }
203
+ }
204
+ ```
205
+
206
+ ### Quality Gates
207
+
208
+ Configure in `.ai/workflows/batch-task.md`:
209
+
210
+ ```yaml
211
+ gates:
212
+ typecheck: true
213
+ lint: true
214
+ test: true
215
+ build: false
216
+ ```
217
+
218
+ ## Development
219
+
220
+ ```bash
221
+ git clone https://github.com/diegofornalha/pwn.git
222
+ cd pwn
223
+ pnpm install
224
+ pnpm test
225
+ npm link # For local testing
226
+ ```
227
+
228
+ ## Roadmap
229
+
230
+ - [x] Phase 0: Core workspace injection
231
+ - [x] Phase 1: Multi-channel notifications
232
+ - [x] Phase 2: GitHub Codespaces integration
233
+ - [x] Phase 3: Autonomous batch execution
234
+ - [x] Phase 4: Advanced pattern system
235
+ - [x] Phase 5: Knowledge lifecycle
236
+ - [x] Phase 6: npm publish
237
+ - [ ] `pwn create` - Scaffold new projects
238
+ - [ ] `pwn upgrade` - Update existing workspaces
239
+ - [ ] Docker support
240
+
241
+ ## Contributing
242
+
243
+ Contributions welcome! See [CONTRIBUTING.md](CONTRIBUTING.md).
244
+
245
+ ## License
246
+
247
+ MIT - see [LICENSE](LICENSE)
248
+
249
+ ---
250
+
251
+ **Version:** 0.1.0 | **Status:** Production Ready
package/cli/batch.js ADDED
@@ -0,0 +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
+ }