@agentic15.com/agentic15-claude-zen 4.1.6 → 4.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentic15.com/agentic15-claude-zen",
3
- "version": "4.1.6",
3
+ "version": "4.2.0",
4
4
  "description": "Structured AI-assisted development framework for Claude Code with enforced quality standards",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -267,6 +267,11 @@ export class CommitCommand {
267
267
  if (taskInTracker) {
268
268
  taskInTracker.status = 'completed';
269
269
  taskInTracker.completedAt = new Date().toISOString();
270
+
271
+ // Clear active task and update statistics
272
+ tracker.activeTask = null;
273
+ this.updateStatistics(tracker);
274
+
270
275
  writeFileSync(trackerPath, JSON.stringify(tracker, null, 2));
271
276
  console.log(`\n✅ Marked ${task.id} as completed`);
272
277
  }
@@ -276,6 +281,20 @@ export class CommitCommand {
276
281
  }
277
282
  }
278
283
 
284
+ static updateStatistics(tracker) {
285
+ const completed = tracker.taskFiles.filter(t => t.status === 'completed').length;
286
+ const inProgress = tracker.taskFiles.filter(t => t.status === 'in_progress').length;
287
+ const pending = tracker.taskFiles.filter(t => t.status === 'pending').length;
288
+ const totalTasks = tracker.taskFiles.length;
289
+
290
+ tracker.statistics = {
291
+ totalTasks,
292
+ completed,
293
+ inProgress,
294
+ pending
295
+ };
296
+ }
297
+
279
298
  static displaySummary(task, prUrl, tracker) {
280
299
  console.log('\n┌─────────────────────────────────────────┐');
281
300
  console.log('│ ✅ Commit Workflow Complete │');
@@ -1,282 +1,291 @@
1
- import { readFileSync, writeFileSync, existsSync, mkdirSync, readdirSync } from 'fs';
2
- import { join } from 'path';
3
- import readline from 'readline';
4
-
5
- export class PlanCommand {
6
- static async handle(description) {
7
- // Check if plan already exists
8
- const activePlanPath = join(process.cwd(), '.claude', 'ACTIVE-PLAN');
9
-
10
- if (existsSync(activePlanPath)) {
11
- const planId = readFileSync(activePlanPath, 'utf-8').trim();
12
- const planPath = join(process.cwd(), '.claude', 'plans', planId);
13
- const projectPlanPath = join(planPath, 'PROJECT-PLAN.json');
14
-
15
- // Check if plan file exists
16
- if (existsSync(projectPlanPath)) {
17
- // Plan exists, check if it's locked
18
- const lockedPath = join(planPath, '.plan-locked');
19
-
20
- if (existsSync(lockedPath)) {
21
- console.log('\n⚠️ Plan already locked');
22
- console.log(` Plan: ${planId}\n`);
23
- this.showPlanStatus(planId);
24
- process.exit(0);
25
- }
26
-
27
- // Plan exists but not locked - lock it
28
- console.log('\n📋 Found existing plan, locking it...\n');
29
- return this.lockPlan(planId);
30
- } else {
31
- // Requirements exist but plan not created yet
32
- console.log('\n⚠️ Waiting for PROJECT-PLAN.json');
33
- console.log(` Tell Claude: "Create the project plan"\n`);
34
- process.exit(0);
35
- }
36
- }
37
-
38
- // No plan exists - create new one
39
- if (!description) {
40
- // No description provided - enter interactive mode
41
- console.log('\n📝 Interactive Requirements Mode');
42
- console.log('━'.repeat(70));
43
- console.log('Enter your project requirements below.');
44
- console.log('You can paste multiple lines, URLs, or write detailed specs.');
45
- console.log('Press Ctrl+D (Mac/Linux) or Ctrl+Z then Enter (Windows) when done.\n');
46
-
47
- description = await this.promptMultilineInput();
48
-
49
- if (!description || description.trim().length === 0) {
50
- console.log('\n❌ No requirements provided\n');
51
- process.exit(1);
52
- }
53
- }
54
-
55
- return this.generatePlan(description);
56
- }
57
-
58
- static async promptMultilineInput() {
59
- return new Promise((resolve) => {
60
- const rl = readline.createInterface({
61
- input: process.stdin,
62
- output: process.stdout
63
- });
64
-
65
- let lines = [];
66
-
67
- rl.on('line', (line) => {
68
- lines.push(line);
69
- });
70
-
71
- rl.on('close', () => {
72
- resolve(lines.join('\n'));
73
- });
74
- });
75
- }
76
-
77
- static generatePlan(description) {
78
- console.log('\n📋 Generating new plan...\n');
79
-
80
- try {
81
- // Create plan ID
82
- const planId = this.getNextPlanId();
83
- const planPath = join(process.cwd(), '.claude', 'plans', planId);
84
-
85
- // Create plan directory
86
- mkdirSync(planPath, { recursive: true });
87
-
88
- // Create PROJECT-REQUIREMENTS.txt
89
- const requirementsPath = join(planPath, 'PROJECT-REQUIREMENTS.txt');
90
- const requirementsContent = `PROJECT REQUIREMENTS
91
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
92
-
93
- ${description}
94
-
95
- Generated: ${new Date().toISOString()}
96
- PLAN ID: ${planId}
97
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
98
-
99
- INSTRUCTIONS FOR CLAUDE
100
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
101
-
102
- Please analyze the requirements above and create a comprehensive project plan.
103
-
104
- 1. Read the PLAN-SCHEMA.json to understand the plan structure
105
- 2. Read the PROJECT-PLAN-TEMPLATE.json for the format
106
- 3. Create a PROJECT-PLAN.json file in this directory with:
107
- - Clear project/subproject/milestone hierarchy
108
- - Detailed tasks with IDs (TASK-001, TASK-002, etc.)
109
- - Proper dependencies between tasks
110
- - Realistic time estimates
111
- - Phases: design, implementation, testing, deployment
112
- - Completion criteria for each task
113
-
114
- 4. Structure the plan to follow these phases:
115
- - DESIGN: Architecture, UI/UX, database schema
116
- - IMPLEMENTATION: Core features, API, frontend
117
- - TESTING: Unit tests, integration tests, E2E tests
118
- - DEPLOYMENT: Build, CI/CD, documentation
119
-
120
- 5. Ensure tasks are:
121
- - Granular (2-8 hours each)
122
- - Clearly defined with specific deliverables
123
- - Properly sequenced with dependencies
124
- - Grouped logically by feature/component
125
-
126
- 6. After creating the plan, tell the user to run:
127
- npx agentic15 plan
128
-
129
- This will lock the plan and generate the task tracker.
130
-
131
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
132
- GENERATED: ${new Date().toISOString()}
133
- `;
134
-
135
- writeFileSync(requirementsPath, requirementsContent);
136
-
137
- // Set as active plan
138
- const claudeDir = join(process.cwd(), '.claude');
139
- if (!existsSync(claudeDir)) {
140
- mkdirSync(claudeDir, { recursive: true });
141
- }
142
- const activePlanPath = join(claudeDir, 'ACTIVE-PLAN');
143
- writeFileSync(activePlanPath, planId);
144
-
145
- console.log(`✅ Plan requirements created: ${planId}`);
146
- console.log(` Location: .claude/plans/${planId}/PROJECT-REQUIREMENTS.txt\n`);
147
- console.log('💡 Next steps:');
148
- console.log(` 1. Tell Claude: "Create the project plan"`);
149
- console.log(` 2. When Claude is done, run: npx agentic15 plan\n`);
150
- } catch (error) {
151
- console.log(`\n❌ Failed to generate plan: ${error.message}\n`);
152
- process.exit(1);
153
- }
154
- }
155
-
156
- static lockPlan(planId) {
157
- console.log(`📋 Locking plan: ${planId}\n`);
158
-
159
- try {
160
- const planPath = join(process.cwd(), '.claude', 'plans', planId);
161
- const projectPlanPath = join(planPath, 'PROJECT-PLAN.json');
162
-
163
- // Verify PROJECT-PLAN.json exists
164
- if (!existsSync(projectPlanPath)) {
165
- console.log('\n❌ PROJECT-PLAN.json not found');
166
- console.log(' Tell Claude to create the plan first\n');
167
- process.exit(1);
168
- }
169
-
170
- // Read the plan
171
- const plan = JSON.parse(readFileSync(projectPlanPath, 'utf-8'));
172
-
173
- // Extract tasks from plan
174
- const tasks = [];
175
- this.extractTasks(plan, tasks);
176
-
177
- // Create task files
178
- const tasksDir = join(planPath, 'tasks');
179
- if (!existsSync(tasksDir)) {
180
- mkdirSync(tasksDir, { recursive: true });
181
- }
182
-
183
- // Write individual task files
184
- tasks.forEach(task => {
185
- const taskPath = join(tasksDir, `${task.id}.json`);
186
- writeFileSync(taskPath, JSON.stringify(task, null, 2));
187
- });
188
-
189
- // Create task tracker
190
- const tracker = {
191
- planId,
192
- lockedAt: new Date().toISOString(),
193
- taskFiles: tasks.map(task => ({
194
- id: task.id,
195
- title: task.title,
196
- phase: task.phase || 'implementation',
197
- status: 'pending',
198
- description: task.description
199
- }))
200
- };
201
-
202
- const trackerPath = join(planPath, 'TASK-TRACKER.json');
203
- writeFileSync(trackerPath, JSON.stringify(tracker, null, 2));
204
-
205
- // Mark as locked
206
- const lockedPath = join(planPath, '.plan-locked');
207
- writeFileSync(lockedPath, new Date().toISOString());
208
-
209
- console.log('✅ Plan locked successfully\n');
210
- this.showPlanStatus(planId);
211
- console.log('💡 Next step: npx agentic15 task next\n');
212
- } catch (error) {
213
- console.log(`\n❌ Failed to lock plan: ${error.message}\n`);
214
- process.exit(1);
215
- }
216
- }
217
-
218
- static extractTasks(obj, tasks) {
219
- // Recursively extract all tasks from the plan structure
220
- if (obj.tasks && Array.isArray(obj.tasks)) {
221
- tasks.push(...obj.tasks);
222
- }
223
-
224
- // Check nested structures
225
- if (obj.milestones && Array.isArray(obj.milestones)) {
226
- obj.milestones.forEach(milestone => this.extractTasks(milestone, tasks));
227
- }
228
-
229
- if (obj.subprojects && Array.isArray(obj.subprojects)) {
230
- obj.subprojects.forEach(subproject => this.extractTasks(subproject, tasks));
231
- }
232
-
233
- if (obj.projects && Array.isArray(obj.projects)) {
234
- obj.projects.forEach(project => this.extractTasks(project, tasks));
235
- }
236
-
237
- // Handle singular 'project' at root level (v2.0 schema)
238
- if (obj.project && typeof obj.project === 'object') {
239
- this.extractTasks(obj.project, tasks);
240
- }
241
- }
242
-
243
- static getNextPlanId() {
244
- const plansDir = join(process.cwd(), '.claude', 'plans');
245
-
246
- if (!existsSync(plansDir)) {
247
- mkdirSync(plansDir, { recursive: true });
248
- }
249
-
250
- const existingPlans = readdirSync(plansDir)
251
- .filter(name => name.match(/^plan-\d{3}-/i))
252
- .map(name => parseInt(name.match(/^plan-(\d{3})-/i)[1]))
253
- .filter(num => !isNaN(num));
254
-
255
- const nextNum = existingPlans.length > 0 ? Math.max(...existingPlans) + 1 : 1;
256
-
257
- return `plan-${String(nextNum).padStart(3, '0')}-generated`;
258
- }
259
-
260
- static showPlanStatus(planId) {
261
- const trackerPath = join(process.cwd(), '.claude', 'plans', planId, 'TASK-TRACKER.json');
262
-
263
- if (!existsSync(trackerPath)) {
264
- return;
265
- }
266
-
267
- try {
268
- const tracker = JSON.parse(readFileSync(trackerPath, 'utf-8'));
269
-
270
- const total = tracker.taskFiles.length;
271
- const completed = tracker.taskFiles.filter(t => t.status === 'completed').length;
272
- const pending = tracker.taskFiles.filter(t => t.status === 'pending').length;
273
-
274
- console.log('📊 Plan Status:');
275
- console.log(` Total Tasks: ${total}`);
276
- console.log(` Completed: ${completed}`);
277
- console.log(` Pending: ${pending}\n`);
278
- } catch (e) {
279
- // Ignore errors
280
- }
281
- }
282
- }
1
+ import { readFileSync, writeFileSync, existsSync, mkdirSync, readdirSync } from 'fs';
2
+ import { join, basename } from 'path';
3
+ import readline from 'readline';
4
+
5
+ export class PlanCommand {
6
+ static async handle(description) {
7
+ // Check if plan already exists
8
+ const activePlanPath = join(process.cwd(), '.claude', 'ACTIVE-PLAN');
9
+
10
+ if (existsSync(activePlanPath)) {
11
+ const planId = readFileSync(activePlanPath, 'utf-8').trim();
12
+ const planPath = join(process.cwd(), '.claude', 'plans', planId);
13
+ const projectPlanPath = join(planPath, 'PROJECT-PLAN.json');
14
+
15
+ // Check if plan file exists
16
+ if (existsSync(projectPlanPath)) {
17
+ // Plan exists, check if it's locked
18
+ const lockedPath = join(planPath, '.plan-locked');
19
+
20
+ if (existsSync(lockedPath)) {
21
+ console.log('\n⚠️ Plan already locked');
22
+ console.log(` Plan: ${planId}\n`);
23
+ this.showPlanStatus(planId);
24
+ process.exit(0);
25
+ }
26
+
27
+ // Plan exists but not locked - lock it
28
+ console.log('\n📋 Found existing plan, locking it...\n');
29
+ return this.lockPlan(planId);
30
+ } else {
31
+ // Requirements exist but plan not created yet
32
+ console.log('\n⚠️ Waiting for PROJECT-PLAN.json');
33
+ console.log(` Tell Claude: "Create the project plan"\n`);
34
+ process.exit(0);
35
+ }
36
+ }
37
+
38
+ // No plan exists - create new one
39
+ if (!description) {
40
+ // No description provided - enter interactive mode
41
+ console.log('\n📝 Interactive Requirements Mode');
42
+ console.log('━'.repeat(70));
43
+ console.log('Enter your project requirements below.');
44
+ console.log('You can paste multiple lines, URLs, or write detailed specs.');
45
+ console.log('Press Ctrl+D (Mac/Linux) or Ctrl+Z then Enter (Windows) when done.\n');
46
+
47
+ description = await this.promptMultilineInput();
48
+
49
+ if (!description || description.trim().length === 0) {
50
+ console.log('\n❌ No requirements provided\n');
51
+ process.exit(1);
52
+ }
53
+ }
54
+
55
+ return this.generatePlan(description);
56
+ }
57
+
58
+ static async promptMultilineInput() {
59
+ return new Promise((resolve) => {
60
+ const rl = readline.createInterface({
61
+ input: process.stdin,
62
+ output: process.stdout
63
+ });
64
+
65
+ let lines = [];
66
+
67
+ rl.on('line', (line) => {
68
+ lines.push(line);
69
+ });
70
+
71
+ rl.on('close', () => {
72
+ resolve(lines.join('\n'));
73
+ });
74
+ });
75
+ }
76
+
77
+ static generatePlan(description) {
78
+ console.log('\n📋 Generating new plan...\n');
79
+
80
+ try {
81
+ // Create plan ID
82
+ const planId = this.getNextPlanId();
83
+ const planPath = join(process.cwd(), '.claude', 'plans', planId);
84
+
85
+ // Create plan directory
86
+ mkdirSync(planPath, { recursive: true });
87
+
88
+ // Create PROJECT-REQUIREMENTS.txt
89
+ const requirementsPath = join(planPath, 'PROJECT-REQUIREMENTS.txt');
90
+ const requirementsContent = `PROJECT REQUIREMENTS
91
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
92
+
93
+ ${description}
94
+
95
+ Generated: ${new Date().toISOString()}
96
+ PLAN ID: ${planId}
97
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
98
+
99
+ INSTRUCTIONS FOR CLAUDE
100
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
101
+
102
+ Please analyze the requirements above and create a comprehensive project plan.
103
+
104
+ 1. Read the PLAN-SCHEMA.json to understand the plan structure
105
+ 2. Read the PROJECT-PLAN-TEMPLATE.json for the format
106
+ 3. Create a PROJECT-PLAN.json file in this directory with:
107
+ - Clear project/subproject/milestone hierarchy
108
+ - Detailed tasks with IDs (TASK-001, TASK-002, etc.)
109
+ - Proper dependencies between tasks
110
+ - Realistic time estimates
111
+ - Phases: design, implementation, testing, deployment
112
+ - Completion criteria for each task
113
+
114
+ 4. Structure the plan to follow these phases:
115
+ - DESIGN: Architecture, UI/UX, database schema
116
+ - IMPLEMENTATION: Core features, API, frontend
117
+ - TESTING: Unit tests, integration tests, E2E tests
118
+ - DEPLOYMENT: Build, CI/CD, documentation
119
+
120
+ 5. Ensure tasks are:
121
+ - Granular (2-8 hours each)
122
+ - Clearly defined with specific deliverables
123
+ - Properly sequenced with dependencies
124
+ - Grouped logically by feature/component
125
+
126
+ 6. After creating the plan, tell the user to run:
127
+ npx agentic15 plan
128
+
129
+ This will lock the plan and generate the task tracker.
130
+
131
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
132
+ GENERATED: ${new Date().toISOString()}
133
+ `;
134
+
135
+ writeFileSync(requirementsPath, requirementsContent);
136
+
137
+ // Set as active plan
138
+ const claudeDir = join(process.cwd(), '.claude');
139
+ if (!existsSync(claudeDir)) {
140
+ mkdirSync(claudeDir, { recursive: true });
141
+ }
142
+ const activePlanPath = join(claudeDir, 'ACTIVE-PLAN');
143
+ writeFileSync(activePlanPath, planId);
144
+
145
+ console.log(`✅ Plan requirements created: ${planId}`);
146
+ console.log(` Location: .claude/plans/${planId}/PROJECT-REQUIREMENTS.txt\n`);
147
+ console.log('💡 Next steps:');
148
+ console.log(` 1. Tell Claude: "Create the project plan"`);
149
+ console.log(` 2. When Claude is done, run: npx agentic15 plan\n`);
150
+ } catch (error) {
151
+ console.log(`\n❌ Failed to generate plan: ${error.message}\n`);
152
+ process.exit(1);
153
+ }
154
+ }
155
+
156
+ static lockPlan(planId) {
157
+ console.log(`📋 Locking plan: ${planId}\n`);
158
+
159
+ try {
160
+ const planPath = join(process.cwd(), '.claude', 'plans', planId);
161
+ const projectPlanPath = join(planPath, 'PROJECT-PLAN.json');
162
+
163
+ // Verify PROJECT-PLAN.json exists
164
+ if (!existsSync(projectPlanPath)) {
165
+ console.log('\n❌ PROJECT-PLAN.json not found');
166
+ console.log(' Tell Claude to create the plan first\n');
167
+ process.exit(1);
168
+ }
169
+
170
+ // Read the plan
171
+ const plan = JSON.parse(readFileSync(projectPlanPath, 'utf-8'));
172
+
173
+ // Extract tasks from plan
174
+ const tasks = [];
175
+ this.extractTasks(plan, tasks);
176
+
177
+ // Create task files
178
+ const tasksDir = join(planPath, 'tasks');
179
+ if (!existsSync(tasksDir)) {
180
+ mkdirSync(tasksDir, { recursive: true });
181
+ }
182
+
183
+ // Write individual task files
184
+ tasks.forEach(task => {
185
+ const taskPath = join(tasksDir, `${task.id}.json`);
186
+ writeFileSync(taskPath, JSON.stringify(task, null, 2));
187
+ });
188
+
189
+ // Create task tracker
190
+ const projectName = basename(process.cwd());
191
+ const tracker = {
192
+ planId,
193
+ projectName,
194
+ activeTask: null,
195
+ lockedAt: new Date().toISOString(),
196
+ statistics: {
197
+ totalTasks: tasks.length,
198
+ completed: 0,
199
+ inProgress: 0,
200
+ pending: tasks.length
201
+ },
202
+ taskFiles: tasks.map(task => ({
203
+ id: task.id,
204
+ title: task.title,
205
+ phase: task.phase || 'implementation',
206
+ status: 'pending',
207
+ description: task.description
208
+ }))
209
+ };
210
+
211
+ const trackerPath = join(planPath, 'TASK-TRACKER.json');
212
+ writeFileSync(trackerPath, JSON.stringify(tracker, null, 2));
213
+
214
+ // Mark as locked
215
+ const lockedPath = join(planPath, '.plan-locked');
216
+ writeFileSync(lockedPath, new Date().toISOString());
217
+
218
+ console.log('✅ Plan locked successfully\n');
219
+ this.showPlanStatus(planId);
220
+ console.log('💡 Next step: npx agentic15 task next\n');
221
+ } catch (error) {
222
+ console.log(`\n❌ Failed to lock plan: ${error.message}\n`);
223
+ process.exit(1);
224
+ }
225
+ }
226
+
227
+ static extractTasks(obj, tasks) {
228
+ // Recursively extract all tasks from the plan structure
229
+ if (obj.tasks && Array.isArray(obj.tasks)) {
230
+ tasks.push(...obj.tasks);
231
+ }
232
+
233
+ // Check nested structures
234
+ if (obj.milestones && Array.isArray(obj.milestones)) {
235
+ obj.milestones.forEach(milestone => this.extractTasks(milestone, tasks));
236
+ }
237
+
238
+ if (obj.subprojects && Array.isArray(obj.subprojects)) {
239
+ obj.subprojects.forEach(subproject => this.extractTasks(subproject, tasks));
240
+ }
241
+
242
+ if (obj.projects && Array.isArray(obj.projects)) {
243
+ obj.projects.forEach(project => this.extractTasks(project, tasks));
244
+ }
245
+
246
+ // Handle singular 'project' at root level (v2.0 schema)
247
+ if (obj.project && typeof obj.project === 'object') {
248
+ this.extractTasks(obj.project, tasks);
249
+ }
250
+ }
251
+
252
+ static getNextPlanId() {
253
+ const plansDir = join(process.cwd(), '.claude', 'plans');
254
+
255
+ if (!existsSync(plansDir)) {
256
+ mkdirSync(plansDir, { recursive: true });
257
+ }
258
+
259
+ const existingPlans = readdirSync(plansDir)
260
+ .filter(name => name.match(/^plan-\d{3}-/i))
261
+ .map(name => parseInt(name.match(/^plan-(\d{3})-/i)[1]))
262
+ .filter(num => !isNaN(num));
263
+
264
+ const nextNum = existingPlans.length > 0 ? Math.max(...existingPlans) + 1 : 1;
265
+
266
+ return `plan-${String(nextNum).padStart(3, '0')}-generated`;
267
+ }
268
+
269
+ static showPlanStatus(planId) {
270
+ const trackerPath = join(process.cwd(), '.claude', 'plans', planId, 'TASK-TRACKER.json');
271
+
272
+ if (!existsSync(trackerPath)) {
273
+ return;
274
+ }
275
+
276
+ try {
277
+ const tracker = JSON.parse(readFileSync(trackerPath, 'utf-8'));
278
+
279
+ const total = tracker.taskFiles.length;
280
+ const completed = tracker.taskFiles.filter(t => t.status === 'completed').length;
281
+ const pending = tracker.taskFiles.filter(t => t.status === 'pending').length;
282
+
283
+ console.log('📊 Plan Status:');
284
+ console.log(` Total Tasks: ${total}`);
285
+ console.log(` Completed: ${completed}`);
286
+ console.log(` Pending: ${pending}\n`);
287
+ } catch (e) {
288
+ // Ignore errors
289
+ }
290
+ }
291
+ }
@@ -1,287 +1,305 @@
1
- import { execSync } from 'child_process';
2
- import { readFileSync, writeFileSync, existsSync } from 'fs';
3
- import { join } from 'path';
4
- import { GitHubClient } from '../core/GitHubClient.js';
5
- import { GitHubConfig } from '../core/GitHubConfig.js';
6
- import { TaskIssueMapper } from '../core/TaskIssueMapper.js';
7
-
8
- export class TaskCommand {
9
- static async handle(action, taskId) {
10
- switch (action) {
11
- case 'start':
12
- return this.startTask(taskId);
13
- case 'next':
14
- return this.startNext();
15
- case 'status':
16
- return this.showStatus();
17
- default:
18
- console.log(`\n❌ Unknown action: ${action}`);
19
- console.log(' Valid actions: start, next, status\n');
20
- process.exit(1);
21
- }
22
- }
23
-
24
- static async startTask(taskId) {
25
- if (!taskId) {
26
- console.log('\n❌ Task ID required for "start" action');
27
- console.log(' Usage: agentic15 task start TASK-001\n');
28
- process.exit(1);
29
- }
30
-
31
- // Verify git remote is configured
32
- this.validateGitRemote();
33
-
34
- // Load task tracker
35
- const tracker = this.loadTracker();
36
- const task = tracker.taskFiles.find(t => t.id === taskId);
37
-
38
- if (!task) {
39
- console.log(`\n❌ Task not found: ${taskId}\n`);
40
- process.exit(1);
41
- }
42
-
43
- if (task.status === 'completed') {
44
- console.log(`\n⚠️ Task ${taskId} is already completed\n`);
45
- process.exit(1);
46
- }
47
-
48
- // Check if another task is in progress
49
- const inProgress = tracker.taskFiles.find(t => t.status === 'in_progress');
50
- if (inProgress && inProgress.id !== taskId) {
51
- console.log(`\n⚠️ Task ${inProgress.id} is already in progress`);
52
- console.log(` Complete it first with: agentic15 commit\n`);
53
- process.exit(1);
54
- }
55
-
56
- // Create feature branch
57
- const branchName = `feature/${taskId.toLowerCase()}`;
58
- try {
59
- execSync(`git checkout -b ${branchName}`, { stdio: 'inherit' });
60
- } catch (error) {
61
- // Branch might already exist
62
- try {
63
- execSync(`git checkout ${branchName}`, { stdio: 'inherit' });
64
- } catch (e) {
65
- console.log(`\n❌ Failed to create/checkout branch: ${branchName}\n`);
66
- process.exit(1);
67
- }
68
- }
69
-
70
- // Update task status
71
- task.status = 'in_progress';
72
- task.startedAt = new Date().toISOString();
73
- this.saveTracker(tracker);
74
-
75
- // Create GitHub issue if enabled
76
- let githubIssue = null;
77
- const config = new GitHubConfig(process.cwd());
78
- if (config.isAutoCreateEnabled()) {
79
- githubIssue = await this.createGitHubIssue(task, config);
80
- }
81
-
82
- // Display task details
83
- this.displayTaskDetails(task, githubIssue, tracker);
84
- }
85
-
86
- static async startNext() {
87
- const tracker = this.loadTracker();
88
-
89
- // Find next pending task
90
- const nextTask = tracker.taskFiles.find(t => t.status === 'pending');
91
-
92
- if (!nextTask) {
93
- console.log('\n✅ No more pending tasks!\n');
94
- const completed = tracker.taskFiles.filter(t => t.status === 'completed').length;
95
- const total = tracker.taskFiles.length;
96
- console.log(` Progress: ${completed}/${total} tasks completed\n`);
97
- process.exit(0);
98
- }
99
-
100
- console.log(`\n▶️ Auto-starting next task: ${nextTask.id}\n`);
101
- return this.startTask(nextTask.id);
102
- }
103
-
104
- static showStatus() {
105
- const tracker = this.loadTracker();
106
-
107
- const inProgress = tracker.taskFiles.find(t => t.status === 'in_progress');
108
- const completed = tracker.taskFiles.filter(t => t.status === 'completed').length;
109
- const pending = tracker.taskFiles.filter(t => t.status === 'pending').length;
110
- const total = tracker.taskFiles.length;
111
-
112
- console.log('\n📊 Task Status\n');
113
- console.log(` Plan: ${tracker.planId}`);
114
- console.log(` Progress: ${completed}/${total} completed (${pending} pending)\n`);
115
-
116
- if (inProgress) {
117
- console.log(` 🔄 Currently working on: ${inProgress.id}`);
118
- console.log(` 📌 ${inProgress.title}`);
119
-
120
- // Show changed files
121
- try {
122
- const diff = execSync('git diff --name-only', { encoding: 'utf-8' });
123
- if (diff.trim()) {
124
- console.log(`\n 📝 Changed files:`);
125
- diff.trim().split('\n').forEach(file => {
126
- console.log(` - ${file}`);
127
- });
128
- }
129
- } catch (e) {
130
- // Ignore
131
- }
132
- } else {
133
- console.log(' ℹ️ No task currently in progress');
134
- console.log(` Run: agentic15 task next\n`);
135
- }
136
-
137
- console.log('');
138
- }
139
-
140
- static async createGitHubIssue(task, config) {
141
- try {
142
- const client = new GitHubClient(
143
- config.getToken(),
144
- config.getRepoInfo().owner,
145
- config.getRepoInfo().repo
146
- );
147
-
148
- if (!client.isConfigured()) {
149
- console.log('\n⚠️ GitHub not configured. Skipping issue creation.');
150
- console.log(' Run: agentic15 auth setup\n');
151
- return null;
152
- }
153
-
154
- // Load full task details
155
- const taskPath = this.getTaskPath(task.id);
156
- const taskData = JSON.parse(readFileSync(taskPath, 'utf-8'));
157
-
158
- const title = TaskIssueMapper.taskToIssueTitle(taskData);
159
- const body = TaskIssueMapper.taskToIssueBody(taskData);
160
- const labels = TaskIssueMapper.taskStatusToLabels(taskData.status || 'pending', taskData.phase);
161
- const issueNumber = await client.createIssue(title, body, labels);
162
-
163
- if (issueNumber) {
164
- // Save issue number to task
165
- taskData.githubIssue = issueNumber;
166
- writeFileSync(taskPath, JSON.stringify(taskData, null, 2));
167
-
168
- console.log(`\n✓ Created GitHub issue #${issueNumber}`);
169
- const repoInfo = config.getRepoInfo();
170
- console.log(` https://github.com/${repoInfo.owner}/${repoInfo.repo}/issues/${issueNumber}\n`);
171
-
172
- return issueNumber;
173
- }
174
- } catch (error) {
175
- console.log(`\n⚠️ Failed to create GitHub issue: ${error.message}\n`);
176
- }
177
-
178
- return null;
179
- }
180
-
181
- static displayTaskDetails(task, githubIssue, tracker) {
182
- console.log(`\n✅ Started task: ${task.id}`);
183
- console.log(`📋 Plan: ${tracker.planId}\n`);
184
- console.log(`📌 ${task.title}`);
185
-
186
- if (task.description) {
187
- console.log(`📝 ${task.description}\n`);
188
- }
189
-
190
- if (task.phase) {
191
- console.log(`🔧 Phase: ${task.phase}`);
192
- }
193
-
194
- if (githubIssue) {
195
- const config = new GitHubConfig(process.cwd());
196
- const repoInfo = config.getRepoInfo();
197
- console.log(`🔗 GitHub Issue: https://github.com/${repoInfo.owner}/${repoInfo.repo}/issues/${githubIssue}`);
198
- }
199
-
200
- // Load full task for completion criteria
201
- try {
202
- const taskPath = this.getTaskPath(task.id);
203
- const taskData = JSON.parse(readFileSync(taskPath, 'utf-8'));
204
-
205
- if (taskData.completionCriteria && taskData.completionCriteria.length > 0) {
206
- console.log(`\n✓ Completion criteria:`);
207
- taskData.completionCriteria.forEach((criteria, idx) => {
208
- console.log(` ${idx + 1}. ${criteria}`);
209
- });
210
- }
211
- } catch (e) {
212
- // Ignore
213
- }
214
-
215
- console.log(`\n💡 Next steps:`);
216
- console.log(` 1. Tell Claude: "Write code for ${task.id}"`);
217
- console.log(` 2. When done: agentic15 commit\n`);
218
- }
219
-
220
- static loadTracker() {
221
- const activePlanPath = join(process.cwd(), '.claude', 'ACTIVE-PLAN');
222
-
223
- if (!existsSync(activePlanPath)) {
224
- console.log('\n❌ No active plan found');
225
- console.log(' Run: agentic15 plan "project description"\n');
226
- process.exit(1);
227
- }
228
-
229
- const planId = readFileSync(activePlanPath, 'utf-8').trim();
230
- const trackerPath = join(process.cwd(), '.claude', 'plans', planId, 'TASK-TRACKER.json');
231
-
232
- if (!existsSync(trackerPath)) {
233
- console.log('\n❌ Task tracker not found');
234
- console.log(' Run: agentic15 plan\n');
235
- process.exit(1);
236
- }
237
-
238
- return JSON.parse(readFileSync(trackerPath, 'utf-8'));
239
- }
240
-
241
- static saveTracker(tracker) {
242
- const activePlanPath = join(process.cwd(), '.claude', 'ACTIVE-PLAN');
243
- const planId = readFileSync(activePlanPath, 'utf-8').trim();
244
- const trackerPath = join(process.cwd(), '.claude', 'plans', planId, 'TASK-TRACKER.json');
245
-
246
- writeFileSync(trackerPath, JSON.stringify(tracker, null, 2));
247
- }
248
-
249
- static getTaskPath(taskId) {
250
- const activePlanPath = join(process.cwd(), '.claude', 'ACTIVE-PLAN');
251
- const planId = readFileSync(activePlanPath, 'utf-8').trim();
252
- return join(process.cwd(), '.claude', 'plans', planId, 'tasks', `${taskId}.json`);
253
- }
254
-
255
- static validateGitRemote() {
256
- try {
257
- // Check if git remote origin exists
258
- const remote = execSync('git remote get-url origin', { encoding: 'utf-8', stdio: 'pipe' }).trim();
259
-
260
- if (!remote || remote.length === 0) {
261
- throw new Error('No remote URL');
262
- }
263
-
264
- // Validate it's a GitHub URL
265
- if (!remote.includes('github.com')) {
266
- console.log('\n⚠️ Warning: Remote is not a GitHub repository');
267
- console.log(` Remote URL: ${remote}`);
268
- console.log(' GitHub integration features may not work.\n');
269
- }
270
- } catch (error) {
271
- console.log('\n❌ Git remote "origin" is not configured');
272
- console.log('\n Before starting tasks, you must link your project to a GitHub repository:');
273
- console.log('\n 1. Create a GitHub repository:');
274
- console.log(' gh repo create OWNER/REPO --public (or --private)');
275
- console.log('\n 2. Link it to your local project:');
276
- console.log(' git remote add origin https://github.com/OWNER/REPO.git');
277
- console.log('\n 3. Push your initial code:');
278
- console.log(' git branch -M main');
279
- console.log(' git add .');
280
- console.log(' git commit -m "Initial commit"');
281
- console.log(' git push -u origin main');
282
- console.log('\n 4. Then start your task:');
283
- console.log(' npx agentic15 task next\n');
284
- process.exit(1);
285
- }
286
- }
287
- }
1
+ import { execSync } from 'child_process';
2
+ import { readFileSync, writeFileSync, existsSync } from 'fs';
3
+ import { join } from 'path';
4
+ import { GitHubClient } from '../core/GitHubClient.js';
5
+ import { GitHubConfig } from '../core/GitHubConfig.js';
6
+ import { TaskIssueMapper } from '../core/TaskIssueMapper.js';
7
+
8
+ export class TaskCommand {
9
+ static async handle(action, taskId) {
10
+ switch (action) {
11
+ case 'start':
12
+ return this.startTask(taskId);
13
+ case 'next':
14
+ return this.startNext();
15
+ case 'status':
16
+ return this.showStatus();
17
+ default:
18
+ console.log(`\n❌ Unknown action: ${action}`);
19
+ console.log(' Valid actions: start, next, status\n');
20
+ process.exit(1);
21
+ }
22
+ }
23
+
24
+ static async startTask(taskId) {
25
+ if (!taskId) {
26
+ console.log('\n❌ Task ID required for "start" action');
27
+ console.log(' Usage: agentic15 task start TASK-001\n');
28
+ process.exit(1);
29
+ }
30
+
31
+ // Verify git remote is configured
32
+ this.validateGitRemote();
33
+
34
+ // Load task tracker
35
+ const tracker = this.loadTracker();
36
+ const task = tracker.taskFiles.find(t => t.id === taskId);
37
+
38
+ if (!task) {
39
+ console.log(`\n❌ Task not found: ${taskId}\n`);
40
+ process.exit(1);
41
+ }
42
+
43
+ if (task.status === 'completed') {
44
+ console.log(`\n⚠️ Task ${taskId} is already completed\n`);
45
+ process.exit(1);
46
+ }
47
+
48
+ // Check if another task is in progress
49
+ const inProgress = tracker.taskFiles.find(t => t.status === 'in_progress');
50
+ if (inProgress && inProgress.id !== taskId) {
51
+ console.log(`\n⚠️ Task ${inProgress.id} is already in progress`);
52
+ console.log(` Complete it first with: agentic15 commit\n`);
53
+ process.exit(1);
54
+ }
55
+
56
+ // Create feature branch
57
+ const branchName = `feature/${taskId.toLowerCase()}`;
58
+ try {
59
+ execSync(`git checkout -b ${branchName}`, { stdio: 'inherit' });
60
+ } catch (error) {
61
+ // Branch might already exist
62
+ try {
63
+ execSync(`git checkout ${branchName}`, { stdio: 'inherit' });
64
+ } catch (e) {
65
+ console.log(`\n❌ Failed to create/checkout branch: ${branchName}\n`);
66
+ process.exit(1);
67
+ }
68
+ }
69
+
70
+ // Update task status
71
+ task.status = 'in_progress';
72
+ task.startedAt = new Date().toISOString();
73
+
74
+ // Update tracker metadata
75
+ tracker.activeTask = task.id;
76
+ this.updateStatistics(tracker);
77
+ this.saveTracker(tracker);
78
+
79
+ // Create GitHub issue if enabled
80
+ let githubIssue = null;
81
+ const config = new GitHubConfig(process.cwd());
82
+ if (config.isAutoCreateEnabled()) {
83
+ githubIssue = await this.createGitHubIssue(task, config);
84
+ }
85
+
86
+ // Display task details
87
+ this.displayTaskDetails(task, githubIssue, tracker);
88
+ }
89
+
90
+ static async startNext() {
91
+ const tracker = this.loadTracker();
92
+
93
+ // Find next pending task
94
+ const nextTask = tracker.taskFiles.find(t => t.status === 'pending');
95
+
96
+ if (!nextTask) {
97
+ console.log('\n✅ No more pending tasks!\n');
98
+ const completed = tracker.taskFiles.filter(t => t.status === 'completed').length;
99
+ const total = tracker.taskFiles.length;
100
+ console.log(` Progress: ${completed}/${total} tasks completed\n`);
101
+ process.exit(0);
102
+ }
103
+
104
+ console.log(`\n▶️ Auto-starting next task: ${nextTask.id}\n`);
105
+ return this.startTask(nextTask.id);
106
+ }
107
+
108
+ static showStatus() {
109
+ const tracker = this.loadTracker();
110
+
111
+ const inProgress = tracker.taskFiles.find(t => t.status === 'in_progress');
112
+ const completed = tracker.taskFiles.filter(t => t.status === 'completed').length;
113
+ const pending = tracker.taskFiles.filter(t => t.status === 'pending').length;
114
+ const total = tracker.taskFiles.length;
115
+
116
+ console.log('\n📊 Task Status\n');
117
+ console.log(` Plan: ${tracker.planId}`);
118
+ console.log(` Progress: ${completed}/${total} completed (${pending} pending)\n`);
119
+
120
+ if (inProgress) {
121
+ console.log(` 🔄 Currently working on: ${inProgress.id}`);
122
+ console.log(` 📌 ${inProgress.title}`);
123
+
124
+ // Show changed files
125
+ try {
126
+ const diff = execSync('git diff --name-only', { encoding: 'utf-8' });
127
+ if (diff.trim()) {
128
+ console.log(`\n 📝 Changed files:`);
129
+ diff.trim().split('\n').forEach(file => {
130
+ console.log(` - ${file}`);
131
+ });
132
+ }
133
+ } catch (e) {
134
+ // Ignore
135
+ }
136
+ } else {
137
+ console.log(' ℹ️ No task currently in progress');
138
+ console.log(` Run: agentic15 task next\n`);
139
+ }
140
+
141
+ console.log('');
142
+ }
143
+
144
+ static async createGitHubIssue(task, config) {
145
+ try {
146
+ const client = new GitHubClient(
147
+ config.getToken(),
148
+ config.getRepoInfo().owner,
149
+ config.getRepoInfo().repo
150
+ );
151
+
152
+ if (!client.isConfigured()) {
153
+ console.log('\n⚠️ GitHub not configured. Skipping issue creation.');
154
+ console.log(' Run: agentic15 auth setup\n');
155
+ return null;
156
+ }
157
+
158
+ // Load full task details
159
+ const taskPath = this.getTaskPath(task.id);
160
+ const taskData = JSON.parse(readFileSync(taskPath, 'utf-8'));
161
+
162
+ const title = TaskIssueMapper.taskToIssueTitle(taskData);
163
+ const body = TaskIssueMapper.taskToIssueBody(taskData);
164
+ const labels = TaskIssueMapper.taskStatusToLabels(taskData.status || 'pending', taskData.phase);
165
+ const issueNumber = await client.createIssue(title, body, labels);
166
+
167
+ if (issueNumber) {
168
+ // Save issue number to task
169
+ taskData.githubIssue = issueNumber;
170
+ writeFileSync(taskPath, JSON.stringify(taskData, null, 2));
171
+
172
+ console.log(`\n✓ Created GitHub issue #${issueNumber}`);
173
+ const repoInfo = config.getRepoInfo();
174
+ console.log(` https://github.com/${repoInfo.owner}/${repoInfo.repo}/issues/${issueNumber}\n`);
175
+
176
+ return issueNumber;
177
+ }
178
+ } catch (error) {
179
+ console.log(`\n⚠️ Failed to create GitHub issue: ${error.message}\n`);
180
+ }
181
+
182
+ return null;
183
+ }
184
+
185
+ static displayTaskDetails(task, githubIssue, tracker) {
186
+ console.log(`\n✅ Started task: ${task.id}`);
187
+ console.log(`📋 Plan: ${tracker.planId}\n`);
188
+ console.log(`📌 ${task.title}`);
189
+
190
+ if (task.description) {
191
+ console.log(`📝 ${task.description}\n`);
192
+ }
193
+
194
+ if (task.phase) {
195
+ console.log(`🔧 Phase: ${task.phase}`);
196
+ }
197
+
198
+ if (githubIssue) {
199
+ const config = new GitHubConfig(process.cwd());
200
+ const repoInfo = config.getRepoInfo();
201
+ console.log(`🔗 GitHub Issue: https://github.com/${repoInfo.owner}/${repoInfo.repo}/issues/${githubIssue}`);
202
+ }
203
+
204
+ // Load full task for completion criteria
205
+ try {
206
+ const taskPath = this.getTaskPath(task.id);
207
+ const taskData = JSON.parse(readFileSync(taskPath, 'utf-8'));
208
+
209
+ if (taskData.completionCriteria && taskData.completionCriteria.length > 0) {
210
+ console.log(`\n✓ Completion criteria:`);
211
+ taskData.completionCriteria.forEach((criteria, idx) => {
212
+ console.log(` ${idx + 1}. ${criteria}`);
213
+ });
214
+ }
215
+ } catch (e) {
216
+ // Ignore
217
+ }
218
+
219
+ console.log(`\n💡 Next steps:`);
220
+ console.log(` 1. Tell Claude: "Write code for ${task.id}"`);
221
+ console.log(` 2. When done: agentic15 commit\n`);
222
+ }
223
+
224
+ static loadTracker() {
225
+ const activePlanPath = join(process.cwd(), '.claude', 'ACTIVE-PLAN');
226
+
227
+ if (!existsSync(activePlanPath)) {
228
+ console.log('\n❌ No active plan found');
229
+ console.log(' Run: agentic15 plan "project description"\n');
230
+ process.exit(1);
231
+ }
232
+
233
+ const planId = readFileSync(activePlanPath, 'utf-8').trim();
234
+ const trackerPath = join(process.cwd(), '.claude', 'plans', planId, 'TASK-TRACKER.json');
235
+
236
+ if (!existsSync(trackerPath)) {
237
+ console.log('\n❌ Task tracker not found');
238
+ console.log(' Run: agentic15 plan\n');
239
+ process.exit(1);
240
+ }
241
+
242
+ return JSON.parse(readFileSync(trackerPath, 'utf-8'));
243
+ }
244
+
245
+ static saveTracker(tracker) {
246
+ const activePlanPath = join(process.cwd(), '.claude', 'ACTIVE-PLAN');
247
+ const planId = readFileSync(activePlanPath, 'utf-8').trim();
248
+ const trackerPath = join(process.cwd(), '.claude', 'plans', planId, 'TASK-TRACKER.json');
249
+
250
+ writeFileSync(trackerPath, JSON.stringify(tracker, null, 2));
251
+ }
252
+
253
+ static updateStatistics(tracker) {
254
+ const completed = tracker.taskFiles.filter(t => t.status === 'completed').length;
255
+ const inProgress = tracker.taskFiles.filter(t => t.status === 'in_progress').length;
256
+ const pending = tracker.taskFiles.filter(t => t.status === 'pending').length;
257
+ const totalTasks = tracker.taskFiles.length;
258
+
259
+ tracker.statistics = {
260
+ totalTasks,
261
+ completed,
262
+ inProgress,
263
+ pending
264
+ };
265
+ }
266
+
267
+ static getTaskPath(taskId) {
268
+ const activePlanPath = join(process.cwd(), '.claude', 'ACTIVE-PLAN');
269
+ const planId = readFileSync(activePlanPath, 'utf-8').trim();
270
+ return join(process.cwd(), '.claude', 'plans', planId, 'tasks', `${taskId}.json`);
271
+ }
272
+
273
+ static validateGitRemote() {
274
+ try {
275
+ // Check if git remote origin exists
276
+ const remote = execSync('git remote get-url origin', { encoding: 'utf-8', stdio: 'pipe' }).trim();
277
+
278
+ if (!remote || remote.length === 0) {
279
+ throw new Error('No remote URL');
280
+ }
281
+
282
+ // Validate it's a GitHub URL
283
+ if (!remote.includes('github.com')) {
284
+ console.log('\n⚠️ Warning: Remote is not a GitHub repository');
285
+ console.log(` Remote URL: ${remote}`);
286
+ console.log(' GitHub integration features may not work.\n');
287
+ }
288
+ } catch (error) {
289
+ console.log('\n❌ Git remote "origin" is not configured');
290
+ console.log('\n Before starting tasks, you must link your project to a GitHub repository:');
291
+ console.log('\n 1. Create a GitHub repository:');
292
+ console.log(' gh repo create OWNER/REPO --public (or --private)');
293
+ console.log('\n 2. Link it to your local project:');
294
+ console.log(' git remote add origin https://github.com/OWNER/REPO.git');
295
+ console.log('\n 3. Push your initial code:');
296
+ console.log(' git branch -M main');
297
+ console.log(' git add .');
298
+ console.log(' git commit -m "Initial commit"');
299
+ console.log(' git push -u origin main');
300
+ console.log('\n 4. Then start your task:');
301
+ console.log(' npx agentic15 task next\n');
302
+ process.exit(1);
303
+ }
304
+ }
305
+ }
@@ -34,16 +34,12 @@
34
34
  "Edit(./.claude/hooks/**)",
35
35
  "Write(./.claude/hooks/**)",
36
36
  "Edit(./.claude/TASK-TRACKER.json)",
37
- "Read(./.claude/POST-INSTALL.md)",
38
- "Read(./docs/**)",
39
37
  "Bash(agentic15:*)",
40
38
  "Bash(npx agentic15:*)",
41
39
  "Bash(git:*)",
42
40
  "Bash(gh:*)",
43
41
  "Bash(npm run task:*)",
44
42
  "Bash(npm run plan:*)",
45
- "Bash(curl:*)",
46
- "Bash(wget:*)",
47
43
  "Bash(rm -rf:*)",
48
44
  "Bash(sudo:*)",
49
45
  "Bash(npm install:*)",
@@ -58,9 +54,7 @@
58
54
  "Bash(node ./scripts/**)",
59
55
  "Bash(node ./Agent/db/**)",
60
56
  "Bash(bash ./scripts/**)",
61
- "Bash(sh ./scripts/**)",
62
- "WebFetch",
63
- "WebSearch"
57
+ "Bash(sh ./scripts/**)"
64
58
  ]
65
59
  },
66
60
  "sandbox": {