create-claude-workspace 2.1.1 → 2.1.3

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.
@@ -7,11 +7,15 @@ export class OrchestratorClient {
7
7
  projectDir;
8
8
  logger;
9
9
  onMessage;
10
+ onSpawnStart;
11
+ onSpawnEnd;
10
12
  constructor(opts) {
11
13
  this.pool = opts.pool;
12
14
  this.projectDir = opts.projectDir;
13
15
  this.logger = opts.logger;
14
16
  this.onMessage = opts.onMessage;
17
+ this.onSpawnStart = opts.onSpawnStart;
18
+ this.onSpawnEnd = opts.onSpawnEnd;
15
19
  }
16
20
  /**
17
21
  * Ask orchestrator to route a task to the best agent.
@@ -88,7 +92,13 @@ export class OrchestratorClient {
88
92
  onMessage: this.onMessage,
89
93
  };
90
94
  this.logger.info('Consulting orchestrator AI...');
91
- return this.pool.spawn(slot.id, spawnOpts);
95
+ this.onSpawnStart?.('orchestrator-ai');
96
+ try {
97
+ return await this.pool.spawn(slot.id, spawnOpts);
98
+ }
99
+ finally {
100
+ this.onSpawnEnd?.();
101
+ }
92
102
  }
93
103
  }
94
104
  // ─── JSON parsing helpers ───
@@ -225,12 +225,16 @@ export async function runScheduler(opts) {
225
225
  });
226
226
  // SDK message handler — streams tool use, text, tokens to TUI
227
227
  const onMessage = (msg) => tui.handleMessage(msg);
228
+ const onSpawnStart = (name) => tui.pushAgent(name);
229
+ const onSpawnEnd = () => tui.popAgent();
228
230
  // Orchestrator client
229
231
  const orchestrator = new OrchestratorClient({
230
232
  pool,
231
233
  projectDir: opts.projectDir,
232
234
  logger,
233
235
  onMessage,
236
+ onSpawnStart,
237
+ onSpawnEnd,
234
238
  });
235
239
  // Signal handling
236
240
  let stopping = false;
@@ -259,6 +263,8 @@ export async function runScheduler(opts) {
259
263
  opts,
260
264
  logger,
261
265
  onMessage,
266
+ onSpawnStart,
267
+ onSpawnEnd,
262
268
  });
263
269
  if (!workDone) {
264
270
  // No work → idle polling
@@ -20,7 +20,7 @@ const MAX_CI_FIXES = 3;
20
20
  * Returns true if work was done, false if idle.
21
21
  */
22
22
  export async function runIteration(deps) {
23
- const { pool, orchestrator, state, opts, logger, onMessage } = deps;
23
+ const { pool, orchestrator, state, opts, logger, onMessage, onSpawnStart, onSpawnEnd } = deps;
24
24
  const projectDir = opts.projectDir;
25
25
  // Rotate log if needed
26
26
  rotateLog(projectDir);
@@ -164,7 +164,7 @@ export async function runIteration(deps) {
164
164
  }
165
165
  // ─── Pipeline execution ───
166
166
  async function runTaskPipeline(task, workerId, agents, deps) {
167
- const { pool, orchestrator, state, opts, logger, onMessage } = deps;
167
+ const { pool, orchestrator, state, opts, logger, onMessage, onSpawnStart, onSpawnEnd } = deps;
168
168
  const projectDir = opts.projectDir;
169
169
  // Create worktree
170
170
  const slug = taskToSlug(task);
@@ -204,7 +204,7 @@ async function runTaskPipeline(task, workerId, agents, deps) {
204
204
  cwd: worktreePath,
205
205
  prompt: buildPlanPrompt({ task, worktreePath, projectDir }),
206
206
  model: getAgentModel(pipeline.assignedAgent, agents),
207
- }, state, task.id, logger, onMessage);
207
+ }, state, task.id, logger, onMessage, onSpawnStart, onSpawnEnd);
208
208
  if (!planResult.success) {
209
209
  logger.error(`[${task.id}] Planning failed: ${planResult.error}`);
210
210
  return false;
@@ -228,7 +228,7 @@ async function runTaskPipeline(task, workerId, agents, deps) {
228
228
  apiContract: pipeline.apiContract ?? undefined,
229
229
  }),
230
230
  model: getAgentModel(pipeline.assignedAgent, agents),
231
- }, state, task.id, logger, onMessage);
231
+ }, state, task.id, logger, onMessage, onSpawnStart, onSpawnEnd);
232
232
  if (!implResult.success) {
233
233
  logger.error(`[${task.id}] Implementation failed: ${implResult.error}`);
234
234
  return false;
@@ -246,7 +246,7 @@ async function runTaskPipeline(task, workerId, agents, deps) {
246
246
  testingSection: pipeline.testingSection ?? undefined,
247
247
  }),
248
248
  model: getAgentModel(testRouting.agent, agents),
249
- }, state, task.id, logger, onMessage);
249
+ }, state, task.id, logger, onMessage, onSpawnStart, onSpawnEnd);
250
250
  if (!testResult.success) {
251
251
  pipeline.buildFixes++;
252
252
  if (pipeline.buildFixes >= MAX_BUILD_FIXES) {
@@ -274,7 +274,7 @@ async function runTaskPipeline(task, workerId, agents, deps) {
274
274
  testingSection: pipeline.testingSection ?? undefined,
275
275
  }),
276
276
  model: getAgentModel(reviewRouting.agent, agents),
277
- }, state, task.id, logger, onMessage);
277
+ }, state, task.id, logger, onMessage, onSpawnStart, onSpawnEnd);
278
278
  if (reviewResult.output.includes('**PASS**') || reviewResult.output.includes('PASS')) {
279
279
  reviewPassed = true;
280
280
  }
@@ -296,7 +296,7 @@ async function runTaskPipeline(task, workerId, agents, deps) {
296
296
  reviewFindings: pipeline.reviewFindings,
297
297
  }),
298
298
  model: getAgentModel(pipeline.assignedAgent, agents),
299
- }, state, task.id, logger, onMessage);
299
+ }, state, task.id, logger, onMessage, onSpawnStart, onSpawnEnd);
300
300
  pipeline.step = 're-review';
301
301
  }
302
302
  }
@@ -360,7 +360,9 @@ async function runTaskPipeline(task, workerId, agents, deps) {
360
360
  }
361
361
  }
362
362
  // ─── Helpers ───
363
- async function spawnAgent(pool, slotId, opts, state, taskId, logger, onMessage) {
363
+ async function spawnAgent(pool, slotId, opts, state, taskId, logger, onMessage, onSpawnStart, onSpawnEnd) {
364
+ const agentName = opts.agent ?? 'claude';
365
+ onSpawnStart?.(agentName);
364
366
  // Check for existing session (resume on crash)
365
367
  const existingSession = getSession(state, taskId);
366
368
  const result = await pool.spawn(slotId, {
@@ -368,6 +370,7 @@ async function spawnAgent(pool, slotId, opts, state, taskId, logger, onMessage)
368
370
  resume: existingSession ?? undefined,
369
371
  onMessage,
370
372
  });
373
+ onSpawnEnd?.();
371
374
  // Record session for crash recovery
372
375
  if (result.sessionId) {
373
376
  recordSession(state, taskId, result.sessionId);
@@ -4,7 +4,7 @@ export const SCHEDULER_DEFAULTS = {
4
4
  concurrency: 1,
5
5
  maxIterations: 50,
6
6
  maxTurns: 50,
7
- skipPermissions: false,
7
+ skipPermissions: true,
8
8
  resume: false,
9
9
  resumeSession: null,
10
10
  logFile: '.claude/scheduler/scheduler.log',
@@ -466,6 +466,9 @@ export class TUI {
466
466
  if (msg.session_id)
467
467
  this.fileOnly(`SESSION: ${msg.session_id}`);
468
468
  }
469
+ pushAgent(name) { this.state.agents.push(name); }
470
+ popAgent() { if (this.state.agents.length > 1)
471
+ this.state.agents.pop(); }
469
472
  resetAgentStack() { this.state.agents = this.topAgent ? [this.topAgent] : []; }
470
473
  getSessionId(msg) { return msg.session_id ?? null; }
471
474
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-claude-workspace",
3
- "version": "2.1.1",
3
+ "version": "2.1.3",
4
4
  "author": "",
5
5
  "repository": {
6
6
  "type": "git",