create-claude-workspace 1.1.17 → 1.1.19
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.
|
@@ -233,43 +233,96 @@ process.on('SIGTERM', () => {
|
|
|
233
233
|
|
|
234
234
|
// ─── Stream event display ───
|
|
235
235
|
|
|
236
|
+
/** Track last displayed text to avoid re-printing full content on partial message updates */
|
|
237
|
+
let lastAssistantText = '';
|
|
238
|
+
|
|
236
239
|
function formatStreamEvent(event) {
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
240
|
+
const type = event.type;
|
|
241
|
+
|
|
242
|
+
// System init — silent (session_id extracted elsewhere)
|
|
243
|
+
if (type === 'system') return null;
|
|
244
|
+
|
|
245
|
+
// Ping — silent
|
|
246
|
+
if (type === 'ping') return null;
|
|
247
|
+
|
|
248
|
+
// Rate limit event
|
|
249
|
+
if (type === 'rate_limit_event') {
|
|
250
|
+
const info = event.rate_limit_info ?? event;
|
|
251
|
+
const resets = info.resets_at ?? info.retry_after ?? '';
|
|
252
|
+
return `${C.yellow}⏳ Rate limited${resets ? ` (resets: ${resets})` : ''}${C.reset}\n`;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Error event
|
|
256
|
+
if (type === 'error') {
|
|
257
|
+
const msg = event.error?.message ?? event.message ?? JSON.stringify(event);
|
|
258
|
+
return `${C.red}✗ Error: ${msg}${C.reset}\n`;
|
|
245
259
|
}
|
|
246
260
|
|
|
247
|
-
// Assistant message
|
|
248
|
-
if (
|
|
261
|
+
// Assistant message — content is always an array of content blocks
|
|
262
|
+
if (type === 'assistant') {
|
|
249
263
|
const msg = event.message;
|
|
250
264
|
if (!msg) return null;
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
const
|
|
256
|
-
|
|
265
|
+
const content = msg.content;
|
|
266
|
+
|
|
267
|
+
// Content blocks array (the standard format)
|
|
268
|
+
if (Array.isArray(content)) {
|
|
269
|
+
const parts = [];
|
|
270
|
+
for (const block of content) {
|
|
271
|
+
if (block.type === 'tool_use') {
|
|
272
|
+
const input = block.input ?? {};
|
|
273
|
+
const detail = input.command ?? input.file_path ?? input.pattern ?? input.query ?? '';
|
|
274
|
+
const short = typeof detail === 'string' ? detail.slice(0, 120) : '';
|
|
275
|
+
parts.push(`${C.cyan}▶ ${block.name ?? 'tool'}${C.reset}${short ? ` ${C.dim}${short}${C.reset}` : ''}`);
|
|
276
|
+
} else if (block.type === 'text' && block.text) {
|
|
277
|
+
// With --include-partial-messages, we get the full accumulated text each time.
|
|
278
|
+
// Only print the NEW portion to avoid re-printing everything.
|
|
279
|
+
let text = block.text;
|
|
280
|
+
if (text.startsWith(lastAssistantText) && lastAssistantText.length > 0) {
|
|
281
|
+
text = text.slice(lastAssistantText.length);
|
|
282
|
+
}
|
|
283
|
+
if (text) {
|
|
284
|
+
lastAssistantText = block.text;
|
|
285
|
+
parts.push(text);
|
|
286
|
+
}
|
|
287
|
+
} else if (block.type === 'thinking' && block.thinking) {
|
|
288
|
+
// Thinking blocks — show abbreviated
|
|
289
|
+
const preview = block.thinking.slice(0, 200).replace(/\n/g, ' ');
|
|
290
|
+
parts.push(`${C.dim}💭 ${preview}${preview.length < block.thinking.length ? '...' : ''}${C.reset}`);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
if (parts.length) return parts.join('\n') + '\n';
|
|
294
|
+
return null;
|
|
257
295
|
}
|
|
258
|
-
|
|
259
|
-
|
|
296
|
+
|
|
297
|
+
// Fallback: string content (shouldn't happen with stream-json, but just in case)
|
|
298
|
+
if (typeof content === 'string' && content) {
|
|
299
|
+
return `${content}\n`;
|
|
260
300
|
}
|
|
261
301
|
return null;
|
|
262
302
|
}
|
|
263
303
|
|
|
264
|
-
//
|
|
265
|
-
if (
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
const content =
|
|
269
|
-
|
|
270
|
-
|
|
304
|
+
// User message — contains tool results
|
|
305
|
+
if (type === 'user') {
|
|
306
|
+
// Reset text tracking on new turn
|
|
307
|
+
lastAssistantText = '';
|
|
308
|
+
const content = event.message?.content;
|
|
309
|
+
if (!Array.isArray(content)) return null;
|
|
310
|
+
for (const block of content) {
|
|
311
|
+
if (block.type === 'tool_result') {
|
|
312
|
+
const isErr = block.is_error;
|
|
313
|
+
const icon = isErr ? `${C.red}✗` : `${C.green}✓`;
|
|
314
|
+
const text = typeof block.content === 'string' ? block.content : '';
|
|
315
|
+
const preview = text.slice(0, 150).replace(/\n/g, ' ');
|
|
316
|
+
return `${icon} ${C.dim}${preview}${C.reset}\n`;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
return null;
|
|
271
320
|
}
|
|
272
321
|
|
|
322
|
+
// Final result — silent (parsed separately for structured output)
|
|
323
|
+
if (type === 'result') return null;
|
|
324
|
+
|
|
325
|
+
// Unknown event type — show for debugging
|
|
273
326
|
return null;
|
|
274
327
|
}
|
|
275
328
|
|
|
@@ -286,6 +339,7 @@ function runClaude(projectDir, opts, { resumeSessionId = null, resumePrompt = nu
|
|
|
286
339
|
baseFlags.push('-p');
|
|
287
340
|
baseFlags.push('--output-format', 'stream-json');
|
|
288
341
|
baseFlags.push('--verbose');
|
|
342
|
+
baseFlags.push('--include-partial-messages');
|
|
289
343
|
baseFlags.push('--max-turns', String(opts.maxTurns));
|
|
290
344
|
baseFlags.push('--json-schema', RESULT_SCHEMA);
|
|
291
345
|
|
|
@@ -351,6 +405,9 @@ function runClaude(projectDir, opts, { resumeSessionId = null, resumePrompt = nu
|
|
|
351
405
|
}
|
|
352
406
|
|
|
353
407
|
// Rate limit detection from stream events
|
|
408
|
+
if (event.type === 'rate_limit_event') {
|
|
409
|
+
isRateLimit = true;
|
|
410
|
+
}
|
|
354
411
|
if (event.type === 'error') {
|
|
355
412
|
const msg = (event.error?.message ?? event.message ?? '').toLowerCase();
|
|
356
413
|
if (msg.includes('rate limit') || msg.includes('rate_limit') || msg.includes('overloaded')) {
|
|
@@ -360,7 +417,9 @@ function runClaude(projectDir, opts, { resumeSessionId = null, resumePrompt = nu
|
|
|
360
417
|
|
|
361
418
|
// Display formatted event
|
|
362
419
|
const formatted = formatStreamEvent(event);
|
|
363
|
-
if (formatted)
|
|
420
|
+
if (formatted) {
|
|
421
|
+
process.stdout.write(formatted);
|
|
422
|
+
}
|
|
364
423
|
} catch {
|
|
365
424
|
// Non-JSON line — display as-is
|
|
366
425
|
process.stdout.write(line + '\n');
|
|
@@ -66,16 +66,23 @@ function toDockerPath(p) {
|
|
|
66
66
|
* Does NOT use shell: true — on Windows, cmd.exe splits arguments after
|
|
67
67
|
* '-c' into separate words, breaking 'bash -c "node ..."' commands.
|
|
68
68
|
* Without shell, Node.js passes each array element as a distinct argv entry.
|
|
69
|
+
*
|
|
70
|
+
* cwd is set to DOCKER_DIR so Docker Compose finds docker-compose.yml
|
|
71
|
+
* in its default location. Volume/build paths in the compose file are
|
|
72
|
+
* resolved relative to the compose file's directory, not cwd.
|
|
69
73
|
*/
|
|
70
74
|
function compose(args, opts = {}) {
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
cwd: PROJECT_DIR,
|
|
75
|
+
const files = [];
|
|
76
|
+
if (existsSync(AUTH_COMPOSE)) files.push('-f', 'docker-compose.yml', '-f', AUTH_COMPOSE);
|
|
77
|
+
const result = spawnSync('docker', ['compose', ...files, ...args], {
|
|
78
|
+
cwd: DOCKER_DIR,
|
|
76
79
|
stdio: opts.capture ? 'pipe' : 'inherit',
|
|
77
80
|
env: { ...process.env },
|
|
78
81
|
});
|
|
82
|
+
if (!opts.capture && result.status !== 0 && result.status !== null) {
|
|
83
|
+
error(`docker compose ${args[0]} failed (exit code ${result.status})`);
|
|
84
|
+
}
|
|
85
|
+
return result;
|
|
79
86
|
}
|
|
80
87
|
|
|
81
88
|
function cleanup() {
|
|
@@ -247,7 +254,11 @@ info('Docker is ready.');
|
|
|
247
254
|
|
|
248
255
|
// 2. Build
|
|
249
256
|
step('2/4 Building container image...');
|
|
250
|
-
compose(opts.rebuild ? ['build', '--no-cache'] : ['build', '-q']);
|
|
257
|
+
const buildResult = compose(opts.rebuild ? ['build', '--no-cache'] : ['build', '-q']);
|
|
258
|
+
if (buildResult.status !== 0) {
|
|
259
|
+
error('Docker image build failed. Fix the errors above and re-run.');
|
|
260
|
+
process.exit(1);
|
|
261
|
+
}
|
|
251
262
|
info('Image built.');
|
|
252
263
|
|
|
253
264
|
// 3. Auth
|