@agentic15.com/agentic15-claude-zen 1.1.0 → 2.0.1

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.
@@ -0,0 +1,156 @@
1
+ import { readFileSync, existsSync } from 'fs';
2
+ import { join } from 'path';
3
+ import { execSync } from 'child_process';
4
+
5
+ export class StatusCommand {
6
+ static show() {
7
+ console.log('\nšŸ“Š Project Status\n');
8
+
9
+ // Load tracker
10
+ const tracker = this.loadTracker();
11
+
12
+ if (!tracker) {
13
+ console.log('āŒ No active plan found\n');
14
+ process.exit(1);
15
+ }
16
+
17
+ // Calculate statistics
18
+ const completed = tracker.taskFiles.filter(t => t.status === 'completed');
19
+ const inProgress = tracker.taskFiles.filter(t => t.status === 'in_progress');
20
+ const pending = tracker.taskFiles.filter(t => t.status === 'pending');
21
+ const blocked = tracker.taskFiles.filter(t => t.status === 'blocked');
22
+ const total = tracker.taskFiles.length;
23
+
24
+ // Display plan info
25
+ console.log(` Plan: ${tracker.planId}`);
26
+ console.log(` Total Tasks: ${total}\n`);
27
+
28
+ // Progress bar
29
+ const completedPercent = Math.round((completed.length / total) * 100);
30
+ const barLength = 30;
31
+ const filledLength = Math.round((completedPercent / 100) * barLength);
32
+ const bar = 'ā–ˆ'.repeat(filledLength) + 'ā–‘'.repeat(barLength - filledLength);
33
+
34
+ console.log(` Progress: [${bar}] ${completedPercent}%\n`);
35
+
36
+ // Status breakdown
37
+ console.log(' Status Breakdown:');
38
+ console.log(` āœ… Completed: ${completed.length}`);
39
+ console.log(` šŸ”„ In Progress: ${inProgress.length}`);
40
+ console.log(` ā³ Pending: ${pending.length}`);
41
+
42
+ if (blocked.length > 0) {
43
+ console.log(` 🚫 Blocked: ${blocked.length}`);
44
+ }
45
+
46
+ console.log('');
47
+
48
+ // Current task
49
+ if (inProgress.length > 0) {
50
+ const current = inProgress[0];
51
+ console.log(' šŸ”„ Current Task:');
52
+ console.log(` ${current.id}: ${current.title}`);
53
+
54
+ // Show changed files
55
+ try {
56
+ const diff = execSync('git diff --name-only', { encoding: 'utf-8' });
57
+ const staged = execSync('git diff --cached --name-only', { encoding: 'utf-8' });
58
+
59
+ const allChanges = new Set([
60
+ ...diff.trim().split('\n').filter(Boolean),
61
+ ...staged.trim().split('\n').filter(Boolean)
62
+ ]);
63
+
64
+ if (allChanges.size > 0) {
65
+ console.log(`\n šŸ“ Modified files (${allChanges.size}):`);
66
+ Array.from(allChanges).slice(0, 10).forEach(file => {
67
+ console.log(` - ${file}`);
68
+ });
69
+
70
+ if (allChanges.size > 10) {
71
+ console.log(` ... and ${allChanges.size - 10} more`);
72
+ }
73
+ }
74
+ } catch (e) {
75
+ // Ignore git errors
76
+ }
77
+
78
+ console.log('');
79
+ console.log(' šŸ’” Next step: agentic15 commit');
80
+ } else if (pending.length > 0) {
81
+ console.log(' šŸ“Œ Next Task:');
82
+ const next = pending[0];
83
+ console.log(` ${next.id}: ${next.title}`);
84
+ console.log('');
85
+ console.log(' šŸ’” Next step: agentic15 task next');
86
+ } else if (blocked.length > 0) {
87
+ console.log(' 🚫 Blocked Tasks:');
88
+ blocked.slice(0, 3).forEach(task => {
89
+ console.log(` ${task.id}: ${task.title}`);
90
+ });
91
+
92
+ if (blocked.length > 3) {
93
+ console.log(` ... and ${blocked.length - 3} more`);
94
+ }
95
+ } else {
96
+ console.log(' šŸŽ‰ All tasks completed!');
97
+ }
98
+
99
+ console.log('');
100
+
101
+ // Recent activity
102
+ const recentCompleted = completed
103
+ .filter(t => t.completedAt)
104
+ .sort((a, b) => new Date(b.completedAt) - new Date(a.completedAt))
105
+ .slice(0, 3);
106
+
107
+ if (recentCompleted.length > 0) {
108
+ console.log(' šŸ“œ Recently Completed:');
109
+ recentCompleted.forEach(task => {
110
+ const date = new Date(task.completedAt);
111
+ const timeAgo = this.getTimeAgo(date);
112
+ console.log(` āœ“ ${task.id}: ${task.title} (${timeAgo})`);
113
+ });
114
+ console.log('');
115
+ }
116
+ }
117
+
118
+ static loadTracker() {
119
+ const activePlanPath = join(process.cwd(), '.claude', 'ACTIVE-PLAN');
120
+
121
+ if (!existsSync(activePlanPath)) {
122
+ return null;
123
+ }
124
+
125
+ const planId = readFileSync(activePlanPath, 'utf-8').trim();
126
+ const trackerPath = join(process.cwd(), '.claude', 'plans', planId, 'TASK-TRACKER.json');
127
+
128
+ if (!existsSync(trackerPath)) {
129
+ return null;
130
+ }
131
+
132
+ return JSON.parse(readFileSync(trackerPath, 'utf-8'));
133
+ }
134
+
135
+ static getTimeAgo(date) {
136
+ const seconds = Math.floor((new Date() - date) / 1000);
137
+
138
+ const intervals = {
139
+ year: 31536000,
140
+ month: 2592000,
141
+ week: 604800,
142
+ day: 86400,
143
+ hour: 3600,
144
+ minute: 60
145
+ };
146
+
147
+ for (const [unit, secondsInUnit] of Object.entries(intervals)) {
148
+ const interval = Math.floor(seconds / secondsInUnit);
149
+ if (interval >= 1) {
150
+ return `${interval} ${unit}${interval === 1 ? '' : 's'} ago`;
151
+ }
152
+ }
153
+
154
+ return 'just now';
155
+ }
156
+ }
@@ -0,0 +1,249 @@
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
+ // Load task tracker
32
+ const tracker = this.loadTracker();
33
+ const task = tracker.taskFiles.find(t => t.id === taskId);
34
+
35
+ if (!task) {
36
+ console.log(`\nāŒ Task not found: ${taskId}\n`);
37
+ process.exit(1);
38
+ }
39
+
40
+ if (task.status === 'completed') {
41
+ console.log(`\nāš ļø Task ${taskId} is already completed\n`);
42
+ process.exit(1);
43
+ }
44
+
45
+ // Check if another task is in progress
46
+ const inProgress = tracker.taskFiles.find(t => t.status === 'in_progress');
47
+ if (inProgress && inProgress.id !== taskId) {
48
+ console.log(`\nāš ļø Task ${inProgress.id} is already in progress`);
49
+ console.log(` Complete it first with: agentic15 commit\n`);
50
+ process.exit(1);
51
+ }
52
+
53
+ // Create feature branch
54
+ const branchName = `feature/${taskId.toLowerCase()}`;
55
+ try {
56
+ execSync(`git checkout -b ${branchName}`, { stdio: 'inherit' });
57
+ } catch (error) {
58
+ // Branch might already exist
59
+ try {
60
+ execSync(`git checkout ${branchName}`, { stdio: 'inherit' });
61
+ } catch (e) {
62
+ console.log(`\nāŒ Failed to create/checkout branch: ${branchName}\n`);
63
+ process.exit(1);
64
+ }
65
+ }
66
+
67
+ // Update task status
68
+ task.status = 'in_progress';
69
+ task.startedAt = new Date().toISOString();
70
+ this.saveTracker(tracker);
71
+
72
+ // Create GitHub issue if enabled
73
+ let githubIssue = null;
74
+ const config = new GitHubConfig(process.cwd());
75
+ if (config.isAutoCreateEnabled()) {
76
+ githubIssue = await this.createGitHubIssue(task, config);
77
+ }
78
+
79
+ // Display task details
80
+ this.displayTaskDetails(task, githubIssue, tracker);
81
+ }
82
+
83
+ static async startNext() {
84
+ const tracker = this.loadTracker();
85
+
86
+ // Find next pending task
87
+ const nextTask = tracker.taskFiles.find(t => t.status === 'pending');
88
+
89
+ if (!nextTask) {
90
+ console.log('\nāœ… No more pending tasks!\n');
91
+ const completed = tracker.taskFiles.filter(t => t.status === 'completed').length;
92
+ const total = tracker.taskFiles.length;
93
+ console.log(` Progress: ${completed}/${total} tasks completed\n`);
94
+ process.exit(0);
95
+ }
96
+
97
+ console.log(`\nā–¶ļø Auto-starting next task: ${nextTask.id}\n`);
98
+ return this.startTask(nextTask.id);
99
+ }
100
+
101
+ static showStatus() {
102
+ const tracker = this.loadTracker();
103
+
104
+ const inProgress = tracker.taskFiles.find(t => t.status === 'in_progress');
105
+ const completed = tracker.taskFiles.filter(t => t.status === 'completed').length;
106
+ const pending = tracker.taskFiles.filter(t => t.status === 'pending').length;
107
+ const total = tracker.taskFiles.length;
108
+
109
+ console.log('\nšŸ“Š Task Status\n');
110
+ console.log(` Plan: ${tracker.planId}`);
111
+ console.log(` Progress: ${completed}/${total} completed (${pending} pending)\n`);
112
+
113
+ if (inProgress) {
114
+ console.log(` šŸ”„ Currently working on: ${inProgress.id}`);
115
+ console.log(` šŸ“Œ ${inProgress.title}`);
116
+
117
+ // Show changed files
118
+ try {
119
+ const diff = execSync('git diff --name-only', { encoding: 'utf-8' });
120
+ if (diff.trim()) {
121
+ console.log(`\n šŸ“ Changed files:`);
122
+ diff.trim().split('\n').forEach(file => {
123
+ console.log(` - ${file}`);
124
+ });
125
+ }
126
+ } catch (e) {
127
+ // Ignore
128
+ }
129
+ } else {
130
+ console.log(' ā„¹ļø No task currently in progress');
131
+ console.log(` Run: agentic15 task next\n`);
132
+ }
133
+
134
+ console.log('');
135
+ }
136
+
137
+ static async createGitHubIssue(task, config) {
138
+ try {
139
+ const client = new GitHubClient(
140
+ config.getToken(),
141
+ config.getRepoInfo().owner,
142
+ config.getRepoInfo().repo
143
+ );
144
+
145
+ if (!client.isConfigured()) {
146
+ console.log('\nāš ļø GitHub not configured. Skipping issue creation.');
147
+ console.log(' Run: agentic15 auth setup\n');
148
+ return null;
149
+ }
150
+
151
+ // Load full task details
152
+ const taskPath = this.getTaskPath(task.id);
153
+ const taskData = JSON.parse(readFileSync(taskPath, 'utf-8'));
154
+
155
+ const { title, body, labels } = TaskIssueMapper.mapTaskToIssue(taskData);
156
+ const issueNumber = await client.createIssue(title, body, labels);
157
+
158
+ if (issueNumber) {
159
+ // Save issue number to task
160
+ taskData.githubIssue = issueNumber;
161
+ writeFileSync(taskPath, JSON.stringify(taskData, null, 2));
162
+
163
+ console.log(`\nāœ“ Created GitHub issue #${issueNumber}`);
164
+ const repoInfo = config.getRepoInfo();
165
+ console.log(` https://github.com/${repoInfo.owner}/${repoInfo.repo}/issues/${issueNumber}\n`);
166
+
167
+ return issueNumber;
168
+ }
169
+ } catch (error) {
170
+ console.log(`\nāš ļø Failed to create GitHub issue: ${error.message}\n`);
171
+ }
172
+
173
+ return null;
174
+ }
175
+
176
+ static displayTaskDetails(task, githubIssue, tracker) {
177
+ console.log(`\nāœ… Started task: ${task.id}`);
178
+ console.log(`šŸ“‹ Plan: ${tracker.planId}\n`);
179
+ console.log(`šŸ“Œ ${task.title}`);
180
+
181
+ if (task.description) {
182
+ console.log(`šŸ“ ${task.description}\n`);
183
+ }
184
+
185
+ if (task.phase) {
186
+ console.log(`šŸ”§ Phase: ${task.phase}`);
187
+ }
188
+
189
+ if (githubIssue) {
190
+ const config = new GitHubConfig(process.cwd());
191
+ const repoInfo = config.getRepoInfo();
192
+ console.log(`šŸ”— GitHub Issue: https://github.com/${repoInfo.owner}/${repoInfo.repo}/issues/${githubIssue}`);
193
+ }
194
+
195
+ // Load full task for completion criteria
196
+ try {
197
+ const taskPath = this.getTaskPath(task.id);
198
+ const taskData = JSON.parse(readFileSync(taskPath, 'utf-8'));
199
+
200
+ if (taskData.completionCriteria && taskData.completionCriteria.length > 0) {
201
+ console.log(`\nāœ“ Completion criteria:`);
202
+ taskData.completionCriteria.forEach((criteria, idx) => {
203
+ console.log(` ${idx + 1}. ${criteria}`);
204
+ });
205
+ }
206
+ } catch (e) {
207
+ // Ignore
208
+ }
209
+
210
+ console.log(`\nšŸ’” Next steps:`);
211
+ console.log(` 1. Tell Claude: "Write code for ${task.id}"`);
212
+ console.log(` 2. When done: agentic15 commit\n`);
213
+ }
214
+
215
+ static loadTracker() {
216
+ const activePlanPath = join(process.cwd(), '.claude', 'ACTIVE-PLAN');
217
+
218
+ if (!existsSync(activePlanPath)) {
219
+ console.log('\nāŒ No active plan found');
220
+ console.log(' Run: agentic15 plan "project description"\n');
221
+ process.exit(1);
222
+ }
223
+
224
+ const planId = readFileSync(activePlanPath, 'utf-8').trim();
225
+ const trackerPath = join(process.cwd(), '.claude', 'plans', planId, 'TASK-TRACKER.json');
226
+
227
+ if (!existsSync(trackerPath)) {
228
+ console.log('\nāŒ Task tracker not found');
229
+ console.log(' Run: agentic15 plan\n');
230
+ process.exit(1);
231
+ }
232
+
233
+ return JSON.parse(readFileSync(trackerPath, 'utf-8'));
234
+ }
235
+
236
+ static saveTracker(tracker) {
237
+ const activePlanPath = join(process.cwd(), '.claude', 'ACTIVE-PLAN');
238
+ const planId = readFileSync(activePlanPath, 'utf-8').trim();
239
+ const trackerPath = join(process.cwd(), '.claude', 'plans', planId, 'TASK-TRACKER.json');
240
+
241
+ writeFileSync(trackerPath, JSON.stringify(tracker, null, 2));
242
+ }
243
+
244
+ static getTaskPath(taskId) {
245
+ const activePlanPath = join(process.cwd(), '.claude', 'ACTIVE-PLAN');
246
+ const planId = readFileSync(activePlanPath, 'utf-8').trim();
247
+ return join(process.cwd(), '.claude', 'plans', planId, 'tasks', `${taskId}.json`);
248
+ }
249
+ }