claude-devloop 1.0.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/README.md +340 -0
- package/dist/cli.d.ts +4 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +90 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/config.d.ts +9 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +80 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/continue.d.ts +11 -0
- package/dist/commands/continue.d.ts.map +1 -0
- package/dist/commands/continue.js +167 -0
- package/dist/commands/continue.js.map +1 -0
- package/dist/commands/feature.d.ts +7 -0
- package/dist/commands/feature.d.ts.map +1 -0
- package/dist/commands/feature.js +123 -0
- package/dist/commands/feature.js.map +1 -0
- package/dist/commands/init.d.ts +8 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +401 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/run.d.ts +12 -0
- package/dist/commands/run.d.ts.map +1 -0
- package/dist/commands/run.js +82 -0
- package/dist/commands/run.js.map +1 -0
- package/dist/commands/shared.d.ts +22 -0
- package/dist/commands/shared.d.ts.map +1 -0
- package/dist/commands/shared.js +32 -0
- package/dist/commands/shared.js.map +1 -0
- package/dist/commands/status.d.ts +8 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +305 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/workspace.d.ts +2 -0
- package/dist/commands/workspace.d.ts.map +1 -0
- package/dist/commands/workspace.js +19 -0
- package/dist/commands/workspace.js.map +1 -0
- package/dist/constants.d.ts +21 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +21 -0
- package/dist/constants.js.map +1 -0
- package/dist/core/claude.d.ts +20 -0
- package/dist/core/claude.d.ts.map +1 -0
- package/dist/core/claude.js +401 -0
- package/dist/core/claude.js.map +1 -0
- package/dist/core/commit-format.d.ts +22 -0
- package/dist/core/commit-format.d.ts.map +1 -0
- package/dist/core/commit-format.js +148 -0
- package/dist/core/commit-format.js.map +1 -0
- package/dist/core/config.d.ts +30 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +130 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/feature-session.d.ts +8 -0
- package/dist/core/feature-session.d.ts.map +1 -0
- package/dist/core/feature-session.js +58 -0
- package/dist/core/feature-session.js.map +1 -0
- package/dist/core/git.d.ts +81 -0
- package/dist/core/git.d.ts.map +1 -0
- package/dist/core/git.js +475 -0
- package/dist/core/git.js.map +1 -0
- package/dist/core/loop.d.ts +3 -0
- package/dist/core/loop.d.ts.map +1 -0
- package/dist/core/loop.js +469 -0
- package/dist/core/loop.js.map +1 -0
- package/dist/core/session.d.ts +7 -0
- package/dist/core/session.d.ts.map +1 -0
- package/dist/core/session.js +57 -0
- package/dist/core/session.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/parser/progress.d.ts +7 -0
- package/dist/parser/progress.d.ts.map +1 -0
- package/dist/parser/progress.js +132 -0
- package/dist/parser/progress.js.map +1 -0
- package/dist/parser/requirements.d.ts +6 -0
- package/dist/parser/requirements.d.ts.map +1 -0
- package/dist/parser/requirements.js +126 -0
- package/dist/parser/requirements.js.map +1 -0
- package/dist/types/feature.d.ts +15 -0
- package/dist/types/feature.d.ts.map +1 -0
- package/dist/types/feature.js +2 -0
- package/dist/types/feature.js.map +1 -0
- package/dist/types/index.d.ts +78 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +3 -0
- package/dist/types/index.js.map +1 -0
- package/package.json +40 -0
|
@@ -0,0 +1,469 @@
|
|
|
1
|
+
import ora from 'ora';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import { parseRequirements, getNextTask } from '../parser/requirements.js';
|
|
4
|
+
import { readProgress, appendIteration } from '../parser/progress.js';
|
|
5
|
+
import { invokeClaudeAutomated, buildTaskPrompt, isApiError } from './claude.js';
|
|
6
|
+
import { createSession, updateSessionPhase, updateSessionIteration } from './session.js';
|
|
7
|
+
import { createFeatureSession, updateFeatureSessionIteration } from './feature-session.js';
|
|
8
|
+
import { commitIteration, commitInterruptedWork, ensureGitRepo, getUncommittedChanges } from './git.js';
|
|
9
|
+
// Graceful shutdown state
|
|
10
|
+
let stopRequested = false;
|
|
11
|
+
let forceStopRequested = false;
|
|
12
|
+
// Terminal title management
|
|
13
|
+
let originalTitle = null;
|
|
14
|
+
function setTerminalTitle(title) {
|
|
15
|
+
// Save original title on first call
|
|
16
|
+
if (originalTitle === null) {
|
|
17
|
+
originalTitle = 'Terminal'; // Default fallback
|
|
18
|
+
}
|
|
19
|
+
// ANSI escape sequence to set terminal title (works on most terminals)
|
|
20
|
+
process.stdout.write(`\x1b]0;${title}\x07`);
|
|
21
|
+
}
|
|
22
|
+
function restoreTerminalTitle() {
|
|
23
|
+
if (originalTitle !== null) {
|
|
24
|
+
process.stdout.write(`\x1b]0;${originalTitle}\x07`);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
// Elapsed time tracker for spinner
|
|
28
|
+
function formatElapsed(startTime) {
|
|
29
|
+
const elapsed = Math.floor((Date.now() - startTime) / 1000);
|
|
30
|
+
const mins = Math.floor(elapsed / 60);
|
|
31
|
+
const secs = elapsed % 60;
|
|
32
|
+
if (mins > 0) {
|
|
33
|
+
return `${mins}m ${secs}s`;
|
|
34
|
+
}
|
|
35
|
+
return `${secs}s`;
|
|
36
|
+
}
|
|
37
|
+
// Start a spinner with elapsed time updates
|
|
38
|
+
function startTimedSpinner(spinner, baseText, startTime, verbose, terminalTitle) {
|
|
39
|
+
const state = {
|
|
40
|
+
baseText,
|
|
41
|
+
currentActivity: null,
|
|
42
|
+
startTime,
|
|
43
|
+
interval: null
|
|
44
|
+
};
|
|
45
|
+
if (verbose) {
|
|
46
|
+
console.log(chalk.cyan(baseText));
|
|
47
|
+
return state;
|
|
48
|
+
}
|
|
49
|
+
spinner.start(chalk.cyan(`${baseText} (0s)`));
|
|
50
|
+
// Update spinner text and terminal title with elapsed time every second
|
|
51
|
+
// Re-setting terminal title periodically ensures it stays visible even if
|
|
52
|
+
// child processes (like Claude CLI) try to set their own title
|
|
53
|
+
state.interval = setInterval(() => {
|
|
54
|
+
const elapsed = formatElapsed(startTime);
|
|
55
|
+
const activityText = state.currentActivity
|
|
56
|
+
? `${state.baseText} - ${state.currentActivity} (${elapsed})`
|
|
57
|
+
: `${state.baseText} (${elapsed})`;
|
|
58
|
+
spinner.text = chalk.cyan(activityText);
|
|
59
|
+
if (terminalTitle) {
|
|
60
|
+
setTerminalTitle(terminalTitle);
|
|
61
|
+
}
|
|
62
|
+
}, 1000);
|
|
63
|
+
return state;
|
|
64
|
+
}
|
|
65
|
+
// Update spinner with current activity
|
|
66
|
+
function updateSpinnerActivity(state, activity) {
|
|
67
|
+
state.currentActivity = activity;
|
|
68
|
+
}
|
|
69
|
+
function setupGracefulShutdown() {
|
|
70
|
+
const handler = () => {
|
|
71
|
+
if (forceStopRequested) {
|
|
72
|
+
// Third Ctrl+C - force exit
|
|
73
|
+
console.log(chalk.red('\n\nForce stopping...'));
|
|
74
|
+
process.exit(1);
|
|
75
|
+
}
|
|
76
|
+
else if (stopRequested) {
|
|
77
|
+
// Second Ctrl+C - warn about force stop
|
|
78
|
+
forceStopRequested = true;
|
|
79
|
+
console.log(chalk.yellow('\nPress Ctrl+C again to force stop immediately.'));
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
// First Ctrl+C - request graceful stop
|
|
83
|
+
stopRequested = true;
|
|
84
|
+
console.log(chalk.yellow('\n\nGraceful stop requested - will stop after current task completes.'));
|
|
85
|
+
console.log(chalk.gray('Press Ctrl+C again to force stop (may leave work incomplete).'));
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
process.on('SIGINT', handler);
|
|
89
|
+
// Return cleanup function
|
|
90
|
+
return () => {
|
|
91
|
+
process.removeListener('SIGINT', handler);
|
|
92
|
+
stopRequested = false;
|
|
93
|
+
forceStopRequested = false;
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
export async function runLoop(config) {
|
|
97
|
+
const spinner = ora();
|
|
98
|
+
const cleanupShutdownHandler = setupGracefulShutdown();
|
|
99
|
+
// Set initial terminal title
|
|
100
|
+
const featurePrefix = config.featureName ? `[${config.featureName}] ` : '';
|
|
101
|
+
setTerminalTitle(`DevLoop: ${featurePrefix}Starting...`);
|
|
102
|
+
console.log(chalk.blue.bold(`\n=== DevLoop Starting ${config.featureName ? `(Feature: ${config.featureName})` : ''} ===\n`));
|
|
103
|
+
console.log(chalk.gray('Tip: Press Ctrl+C to stop after the current task completes.'));
|
|
104
|
+
console.log(chalk.gray(`Workspace: ${config.workspacePath}`));
|
|
105
|
+
if (config.featureName) {
|
|
106
|
+
console.log(chalk.gray(`Feature: ${config.featureName}`));
|
|
107
|
+
}
|
|
108
|
+
console.log(chalk.gray(`Requirements: ${config.requirementsPath}`));
|
|
109
|
+
console.log(chalk.gray(`Progress: ${config.progressPath}`));
|
|
110
|
+
console.log(chalk.gray(`Max iterations: ${config.maxIterations}`));
|
|
111
|
+
if (config.tokenLimit) {
|
|
112
|
+
console.log(chalk.gray(`Token limit: ${config.tokenLimit.toLocaleString()} (per session)`));
|
|
113
|
+
}
|
|
114
|
+
if (config.costLimit) {
|
|
115
|
+
console.log(chalk.gray(`Cost limit: $${config.costLimit.toFixed(2)} (per session)`));
|
|
116
|
+
}
|
|
117
|
+
console.log(chalk.green(`Workspace restriction: ENABLED (--add-dir)`));
|
|
118
|
+
if (config.dryRun) {
|
|
119
|
+
console.log(chalk.yellow('DRY RUN MODE - No changes will be made'));
|
|
120
|
+
}
|
|
121
|
+
console.log();
|
|
122
|
+
// Ensure git repo is set up for version control
|
|
123
|
+
const gitSetup = await ensureGitRepo(config.workspacePath, config.verbose);
|
|
124
|
+
if (gitSetup.gitAvailable) {
|
|
125
|
+
if (gitSetup.wasInitialized) {
|
|
126
|
+
console.log(chalk.green('Git: Repository initialized with initial commit'));
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
console.log(chalk.green('Git: Version control enabled'));
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
console.log(chalk.yellow('Git: Not available - changes will not be versioned'));
|
|
134
|
+
}
|
|
135
|
+
// Check for uncommitted changes (potential interrupted work)
|
|
136
|
+
// Ignore .devloop/ changes as these are session files updated at run start
|
|
137
|
+
let hasInterruptedWork = false;
|
|
138
|
+
let interruptedDuringTask = false; // Track if we interrupted mid-task (for end-of-loop messaging)
|
|
139
|
+
if (gitSetup.gitAvailable) {
|
|
140
|
+
const uncommitted = await getUncommittedChanges(config.workspacePath, ['.devloop/']);
|
|
141
|
+
if (uncommitted.hasChanges) {
|
|
142
|
+
hasInterruptedWork = true;
|
|
143
|
+
console.log(chalk.yellow('\nDetected uncommitted changes (possible interrupted work):'));
|
|
144
|
+
for (const file of uncommitted.files.slice(0, 10)) {
|
|
145
|
+
console.log(chalk.gray(` - ${file}`));
|
|
146
|
+
}
|
|
147
|
+
if (uncommitted.files.length > 10) {
|
|
148
|
+
console.log(chalk.gray(` ... and ${uncommitted.files.length - 10} more files`));
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
console.log();
|
|
153
|
+
// Create/update session AFTER uncommitted changes check to avoid false positives
|
|
154
|
+
if (config.sessionAction === 'create') {
|
|
155
|
+
await createSession(config.workspacePath, 'run');
|
|
156
|
+
await updateSessionPhase(config.workspacePath, 'run');
|
|
157
|
+
}
|
|
158
|
+
else if (config.sessionAction === 'update') {
|
|
159
|
+
await updateSessionPhase(config.workspacePath, 'run');
|
|
160
|
+
}
|
|
161
|
+
else if (config.sessionAction === 'create-feature' && config.featureName) {
|
|
162
|
+
await createFeatureSession(config.workspacePath, config.featureName, 'run');
|
|
163
|
+
}
|
|
164
|
+
// Load existing progress to determine starting iteration and token usage
|
|
165
|
+
const existingProgress = await readProgress(config.progressPath);
|
|
166
|
+
const startIteration = existingProgress ? existingProgress.iterations.length + 1 : 1;
|
|
167
|
+
// Calculate project totals from previous iterations (for display)
|
|
168
|
+
let projectTokens = { input: 0, output: 0, cacheWrite: 0, cacheRead: 0, total: 0 };
|
|
169
|
+
let projectCost = 0;
|
|
170
|
+
if (existingProgress) {
|
|
171
|
+
for (const iter of existingProgress.iterations) {
|
|
172
|
+
if (iter.tokenUsage) {
|
|
173
|
+
projectTokens.input += iter.tokenUsage.inputTokens;
|
|
174
|
+
projectTokens.output += iter.tokenUsage.outputTokens;
|
|
175
|
+
projectTokens.cacheWrite += iter.tokenUsage.cacheCreationTokens;
|
|
176
|
+
projectTokens.cacheRead += iter.tokenUsage.cacheReadTokens;
|
|
177
|
+
projectTokens.total += iter.tokenUsage.totalTokens;
|
|
178
|
+
projectCost += iter.tokenUsage.costUsd;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
// Track session tokens separately (for limit checking)
|
|
183
|
+
let sessionTokens = { input: 0, output: 0, cacheWrite: 0, cacheRead: 0, total: 0 };
|
|
184
|
+
let sessionCost = 0;
|
|
185
|
+
// Helper to calculate price per million tokens
|
|
186
|
+
const pricePerMillion = (cost, tokens) => {
|
|
187
|
+
if (tokens === 0)
|
|
188
|
+
return '0.00';
|
|
189
|
+
return ((cost / tokens) * 1_000_000).toFixed(2);
|
|
190
|
+
};
|
|
191
|
+
// maxIterations is additional iterations to run, not absolute count
|
|
192
|
+
const endIteration = startIteration + config.maxIterations - 1;
|
|
193
|
+
if (existingProgress && existingProgress.iterations.length > 0) {
|
|
194
|
+
console.log(chalk.yellow(`Resuming from iteration ${startIteration}`));
|
|
195
|
+
console.log(chalk.gray(`Previously completed: ${existingProgress.completed} tasks`));
|
|
196
|
+
console.log(chalk.gray(`Will run up to ${config.maxIterations} more iterations (${startIteration}-${endIteration})`));
|
|
197
|
+
if (projectTokens.total > 0) {
|
|
198
|
+
console.log(chalk.gray(`Project tokens: ${projectTokens.total.toLocaleString()} total`));
|
|
199
|
+
console.log(chalk.gray(` In: ${projectTokens.input.toLocaleString()} | Out: ${projectTokens.output.toLocaleString()} | Cache +${projectTokens.cacheWrite.toLocaleString()}/-${projectTokens.cacheRead.toLocaleString()}`));
|
|
200
|
+
console.log(chalk.gray(`Project cost: $${projectCost.toFixed(4)} (~$${pricePerMillion(projectCost, projectTokens.total)}/M)`));
|
|
201
|
+
}
|
|
202
|
+
console.log();
|
|
203
|
+
}
|
|
204
|
+
for (let i = startIteration; i <= endIteration; i++) {
|
|
205
|
+
// Check for graceful stop request
|
|
206
|
+
if (stopRequested) {
|
|
207
|
+
console.log(chalk.yellow('\nStopping as requested.'));
|
|
208
|
+
break;
|
|
209
|
+
}
|
|
210
|
+
// Check token limit before starting iteration (session tokens only)
|
|
211
|
+
if (config.tokenLimit && sessionTokens.total >= config.tokenLimit) {
|
|
212
|
+
console.log(chalk.yellow(`\nSession token limit reached: ${sessionTokens.total.toLocaleString()} / ${config.tokenLimit.toLocaleString()}`));
|
|
213
|
+
console.log(chalk.yellow('Stopping to prevent rate limit errors.'));
|
|
214
|
+
break;
|
|
215
|
+
}
|
|
216
|
+
// Check cost limit before starting iteration (session cost only)
|
|
217
|
+
if (config.costLimit && sessionCost >= config.costLimit) {
|
|
218
|
+
console.log(chalk.yellow(`\nSession cost limit reached: $${sessionCost.toFixed(4)} / $${config.costLimit.toFixed(2)}`));
|
|
219
|
+
console.log(chalk.yellow('Stopping to control costs.'));
|
|
220
|
+
break;
|
|
221
|
+
}
|
|
222
|
+
const iterationStart = new Date();
|
|
223
|
+
// Parse requirements fresh each iteration
|
|
224
|
+
spinner.start(chalk.cyan(`Iteration ${i}: Reading requirements...`));
|
|
225
|
+
let requirements;
|
|
226
|
+
try {
|
|
227
|
+
requirements = await parseRequirements(config.requirementsPath);
|
|
228
|
+
}
|
|
229
|
+
catch (error) {
|
|
230
|
+
spinner.fail(chalk.red(`Failed to parse requirements: ${error}`));
|
|
231
|
+
break;
|
|
232
|
+
}
|
|
233
|
+
spinner.stop();
|
|
234
|
+
// Check if all tasks are done
|
|
235
|
+
const pendingTasks = requirements.tasks.filter(t => t.status === 'pending');
|
|
236
|
+
const doneTasks = requirements.tasks.filter(t => t.status === 'done');
|
|
237
|
+
if (pendingTasks.length === 0) {
|
|
238
|
+
setTerminalTitle(`DevLoop: ${featurePrefix}All ${doneTasks.length} tasks complete!`);
|
|
239
|
+
console.log(chalk.green.bold('\n✓ All tasks completed!'));
|
|
240
|
+
console.log(chalk.gray(`Completed ${doneTasks.length} tasks in ${i - 1} iterations.`));
|
|
241
|
+
break;
|
|
242
|
+
}
|
|
243
|
+
// Get next task based on dependencies and priority
|
|
244
|
+
const nextTask = getNextTask(requirements);
|
|
245
|
+
if (!nextTask) {
|
|
246
|
+
console.log(chalk.yellow('\nNo available tasks (all remaining tasks have unmet dependencies)'));
|
|
247
|
+
console.log(chalk.gray('Blocked tasks:'));
|
|
248
|
+
for (const task of pendingTasks) {
|
|
249
|
+
console.log(chalk.gray(` - ${task.id}: depends on ${task.dependencies.join(', ')}`));
|
|
250
|
+
}
|
|
251
|
+
break;
|
|
252
|
+
}
|
|
253
|
+
// Commit interrupted work before starting fresh (only on first iteration)
|
|
254
|
+
if (hasInterruptedWork) {
|
|
255
|
+
console.log(chalk.cyan(`\nCommitting interrupted work (likely from ${nextTask.id})...`));
|
|
256
|
+
const committed = await commitInterruptedWork(config.workspacePath, nextTask.id, nextTask.title, config.verbose);
|
|
257
|
+
if (committed) {
|
|
258
|
+
console.log(chalk.green('Interrupted work committed. Starting fresh.'));
|
|
259
|
+
}
|
|
260
|
+
else {
|
|
261
|
+
// Failed to commit uncommitted changes - stop and let user fix it
|
|
262
|
+
console.log(chalk.red.bold('\n⚠ Failed to commit uncommitted changes'));
|
|
263
|
+
console.log(chalk.red('DevLoop detected uncommitted changes but could not commit them.'));
|
|
264
|
+
console.log(chalk.yellow('\nPlease resolve this manually:'));
|
|
265
|
+
console.log(chalk.gray(' 1. Run "git status" to see the uncommitted changes'));
|
|
266
|
+
console.log(chalk.gray(' 2. Either commit them: git add -A && git commit -m "message"'));
|
|
267
|
+
console.log(chalk.gray(' 3. Or discard them: git checkout -- . && git clean -fd'));
|
|
268
|
+
console.log(chalk.gray(' 4. Then run "devloop continue" to resume\n'));
|
|
269
|
+
break;
|
|
270
|
+
}
|
|
271
|
+
hasInterruptedWork = false; // Only handle once
|
|
272
|
+
}
|
|
273
|
+
// Update terminal title with current task
|
|
274
|
+
const totalTasks = requirements.tasks.length;
|
|
275
|
+
const completedTasks = doneTasks.length;
|
|
276
|
+
setTerminalTitle(`DevLoop: ${featurePrefix}${i}/${config.maxIterations} - ${nextTask.id} (${completedTasks}/${totalTasks} done)`);
|
|
277
|
+
console.log(chalk.cyan(`\nIteration ${i}: ${nextTask.id} - ${nextTask.title}`));
|
|
278
|
+
console.log(chalk.gray(` Priority: ${nextTask.priority}`));
|
|
279
|
+
console.log(chalk.gray(` Description: ${nextTask.description}`));
|
|
280
|
+
console.log(chalk.gray(` Press Ctrl+C to stop after this task completes`));
|
|
281
|
+
if (config.dryRun) {
|
|
282
|
+
console.log(chalk.yellow(` [DRY RUN] Would execute this task`));
|
|
283
|
+
// Record dry run iteration
|
|
284
|
+
const iterationLog = {
|
|
285
|
+
iteration: i,
|
|
286
|
+
timestamp: iterationStart.toISOString(),
|
|
287
|
+
taskCompleted: null,
|
|
288
|
+
summary: `[DRY RUN] Would have executed: ${nextTask.title}`,
|
|
289
|
+
duration: '0s',
|
|
290
|
+
exitStatus: 'partial'
|
|
291
|
+
};
|
|
292
|
+
// Don't actually append to progress in dry run
|
|
293
|
+
continue;
|
|
294
|
+
}
|
|
295
|
+
// Build prompt and invoke Claude with timed spinner
|
|
296
|
+
const taskStartTime = Date.now();
|
|
297
|
+
const currentTitle = `DevLoop: ${i}/${config.maxIterations} - ${nextTask.id} (${completedTasks}/${totalTasks} done)`;
|
|
298
|
+
const spinnerState = startTimedSpinner(spinner, ` Claude working on ${nextTask.id}`, taskStartTime, config.verbose, currentTitle);
|
|
299
|
+
const prompt = buildTaskPrompt(nextTask, config.requirementsPath, config.progressPath, config.workspacePath);
|
|
300
|
+
const result = await invokeClaudeAutomated(prompt, config.workspacePath, {
|
|
301
|
+
verbose: config.verbose,
|
|
302
|
+
onProgress: (activity) => {
|
|
303
|
+
updateSpinnerActivity(spinnerState, activity);
|
|
304
|
+
}
|
|
305
|
+
});
|
|
306
|
+
// Stop the spinner interval
|
|
307
|
+
if (spinnerState.interval) {
|
|
308
|
+
clearInterval(spinnerState.interval);
|
|
309
|
+
}
|
|
310
|
+
// Check if stop was requested during task execution
|
|
311
|
+
// If so, treat as interrupted - do NOT mark as complete even if Claude exited cleanly
|
|
312
|
+
if (stopRequested) {
|
|
313
|
+
if (config.verbose) {
|
|
314
|
+
console.log(chalk.yellow(` ⚠ Task interrupted by user request`));
|
|
315
|
+
}
|
|
316
|
+
else {
|
|
317
|
+
spinner.warn(chalk.yellow(` Task ${nextTask.id} interrupted by user request`));
|
|
318
|
+
}
|
|
319
|
+
const duration = `${Math.round(result.duration / 1000)}s`;
|
|
320
|
+
// Record as interrupted - task was NOT completed
|
|
321
|
+
const iterationLog = {
|
|
322
|
+
iteration: i,
|
|
323
|
+
timestamp: iterationStart.toISOString(),
|
|
324
|
+
taskCompleted: null, // NOT completed
|
|
325
|
+
summary: `Interrupted: ${nextTask.title} (user requested stop)`,
|
|
326
|
+
duration,
|
|
327
|
+
exitStatus: 'interrupted',
|
|
328
|
+
tokenUsage: result.tokenUsage
|
|
329
|
+
};
|
|
330
|
+
await appendIteration(config.progressPath, requirements.tasks.length, iterationLog);
|
|
331
|
+
// Update session iteration count
|
|
332
|
+
if (config.featureName) {
|
|
333
|
+
await updateFeatureSessionIteration(config.workspacePath, config.featureName, i);
|
|
334
|
+
}
|
|
335
|
+
else {
|
|
336
|
+
await updateSessionIteration(config.workspacePath, i);
|
|
337
|
+
}
|
|
338
|
+
// Commit the interrupted state (if any changes were made)
|
|
339
|
+
await commitIteration(config.workspacePath, i, null, // No task completed
|
|
340
|
+
null, false, // Not successful
|
|
341
|
+
config.verbose, config.featureName);
|
|
342
|
+
console.log(chalk.yellow('\nStopping as requested. Task was NOT marked as complete.'));
|
|
343
|
+
console.log(chalk.gray('Run "devloop continue" to resume and retry this task.'));
|
|
344
|
+
interruptedDuringTask = true;
|
|
345
|
+
break;
|
|
346
|
+
}
|
|
347
|
+
// Update token tracking (both session and project)
|
|
348
|
+
if (result.tokenUsage) {
|
|
349
|
+
sessionTokens.input += result.tokenUsage.inputTokens;
|
|
350
|
+
sessionTokens.output += result.tokenUsage.outputTokens;
|
|
351
|
+
sessionTokens.cacheWrite += result.tokenUsage.cacheCreationTokens;
|
|
352
|
+
sessionTokens.cacheRead += result.tokenUsage.cacheReadTokens;
|
|
353
|
+
sessionTokens.total += result.tokenUsage.totalTokens;
|
|
354
|
+
sessionCost += result.tokenUsage.costUsd;
|
|
355
|
+
projectTokens.input += result.tokenUsage.inputTokens;
|
|
356
|
+
projectTokens.output += result.tokenUsage.outputTokens;
|
|
357
|
+
projectTokens.cacheWrite += result.tokenUsage.cacheCreationTokens;
|
|
358
|
+
projectTokens.cacheRead += result.tokenUsage.cacheReadTokens;
|
|
359
|
+
projectTokens.total += result.tokenUsage.totalTokens;
|
|
360
|
+
projectCost += result.tokenUsage.costUsd;
|
|
361
|
+
}
|
|
362
|
+
const duration = `${Math.round(result.duration / 1000)}s`;
|
|
363
|
+
// Record iteration with error details and token usage
|
|
364
|
+
const iterationLog = {
|
|
365
|
+
iteration: i,
|
|
366
|
+
timestamp: iterationStart.toISOString(),
|
|
367
|
+
taskCompleted: result.success ? nextTask.id : null,
|
|
368
|
+
summary: result.success
|
|
369
|
+
? `Completed ${nextTask.title}`
|
|
370
|
+
: `Failed: ${result.error?.split('\n')[0] || 'Unknown error'}`,
|
|
371
|
+
duration,
|
|
372
|
+
exitStatus: result.success ? 'success' : 'error',
|
|
373
|
+
errorType: result.success ? undefined : result.errorType,
|
|
374
|
+
errorDetail: result.success ? undefined : result.error,
|
|
375
|
+
tokenUsage: result.tokenUsage
|
|
376
|
+
};
|
|
377
|
+
// Update progress file
|
|
378
|
+
await appendIteration(config.progressPath, requirements.tasks.length, iterationLog);
|
|
379
|
+
// Update session (feature or legacy)
|
|
380
|
+
if (config.featureName) {
|
|
381
|
+
await updateFeatureSessionIteration(config.workspacePath, config.featureName, i);
|
|
382
|
+
}
|
|
383
|
+
else {
|
|
384
|
+
await updateSessionIteration(config.workspacePath, i);
|
|
385
|
+
}
|
|
386
|
+
if (result.success) {
|
|
387
|
+
const tokenInfo = result.tokenUsage
|
|
388
|
+
? ` [${result.tokenUsage.totalTokens.toLocaleString()} tokens]`
|
|
389
|
+
: '';
|
|
390
|
+
if (config.verbose) {
|
|
391
|
+
console.log(chalk.green(` ✓ Completed ${nextTask.id} (${duration})${tokenInfo}`));
|
|
392
|
+
}
|
|
393
|
+
else {
|
|
394
|
+
spinner.succeed(chalk.green(` Completed ${nextTask.id} (${duration})${tokenInfo}`));
|
|
395
|
+
}
|
|
396
|
+
// Show detailed token usage breakdown
|
|
397
|
+
if (result.tokenUsage) {
|
|
398
|
+
const t = result.tokenUsage;
|
|
399
|
+
console.log(chalk.gray(` This iteration: ${t.totalTokens.toLocaleString()} tokens ($${t.costUsd.toFixed(4)}, ~$${pricePerMillion(t.costUsd, t.totalTokens)}/M)`));
|
|
400
|
+
console.log(chalk.gray(` In: ${t.inputTokens.toLocaleString()} | Out: ${t.outputTokens.toLocaleString()} | Cache +${t.cacheCreationTokens.toLocaleString()}/-${t.cacheReadTokens.toLocaleString()}`));
|
|
401
|
+
console.log(chalk.gray(` Session: ${sessionTokens.total.toLocaleString()} tokens ($${sessionCost.toFixed(4)}, ~$${pricePerMillion(sessionCost, sessionTokens.total)}/M)`));
|
|
402
|
+
console.log(chalk.gray(` Project: ${projectTokens.total.toLocaleString()} tokens ($${projectCost.toFixed(4)}, ~$${pricePerMillion(projectCost, projectTokens.total)}/M)`));
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
else {
|
|
406
|
+
if (config.verbose) {
|
|
407
|
+
console.log(chalk.red(` ✗ Failed ${nextTask.id} - ${result.error}`));
|
|
408
|
+
}
|
|
409
|
+
else {
|
|
410
|
+
spinner.fail(chalk.red(` Failed ${nextTask.id} - ${result.error}`));
|
|
411
|
+
}
|
|
412
|
+
// Check if this is an API error (not a task failure)
|
|
413
|
+
if (isApiError(result.errorType)) {
|
|
414
|
+
console.log(chalk.red.bold('\n⚠ API Error Detected - Stopping DevLoop\n'));
|
|
415
|
+
console.log(chalk.red(` Error Type: ${result.errorType}`));
|
|
416
|
+
console.log(chalk.red(` Details: ${result.error}`));
|
|
417
|
+
console.log(chalk.yellow('\n This is an API-level error, not a task failure.'));
|
|
418
|
+
console.log(chalk.yellow(' Please resolve the issue before continuing.\n'));
|
|
419
|
+
break;
|
|
420
|
+
}
|
|
421
|
+
// Task failure - continue to next iteration (future attempt may succeed)
|
|
422
|
+
console.log(chalk.yellow(' Continuing to next task...'));
|
|
423
|
+
}
|
|
424
|
+
// Commit iteration changes to git (if available)
|
|
425
|
+
const commitResult = await commitIteration(config.workspacePath, i, result.success ? nextTask.id : null, result.success ? nextTask.title : null, result.success, config.verbose, config.featureName);
|
|
426
|
+
// Stop loop if commit failed due to a hook
|
|
427
|
+
if (commitResult.hookFailure) {
|
|
428
|
+
console.log(chalk.yellow('\nStopping DevLoop due to commit hook failure.'));
|
|
429
|
+
console.log(chalk.gray('Fix the commit message format and run "devloop run" again.'));
|
|
430
|
+
break;
|
|
431
|
+
}
|
|
432
|
+
// Small delay between iterations to avoid rate limiting
|
|
433
|
+
await sleep(1000);
|
|
434
|
+
}
|
|
435
|
+
// Clean up signal handler
|
|
436
|
+
cleanupShutdownHandler();
|
|
437
|
+
// Final summary
|
|
438
|
+
console.log(chalk.blue.bold('\n=== DevLoop Complete ===\n'));
|
|
439
|
+
const finalProgress = await readProgress(config.progressPath);
|
|
440
|
+
if (finalProgress) {
|
|
441
|
+
const successCount = finalProgress.iterations.filter(i => i.exitStatus === 'success').length;
|
|
442
|
+
console.log(chalk.gray(`Total iterations: ${finalProgress.iterations.length}`));
|
|
443
|
+
console.log(chalk.green(`Successful: ${successCount}`));
|
|
444
|
+
console.log(chalk.red(`Failed: ${finalProgress.iterations.length - successCount}`));
|
|
445
|
+
console.log(chalk.gray(`Tasks completed: ${finalProgress.completed}/${finalProgress.totalTasks}`));
|
|
446
|
+
// Set final terminal title
|
|
447
|
+
if (stopRequested) {
|
|
448
|
+
setTerminalTitle(`DevLoop: Stopped (${finalProgress.completed}/${finalProgress.totalTasks} tasks)`);
|
|
449
|
+
}
|
|
450
|
+
else if (finalProgress.completed === finalProgress.totalTasks) {
|
|
451
|
+
setTerminalTitle(`DevLoop: Complete! (${finalProgress.totalTasks} tasks)`);
|
|
452
|
+
}
|
|
453
|
+
else {
|
|
454
|
+
setTerminalTitle(`DevLoop: Done (${finalProgress.completed}/${finalProgress.totalTasks} tasks)`);
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
else {
|
|
458
|
+
setTerminalTitle('DevLoop: Complete');
|
|
459
|
+
}
|
|
460
|
+
if (stopRequested && !interruptedDuringTask) {
|
|
461
|
+
// Only show generic message if we stopped between tasks, not mid-task
|
|
462
|
+
// (mid-task interruption already printed detailed messaging)
|
|
463
|
+
console.log(chalk.yellow('\nRun was stopped by user. Use "devloop continue" to resume.'));
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
function sleep(ms) {
|
|
467
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
468
|
+
}
|
|
469
|
+
//# sourceMappingURL=loop.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loop.js","sourceRoot":"","sources":["../../src/core/loop.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Session, SessionPhase } from '../types/index.js';
|
|
2
|
+
export declare function readSession(workspace: string): Promise<Session | null>;
|
|
3
|
+
export declare function writeSession(workspace: string, session: Session): Promise<void>;
|
|
4
|
+
export declare function createSession(workspace: string, phase: SessionPhase): Promise<Session>;
|
|
5
|
+
export declare function updateSessionPhase(workspace: string, phase: SessionPhase): Promise<void>;
|
|
6
|
+
export declare function updateSessionIteration(workspace: string, iteration: number): Promise<void>;
|
|
7
|
+
//# sourceMappingURL=session.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/core/session.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAkB1D,wBAAsB,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAQ5E;AAED,wBAAsB,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAIrF;AAED,wBAAsB,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC,CAS5F;AAED,wBAAsB,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAM9F;AAED,wBAAsB,sBAAsB,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAMhG"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import * as fs from 'fs/promises';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
const DEFAULT_SESSION = {
|
|
4
|
+
phase: 'init',
|
|
5
|
+
sessionId: null,
|
|
6
|
+
lastIteration: 0,
|
|
7
|
+
startedAt: new Date().toISOString()
|
|
8
|
+
};
|
|
9
|
+
async function ensureSessionDir(workspace) {
|
|
10
|
+
const sessionDir = path.join(workspace, '.devloop');
|
|
11
|
+
try {
|
|
12
|
+
await fs.mkdir(sessionDir, { recursive: true });
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
// Directory already exists
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
export async function readSession(workspace) {
|
|
19
|
+
const sessionPath = path.join(workspace, '.devloop', 'session.json');
|
|
20
|
+
try {
|
|
21
|
+
const content = await fs.readFile(sessionPath, 'utf-8');
|
|
22
|
+
return JSON.parse(content);
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
export async function writeSession(workspace, session) {
|
|
29
|
+
await ensureSessionDir(workspace);
|
|
30
|
+
const sessionPath = path.join(workspace, '.devloop', 'session.json');
|
|
31
|
+
await fs.writeFile(sessionPath, JSON.stringify(session, null, 2), 'utf-8');
|
|
32
|
+
}
|
|
33
|
+
export async function createSession(workspace, phase) {
|
|
34
|
+
const session = {
|
|
35
|
+
phase,
|
|
36
|
+
sessionId: null,
|
|
37
|
+
lastIteration: 0,
|
|
38
|
+
startedAt: new Date().toISOString()
|
|
39
|
+
};
|
|
40
|
+
await writeSession(workspace, session);
|
|
41
|
+
return session;
|
|
42
|
+
}
|
|
43
|
+
export async function updateSessionPhase(workspace, phase) {
|
|
44
|
+
const session = await readSession(workspace);
|
|
45
|
+
if (session) {
|
|
46
|
+
session.phase = phase;
|
|
47
|
+
await writeSession(workspace, session);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
export async function updateSessionIteration(workspace, iteration) {
|
|
51
|
+
const session = await readSession(workspace);
|
|
52
|
+
if (session) {
|
|
53
|
+
session.lastIteration = iteration;
|
|
54
|
+
await writeSession(workspace, session);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/core/session.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,aAAa,CAAC;AAClC,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAG7B,MAAM,eAAe,GAAY;IAC/B,KAAK,EAAE,MAAM;IACb,SAAS,EAAE,IAAI;IACf,aAAa,EAAE,CAAC;IAChB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;CACpC,CAAC;AAEF,KAAK,UAAU,gBAAgB,CAAC,SAAiB;IAC/C,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;IACpD,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,KAAK,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAClD,CAAC;IAAC,MAAM,CAAC;QACP,2BAA2B;IAC7B,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,SAAiB;IACjD,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,UAAU,EAAE,cAAc,CAAC,CAAC;IACrE,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QACxD,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC7B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,SAAiB,EAAE,OAAgB;IACpE,MAAM,gBAAgB,CAAC,SAAS,CAAC,CAAC;IAClC,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,UAAU,EAAE,cAAc,CAAC,CAAC;IACrE,MAAM,EAAE,CAAC,SAAS,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;AAC7E,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,SAAiB,EAAE,KAAmB;IACxE,MAAM,OAAO,GAAY;QACvB,KAAK;QACL,SAAS,EAAE,IAAI;QACf,aAAa,EAAE,CAAC;QAChB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACpC,CAAC;IACF,MAAM,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IACvC,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,SAAiB,EAAE,KAAmB;IAC7E,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,SAAS,CAAC,CAAC;IAC7C,IAAI,OAAO,EAAE,CAAC;QACZ,OAAO,CAAC,KAAK,GAAG,KAAK,CAAC;QACtB,MAAM,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IACzC,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAAC,SAAiB,EAAE,SAAiB;IAC/E,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,SAAS,CAAC,CAAC;IAC7C,IAAI,OAAO,EAAE,CAAC;QACZ,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC;QAClC,MAAM,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IACzC,CAAC;AACH,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAEnC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Progress, IterationLog } from '../types/index.js';
|
|
2
|
+
export declare function readProgress(filePath: string): Promise<Progress | null>;
|
|
3
|
+
export declare function parseProgressContent(content: string): Progress;
|
|
4
|
+
export declare function generateProgressContent(totalTasks: number, completedCount: number, iterations: IterationLog[]): string;
|
|
5
|
+
export declare function writeProgress(filePath: string, progress: Progress): Promise<void>;
|
|
6
|
+
export declare function appendIteration(filePath: string, totalTasks: number, iteration: IterationLog): Promise<void>;
|
|
7
|
+
//# sourceMappingURL=progress.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"progress.d.ts","sourceRoot":"","sources":["../../src/parser/progress.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,QAAQ,EAAE,YAAY,EAA2C,MAAM,mBAAmB,CAAC;AAEpG,wBAAsB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAO7E;AAED,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,QAAQ,CA4D9D;AAED,wBAAgB,uBAAuB,CACrC,UAAU,EAAE,MAAM,EAClB,cAAc,EAAE,MAAM,EACtB,UAAU,EAAE,YAAY,EAAE,GACzB,MAAM,CA6CR;AAED,wBAAsB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CASvF;AAED,wBAAsB,eAAe,CACnC,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,YAAY,GACtB,OAAO,CAAC,IAAI,CAAC,CAqBf"}
|