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,401 @@
|
|
|
1
|
+
import { spawn } from 'child_process';
|
|
2
|
+
import * as fs from 'fs/promises';
|
|
3
|
+
import * as fsSync from 'fs';
|
|
4
|
+
import * as path from 'path';
|
|
5
|
+
import * as os from 'os';
|
|
6
|
+
/**
|
|
7
|
+
* Parse token usage from Claude JSON output
|
|
8
|
+
*/
|
|
9
|
+
function parseTokenUsage(jsonOutput) {
|
|
10
|
+
try {
|
|
11
|
+
const usage = jsonOutput?.usage;
|
|
12
|
+
if (!usage)
|
|
13
|
+
return undefined;
|
|
14
|
+
const inputTokens = usage.input_tokens || 0;
|
|
15
|
+
const outputTokens = usage.output_tokens || 0;
|
|
16
|
+
const cacheCreationTokens = usage.cache_creation_input_tokens || 0;
|
|
17
|
+
const cacheReadTokens = usage.cache_read_input_tokens || 0;
|
|
18
|
+
return {
|
|
19
|
+
inputTokens,
|
|
20
|
+
outputTokens,
|
|
21
|
+
cacheCreationTokens,
|
|
22
|
+
cacheReadTokens,
|
|
23
|
+
totalTokens: inputTokens + outputTokens + cacheCreationTokens + cacheReadTokens,
|
|
24
|
+
costUsd: jsonOutput?.total_cost_usd || 0
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Classifies an error from Claude CLI output to determine if it's an API error
|
|
33
|
+
* (which should stop the loop) or a task failure (which can continue).
|
|
34
|
+
*/
|
|
35
|
+
function classifyError(stderr, errorMessage) {
|
|
36
|
+
const errorText = ((stderr || '') + (errorMessage || '')).toLowerCase();
|
|
37
|
+
// Rate limit errors (400/429)
|
|
38
|
+
if (errorText.includes('rate limit') ||
|
|
39
|
+
errorText.includes('api usage limit') ||
|
|
40
|
+
errorText.includes('429') ||
|
|
41
|
+
(errorText.includes('400') && errorText.includes('limit'))) {
|
|
42
|
+
return 'rate_limit';
|
|
43
|
+
}
|
|
44
|
+
// API overload (503)
|
|
45
|
+
if (errorText.includes('overload') || errorText.includes('503')) {
|
|
46
|
+
return 'api_overload';
|
|
47
|
+
}
|
|
48
|
+
// Authentication errors (401)
|
|
49
|
+
if (errorText.includes('401') ||
|
|
50
|
+
errorText.includes('unauthorized') ||
|
|
51
|
+
errorText.includes('authentication')) {
|
|
52
|
+
return 'auth_error';
|
|
53
|
+
}
|
|
54
|
+
// Network errors
|
|
55
|
+
if (errorText.includes('econnrefused') ||
|
|
56
|
+
errorText.includes('enotfound') ||
|
|
57
|
+
errorText.includes('timeout') ||
|
|
58
|
+
errorText.includes('network')) {
|
|
59
|
+
return 'network_error';
|
|
60
|
+
}
|
|
61
|
+
// If it has "api error" in it, treat as unknown API error
|
|
62
|
+
if (errorText.includes('api error')) {
|
|
63
|
+
return 'unknown';
|
|
64
|
+
}
|
|
65
|
+
// Otherwise it's likely a task failure (Claude ran but task didn't complete)
|
|
66
|
+
return 'task_failure';
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Checks if an error type represents an API-level error that should stop the loop.
|
|
70
|
+
*/
|
|
71
|
+
export function isApiError(errorType) {
|
|
72
|
+
return errorType !== undefined && errorType !== 'task_failure';
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Creates a workspace-scoped Claude settings file that restricts
|
|
76
|
+
* file operations to the workspace directory only.
|
|
77
|
+
*/
|
|
78
|
+
export async function ensureWorkspaceSettings(workspacePath) {
|
|
79
|
+
const claudeDir = path.join(workspacePath, '.claude');
|
|
80
|
+
const settingsPath = path.join(claudeDir, 'settings.json');
|
|
81
|
+
try {
|
|
82
|
+
await fs.mkdir(claudeDir, { recursive: true });
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
// Directory exists
|
|
86
|
+
}
|
|
87
|
+
const settings = {
|
|
88
|
+
permissions: {
|
|
89
|
+
allow: [
|
|
90
|
+
`Bash(cd:${workspacePath})`,
|
|
91
|
+
`Bash(cd:${workspacePath}/**)`,
|
|
92
|
+
"Bash(npm:*)",
|
|
93
|
+
"Bash(npx:*)",
|
|
94
|
+
"Bash(node:*)",
|
|
95
|
+
"Bash(git:*)",
|
|
96
|
+
"Bash(tsc:*)",
|
|
97
|
+
"Bash(mkdir:*)",
|
|
98
|
+
"Bash(ls:*)",
|
|
99
|
+
"Bash(cat:*)",
|
|
100
|
+
"Bash(echo:*)",
|
|
101
|
+
"Read",
|
|
102
|
+
"Write",
|
|
103
|
+
"Edit",
|
|
104
|
+
"Glob",
|
|
105
|
+
"Grep"
|
|
106
|
+
],
|
|
107
|
+
deny: [
|
|
108
|
+
"Bash(rm -rf /)",
|
|
109
|
+
"Bash(rm -rf ~)",
|
|
110
|
+
"Bash(rm -rf ..)",
|
|
111
|
+
"Bash(sudo:*)",
|
|
112
|
+
"Bash(chmod:*)",
|
|
113
|
+
"Bash(chown:*)"
|
|
114
|
+
]
|
|
115
|
+
},
|
|
116
|
+
restrictToWorkspace: true,
|
|
117
|
+
workspacePath: workspacePath
|
|
118
|
+
};
|
|
119
|
+
await fs.writeFile(settingsPath, JSON.stringify(settings, null, 2), 'utf-8');
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Format a tool name and input into a human-readable activity string.
|
|
123
|
+
*/
|
|
124
|
+
function formatToolActivity(toolName, toolInput) {
|
|
125
|
+
// Extract relevant info from tool input
|
|
126
|
+
let detail = '';
|
|
127
|
+
if (toolInput) {
|
|
128
|
+
// Common patterns in tool inputs
|
|
129
|
+
if (toolInput.file_path) {
|
|
130
|
+
detail = toolInput.file_path;
|
|
131
|
+
}
|
|
132
|
+
else if (toolInput.path) {
|
|
133
|
+
detail = toolInput.path;
|
|
134
|
+
}
|
|
135
|
+
else if (toolInput.pattern) {
|
|
136
|
+
detail = toolInput.pattern;
|
|
137
|
+
}
|
|
138
|
+
else if (toolInput.command) {
|
|
139
|
+
// For bash, show just the first word of the command
|
|
140
|
+
detail = toolInput.command.split(' ')[0].split('\n')[0];
|
|
141
|
+
}
|
|
142
|
+
else if (toolInput.query) {
|
|
143
|
+
detail = toolInput.query.slice(0, 30);
|
|
144
|
+
}
|
|
145
|
+
else if (toolInput.url) {
|
|
146
|
+
detail = toolInput.url.slice(0, 30);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
// Shorten long details
|
|
150
|
+
if (detail.length > 40) {
|
|
151
|
+
detail = '...' + detail.slice(-37);
|
|
152
|
+
}
|
|
153
|
+
switch (toolName.toLowerCase()) {
|
|
154
|
+
case 'read':
|
|
155
|
+
return detail ? `Reading ${detail}` : 'Reading file';
|
|
156
|
+
case 'write':
|
|
157
|
+
return detail ? `Writing ${detail}` : 'Writing file';
|
|
158
|
+
case 'edit':
|
|
159
|
+
return detail ? `Editing ${detail}` : 'Editing file';
|
|
160
|
+
case 'glob':
|
|
161
|
+
return detail ? `Finding ${detail}` : 'Searching files';
|
|
162
|
+
case 'grep':
|
|
163
|
+
return detail ? `Searching: ${detail}` : 'Searching in files';
|
|
164
|
+
case 'bash':
|
|
165
|
+
return detail ? `Running ${detail}` : 'Running command';
|
|
166
|
+
case 'webfetch':
|
|
167
|
+
return 'Fetching URL';
|
|
168
|
+
case 'websearch':
|
|
169
|
+
return detail ? `Searching: ${detail}` : 'Searching web';
|
|
170
|
+
case 'task':
|
|
171
|
+
return 'Running sub-task';
|
|
172
|
+
default:
|
|
173
|
+
return `Using ${toolName}`;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
export async function invokeClaudeAutomated(prompt, workingDirectory, options = {}) {
|
|
177
|
+
const { verbose = false, onProgress } = options;
|
|
178
|
+
const startTime = Date.now();
|
|
179
|
+
// Ensure workspace settings exist
|
|
180
|
+
await ensureWorkspaceSettings(workingDirectory);
|
|
181
|
+
return new Promise((resolve) => {
|
|
182
|
+
// Write prompt to temp file to avoid command line length limits and quoting issues
|
|
183
|
+
const tempDir = os.tmpdir();
|
|
184
|
+
const promptFile = path.join(tempDir, `devloop-prompt-${Date.now()}.txt`);
|
|
185
|
+
fsSync.writeFileSync(promptFile, prompt, 'utf-8');
|
|
186
|
+
if (verbose) {
|
|
187
|
+
console.log(` Executing: claude -p [prompt from file] --dangerously-skip-permissions --output-format stream-json --add-dir "${workingDirectory}"`);
|
|
188
|
+
}
|
|
189
|
+
// Use stream-json format for real-time progress events
|
|
190
|
+
// Note: stream-json requires --verbose when using -p
|
|
191
|
+
const args = [
|
|
192
|
+
'-p', '-',
|
|
193
|
+
'--dangerously-skip-permissions',
|
|
194
|
+
'--output-format', 'stream-json',
|
|
195
|
+
'--verbose',
|
|
196
|
+
'--add-dir', workingDirectory
|
|
197
|
+
];
|
|
198
|
+
const child = spawn('claude', args, {
|
|
199
|
+
cwd: workingDirectory,
|
|
200
|
+
shell: true,
|
|
201
|
+
env: { ...process.env },
|
|
202
|
+
stdio: ['pipe', 'pipe', 'pipe']
|
|
203
|
+
});
|
|
204
|
+
// Pipe the prompt file content to stdin
|
|
205
|
+
const promptContent = fsSync.readFileSync(promptFile, 'utf-8');
|
|
206
|
+
child.stdin?.write(promptContent);
|
|
207
|
+
child.stdin?.end();
|
|
208
|
+
let stderr = '';
|
|
209
|
+
let resultText = '';
|
|
210
|
+
let tokenUsage;
|
|
211
|
+
let isError = false;
|
|
212
|
+
let lineBuffer = '';
|
|
213
|
+
// Parse streaming JSON events from stdout
|
|
214
|
+
child.stdout?.on('data', (data) => {
|
|
215
|
+
const chunk = data.toString();
|
|
216
|
+
if (verbose) {
|
|
217
|
+
process.stdout.write(chunk);
|
|
218
|
+
}
|
|
219
|
+
// Buffer lines (events are newline-delimited JSON)
|
|
220
|
+
lineBuffer += chunk;
|
|
221
|
+
const lines = lineBuffer.split('\n');
|
|
222
|
+
lineBuffer = lines.pop() || ''; // Keep incomplete line in buffer
|
|
223
|
+
for (const line of lines) {
|
|
224
|
+
if (!line.trim())
|
|
225
|
+
continue;
|
|
226
|
+
try {
|
|
227
|
+
const event = JSON.parse(line);
|
|
228
|
+
// Handle different event types
|
|
229
|
+
if (event.type === 'content_block_start') {
|
|
230
|
+
// Tool usage starting
|
|
231
|
+
const block = event.content_block;
|
|
232
|
+
if (block?.type === 'tool_use' && block?.name && onProgress) {
|
|
233
|
+
const activity = formatToolActivity(block.name, block.input);
|
|
234
|
+
onProgress(activity);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
else if (event.type === 'content_block_delta') {
|
|
238
|
+
// Tool input being streamed (partial)
|
|
239
|
+
const delta = event.delta;
|
|
240
|
+
if (delta?.type === 'input_json_delta' && onProgress) {
|
|
241
|
+
// Could parse partial input here if needed
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
else if (event.type === 'result') {
|
|
245
|
+
// Final result with token usage
|
|
246
|
+
resultText = event.result || '';
|
|
247
|
+
isError = event.is_error === true;
|
|
248
|
+
tokenUsage = parseTokenUsage(event);
|
|
249
|
+
if (verbose && tokenUsage) {
|
|
250
|
+
console.log(` Token usage: ${tokenUsage.totalTokens} total (${tokenUsage.inputTokens} in, ${tokenUsage.outputTokens} out)`);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
else if (event.type === 'assistant' && event.message?.content) {
|
|
254
|
+
// Assistant message with tool uses
|
|
255
|
+
for (const block of event.message.content) {
|
|
256
|
+
if (block.type === 'tool_use' && block.name && onProgress) {
|
|
257
|
+
const activity = formatToolActivity(block.name, block.input);
|
|
258
|
+
onProgress(activity);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
catch {
|
|
264
|
+
// Not valid JSON, ignore
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
});
|
|
268
|
+
// Collect stderr for error messages
|
|
269
|
+
child.stderr?.on('data', (data) => {
|
|
270
|
+
const chunk = data.toString();
|
|
271
|
+
stderr += chunk;
|
|
272
|
+
if (verbose) {
|
|
273
|
+
process.stderr.write(chunk);
|
|
274
|
+
}
|
|
275
|
+
});
|
|
276
|
+
child.on('close', (code) => {
|
|
277
|
+
// Clean up temp file
|
|
278
|
+
try {
|
|
279
|
+
fsSync.unlinkSync(promptFile);
|
|
280
|
+
}
|
|
281
|
+
catch {
|
|
282
|
+
// Ignore cleanup errors
|
|
283
|
+
}
|
|
284
|
+
// Process any remaining buffered line
|
|
285
|
+
if (lineBuffer.trim()) {
|
|
286
|
+
try {
|
|
287
|
+
const event = JSON.parse(lineBuffer);
|
|
288
|
+
if (event.type === 'result') {
|
|
289
|
+
resultText = event.result || resultText;
|
|
290
|
+
isError = event.is_error === true;
|
|
291
|
+
tokenUsage = parseTokenUsage(event) || tokenUsage;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
catch {
|
|
295
|
+
// Ignore
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
const duration = Date.now() - startTime;
|
|
299
|
+
const hasError = code !== 0 || isError;
|
|
300
|
+
// Combine all available error information
|
|
301
|
+
let errorMessage;
|
|
302
|
+
if (hasError) {
|
|
303
|
+
const parts = [];
|
|
304
|
+
if (stderr)
|
|
305
|
+
parts.push(stderr.trim());
|
|
306
|
+
if (resultText && resultText.includes('API Error')) {
|
|
307
|
+
parts.push(resultText);
|
|
308
|
+
}
|
|
309
|
+
errorMessage = parts.join('\n') || 'Unknown error';
|
|
310
|
+
}
|
|
311
|
+
const errorType = hasError ? classifyError(errorMessage || stderr || '', null) : undefined;
|
|
312
|
+
resolve({
|
|
313
|
+
success: !hasError,
|
|
314
|
+
output: resultText,
|
|
315
|
+
error: errorMessage,
|
|
316
|
+
errorType,
|
|
317
|
+
duration,
|
|
318
|
+
tokenUsage
|
|
319
|
+
});
|
|
320
|
+
});
|
|
321
|
+
child.on('error', (err) => {
|
|
322
|
+
// Clean up temp file
|
|
323
|
+
try {
|
|
324
|
+
fsSync.unlinkSync(promptFile);
|
|
325
|
+
}
|
|
326
|
+
catch {
|
|
327
|
+
// Ignore cleanup errors
|
|
328
|
+
}
|
|
329
|
+
resolve({
|
|
330
|
+
success: false,
|
|
331
|
+
output: '',
|
|
332
|
+
error: err.message,
|
|
333
|
+
errorType: classifyError(err.message, null),
|
|
334
|
+
duration: Date.now() - startTime,
|
|
335
|
+
tokenUsage: undefined
|
|
336
|
+
});
|
|
337
|
+
});
|
|
338
|
+
});
|
|
339
|
+
}
|
|
340
|
+
export function spawnClaudeInteractive(workingDirectory, sessionId) {
|
|
341
|
+
const args = [];
|
|
342
|
+
if (sessionId) {
|
|
343
|
+
args.push('--resume', sessionId);
|
|
344
|
+
}
|
|
345
|
+
// Spawn Claude in fully interactive mode (no -p flag)
|
|
346
|
+
const child = spawn('claude', args, {
|
|
347
|
+
cwd: workingDirectory,
|
|
348
|
+
shell: true,
|
|
349
|
+
stdio: 'inherit',
|
|
350
|
+
env: { ...process.env }
|
|
351
|
+
});
|
|
352
|
+
return child;
|
|
353
|
+
}
|
|
354
|
+
export function buildTaskPrompt(task, requirementsPath, progressPath, workspacePath) {
|
|
355
|
+
return `You are working on an automated development task. Follow these instructions carefully:
|
|
356
|
+
|
|
357
|
+
WORKSPACE RESTRICTION:
|
|
358
|
+
You are ONLY allowed to work within: ${workspacePath}
|
|
359
|
+
- Do NOT read, write, or modify any files outside this directory
|
|
360
|
+
- Do NOT run commands that affect files outside this directory
|
|
361
|
+
- All file paths must be within the workspace
|
|
362
|
+
|
|
363
|
+
1. READ the requirements file at: ${requirementsPath}
|
|
364
|
+
2. READ the progress file at: ${progressPath} (if it exists)
|
|
365
|
+
|
|
366
|
+
YOUR CURRENT TASK:
|
|
367
|
+
- Task ID: ${task.id}
|
|
368
|
+
- Title: ${task.title}
|
|
369
|
+
- Description: ${task.description}
|
|
370
|
+
- Priority: ${task.priority}
|
|
371
|
+
|
|
372
|
+
INSTRUCTIONS:
|
|
373
|
+
1. Complete the task described above
|
|
374
|
+
2. Make all necessary code changes WITHIN THE WORKSPACE ONLY
|
|
375
|
+
3. After completing the task, update the requirements file to mark task ${task.id} as "done" by changing its Status line from "pending" to "done"
|
|
376
|
+
4. Do NOT work on any other tasks
|
|
377
|
+
|
|
378
|
+
IMPORTANT:
|
|
379
|
+
- Focus only on this specific task
|
|
380
|
+
- Make clean, well-documented changes
|
|
381
|
+
- If you encounter blockers, document them but still attempt the task
|
|
382
|
+
- Update the task status to "done" when complete
|
|
383
|
+
- NEVER modify files outside ${workspacePath}
|
|
384
|
+
|
|
385
|
+
Begin working on ${task.id} now.`;
|
|
386
|
+
}
|
|
387
|
+
export async function checkClaudeInstalled() {
|
|
388
|
+
return new Promise((resolve) => {
|
|
389
|
+
const child = spawn('claude', ['--version'], {
|
|
390
|
+
shell: true,
|
|
391
|
+
stdio: 'pipe'
|
|
392
|
+
});
|
|
393
|
+
child.on('close', (code) => {
|
|
394
|
+
resolve(code === 0);
|
|
395
|
+
});
|
|
396
|
+
child.on('error', () => {
|
|
397
|
+
resolve(false);
|
|
398
|
+
});
|
|
399
|
+
});
|
|
400
|
+
}
|
|
401
|
+
//# sourceMappingURL=claude.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude.js","sourceRoot":"","sources":["../../src/core/claude.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export interface CommitFormatDetection {
|
|
2
|
+
detected: boolean;
|
|
3
|
+
format?: string;
|
|
4
|
+
formatFailed?: string;
|
|
5
|
+
source?: string;
|
|
6
|
+
}
|
|
7
|
+
export interface CommitVariables {
|
|
8
|
+
feature?: string;
|
|
9
|
+
iteration: number;
|
|
10
|
+
status: 'Complete' | 'Attempted';
|
|
11
|
+
taskId: string;
|
|
12
|
+
title: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Detects commit message format from git hooks and config files
|
|
16
|
+
*/
|
|
17
|
+
export declare function detectCommitFormat(workspace: string): Promise<CommitFormatDetection>;
|
|
18
|
+
/**
|
|
19
|
+
* Applies commit message template with variable substitution
|
|
20
|
+
*/
|
|
21
|
+
export declare function formatCommitMessage(template: string, variables: CommitVariables): string;
|
|
22
|
+
//# sourceMappingURL=commit-format.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commit-format.d.ts","sourceRoot":"","sources":["../../src/core/commit-format.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,UAAU,GAAG,WAAW,CAAC;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAmC1F;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,eAAe,GAAG,MAAM,CAQxF"}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import * as fs from 'fs/promises';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
/**
|
|
4
|
+
* Detects commit message format from git hooks and config files
|
|
5
|
+
*/
|
|
6
|
+
export async function detectCommitFormat(workspace) {
|
|
7
|
+
// Check commitlint config
|
|
8
|
+
const commitlintFormat = await checkCommitlint(workspace);
|
|
9
|
+
if (commitlintFormat) {
|
|
10
|
+
return {
|
|
11
|
+
detected: true,
|
|
12
|
+
format: commitlintFormat.format,
|
|
13
|
+
formatFailed: commitlintFormat.formatFailed,
|
|
14
|
+
source: 'commitlint'
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
// Check git hooks
|
|
18
|
+
const gitHookFormat = await checkGitHooks(workspace);
|
|
19
|
+
if (gitHookFormat) {
|
|
20
|
+
return {
|
|
21
|
+
detected: true,
|
|
22
|
+
format: gitHookFormat.format,
|
|
23
|
+
formatFailed: gitHookFormat.formatFailed,
|
|
24
|
+
source: 'git hook'
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
// Check husky
|
|
28
|
+
const huskyFormat = await checkHusky(workspace);
|
|
29
|
+
if (huskyFormat) {
|
|
30
|
+
return {
|
|
31
|
+
detected: true,
|
|
32
|
+
format: huskyFormat.format,
|
|
33
|
+
formatFailed: huskyFormat.formatFailed,
|
|
34
|
+
source: 'husky'
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
return { detected: false };
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Applies commit message template with variable substitution
|
|
41
|
+
*/
|
|
42
|
+
export function formatCommitMessage(template, variables) {
|
|
43
|
+
return template
|
|
44
|
+
.replace(/\{feature\}/g, variables.feature || '')
|
|
45
|
+
.replace(/\{iteration\}/g, String(variables.iteration))
|
|
46
|
+
.replace(/\{status\}/g, variables.status)
|
|
47
|
+
.replace(/\{taskId\}/g, variables.taskId)
|
|
48
|
+
.replace(/\{title\}/g, variables.title)
|
|
49
|
+
.trim();
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Check commitlint configuration files
|
|
53
|
+
*/
|
|
54
|
+
async function checkCommitlint(workspace) {
|
|
55
|
+
const configFiles = [
|
|
56
|
+
'.commitlintrc',
|
|
57
|
+
'.commitlintrc.json',
|
|
58
|
+
'.commitlintrc.js',
|
|
59
|
+
'commitlint.config.js'
|
|
60
|
+
];
|
|
61
|
+
for (const configFile of configFiles) {
|
|
62
|
+
const configPath = path.join(workspace, configFile);
|
|
63
|
+
try {
|
|
64
|
+
await fs.access(configPath);
|
|
65
|
+
// If commitlint config exists, assume conventional commits
|
|
66
|
+
// Suggest format based on conventional commits pattern
|
|
67
|
+
return {
|
|
68
|
+
format: 'feat({feature}): {title}',
|
|
69
|
+
formatFailed: 'wip({feature}): {title}'
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
// File doesn't exist, try next
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Check git hooks for commit message patterns
|
|
80
|
+
*/
|
|
81
|
+
async function checkGitHooks(workspace) {
|
|
82
|
+
const hookPaths = [
|
|
83
|
+
path.join(workspace, '.git', 'hooks', 'commit-msg'),
|
|
84
|
+
path.join(workspace, '.git', 'hooks', 'pre-commit')
|
|
85
|
+
];
|
|
86
|
+
for (const hookPath of hookPaths) {
|
|
87
|
+
try {
|
|
88
|
+
const content = await fs.readFile(hookPath, 'utf-8');
|
|
89
|
+
// Check for conventional commits pattern
|
|
90
|
+
if (/\^?\(feat\|fix\|docs\|chore\)/i.test(content)) {
|
|
91
|
+
return {
|
|
92
|
+
format: 'feat({feature}): {title}',
|
|
93
|
+
formatFailed: 'wip({feature}): {title}'
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
// Check for Jira-style pattern
|
|
97
|
+
if (/\[A-Z\]\+-\\d\+/i.test(content) || /\^?\[A-Z\]\+-\\d\+/i.test(content)) {
|
|
98
|
+
return {
|
|
99
|
+
format: '[{taskId}] {status} - {title}',
|
|
100
|
+
formatFailed: '[{taskId}] {status} - {title}'
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
// File doesn't exist or can't be read, try next
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Check husky configuration
|
|
112
|
+
*/
|
|
113
|
+
async function checkHusky(workspace) {
|
|
114
|
+
// Check .husky/commit-msg
|
|
115
|
+
const huskyHookPath = path.join(workspace, '.husky', 'commit-msg');
|
|
116
|
+
try {
|
|
117
|
+
const content = await fs.readFile(huskyHookPath, 'utf-8');
|
|
118
|
+
// If it mentions commitlint, use conventional commits
|
|
119
|
+
if (/commitlint/.test(content)) {
|
|
120
|
+
return {
|
|
121
|
+
format: 'feat({feature}): {title}',
|
|
122
|
+
formatFailed: 'wip({feature}): {title}'
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
// File doesn't exist
|
|
128
|
+
}
|
|
129
|
+
// Check package.json for husky config
|
|
130
|
+
try {
|
|
131
|
+
const packageJsonPath = path.join(workspace, 'package.json');
|
|
132
|
+
const packageJson = JSON.parse(await fs.readFile(packageJsonPath, 'utf-8'));
|
|
133
|
+
if (packageJson.husky?.hooks?.['commit-msg']) {
|
|
134
|
+
const hook = packageJson.husky.hooks['commit-msg'];
|
|
135
|
+
if (/commitlint/.test(hook)) {
|
|
136
|
+
return {
|
|
137
|
+
format: 'feat({feature}): {title}',
|
|
138
|
+
formatFailed: 'wip({feature}): {title}'
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
catch {
|
|
144
|
+
// File doesn't exist or invalid JSON
|
|
145
|
+
}
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
//# sourceMappingURL=commit-format.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commit-format.js","sourceRoot":"","sources":["../../src/core/commit-format.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { GlobalConfig } from '../types/index.js';
|
|
2
|
+
export declare function ensureConfigDir(): Promise<void>;
|
|
3
|
+
export declare function readGlobalConfig(): Promise<GlobalConfig>;
|
|
4
|
+
export declare function writeGlobalConfig(config: GlobalConfig): Promise<void>;
|
|
5
|
+
export declare function getDefaultWorkspace(): Promise<string | null>;
|
|
6
|
+
export declare function setDefaultWorkspace(workspacePath: string): Promise<void>;
|
|
7
|
+
export declare function resolveWorkspace(cliWorkspace?: string): Promise<string>;
|
|
8
|
+
export declare function getRequirementsPath(workspace: string): string;
|
|
9
|
+
export declare function getProgressPath(workspace: string): string;
|
|
10
|
+
export declare function getSessionPath(workspace: string): string;
|
|
11
|
+
/**
|
|
12
|
+
* Validates a feature name to ensure it's a safe filename
|
|
13
|
+
* @throws Error if feature name is invalid
|
|
14
|
+
*/
|
|
15
|
+
export declare function validateFeatureName(feature: string): void;
|
|
16
|
+
/**
|
|
17
|
+
* Resolves feature input to normalized paths
|
|
18
|
+
* Handles both short form (auth) and explicit paths (requirements/auth.md)
|
|
19
|
+
*/
|
|
20
|
+
export declare function resolveFeaturePath(workspace: string, featureInput: string): {
|
|
21
|
+
featureName: string;
|
|
22
|
+
requirementsPath: string;
|
|
23
|
+
progressPath: string;
|
|
24
|
+
};
|
|
25
|
+
export declare function getFeatureRequirementsPath(workspace: string, feature: string): string;
|
|
26
|
+
export declare function getFeatureProgressPath(workspace: string, feature: string): string;
|
|
27
|
+
export declare function getWorkspaceConfigPath(workspace: string): string;
|
|
28
|
+
export declare function readWorkspaceConfig(workspace: string): Promise<import('../types/feature.js').WorkspaceConfig>;
|
|
29
|
+
export declare function writeWorkspaceConfig(workspace: string, config: import('../types/feature.js').WorkspaceConfig): Promise<void>;
|
|
30
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/core/config.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAUjD,wBAAsB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CAMrD;AAED,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,YAAY,CAAC,CAO9D;AAED,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAG3E;AAED,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAGlE;AAED,wBAAsB,mBAAmB,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAI9E;AAED,wBAAsB,gBAAgB,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAY7E;AAED,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAE7D;AAED,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAExD;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAczD;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG;IAC3E,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,MAAM,CAAC;IACzB,YAAY,EAAE,MAAM,CAAC;CACtB,CA6BA;AAED,wBAAgB,0BAA0B,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAErF;AAED,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAEjF;AAED,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEhE;AAED,wBAAsB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,qBAAqB,EAAE,eAAe,CAAC,CAQnH;AAED,wBAAsB,oBAAoB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,qBAAqB,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAQlI"}
|