@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.
- package/LICENSE +21 -0
- package/README.md +251 -0
- package/cli/batch.js +333 -0
- package/cli/codespaces.js +303 -0
- package/cli/index.js +91 -0
- package/cli/inject.js +53 -0
- package/cli/knowledge.js +531 -0
- package/cli/notify.js +135 -0
- package/cli/patterns.js +665 -0
- package/cli/status.js +91 -0
- package/cli/validate.js +61 -0
- package/package.json +70 -0
- package/src/core/inject.js +128 -0
- package/src/core/state.js +91 -0
- package/src/core/validate.js +202 -0
- package/src/core/workspace.js +176 -0
- package/src/index.js +20 -0
- package/src/knowledge/gc.js +308 -0
- package/src/knowledge/lifecycle.js +401 -0
- package/src/knowledge/promote.js +364 -0
- package/src/knowledge/references.js +342 -0
- package/src/patterns/matcher.js +218 -0
- package/src/patterns/registry.js +375 -0
- package/src/patterns/triggers.js +423 -0
- package/src/services/batch-service.js +849 -0
- package/src/services/notification-service.js +342 -0
- package/templates/codespaces/devcontainer.json +52 -0
- package/templates/codespaces/setup.sh +70 -0
- package/templates/workspace/.ai/README.md +164 -0
- package/templates/workspace/.ai/agents/README.md +204 -0
- package/templates/workspace/.ai/agents/claude.md +625 -0
- package/templates/workspace/.ai/config/.gitkeep +0 -0
- package/templates/workspace/.ai/config/README.md +79 -0
- package/templates/workspace/.ai/config/notifications.template.json +20 -0
- package/templates/workspace/.ai/memory/deadends.md +79 -0
- package/templates/workspace/.ai/memory/decisions.md +58 -0
- package/templates/workspace/.ai/memory/patterns.md +65 -0
- package/templates/workspace/.ai/patterns/backend/README.md +126 -0
- package/templates/workspace/.ai/patterns/frontend/README.md +103 -0
- package/templates/workspace/.ai/patterns/index.md +256 -0
- package/templates/workspace/.ai/patterns/triggers.json +1087 -0
- package/templates/workspace/.ai/patterns/universal/README.md +141 -0
- package/templates/workspace/.ai/state.template.json +8 -0
- package/templates/workspace/.ai/tasks/active.md +77 -0
- package/templates/workspace/.ai/tasks/backlog.md +95 -0
- 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
|
+
}
|