@ctrl-spc/cli 1.1.9 → 1.1.10

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.
Files changed (2) hide show
  1. package/dist/spawner.js +26 -12
  2. package/package.json +1 -1
package/dist/spawner.js CHANGED
@@ -6,26 +6,31 @@ function isRemote(agentType) {
6
6
  return agentType === 'claude-code' || agentType === 'codex';
7
7
  }
8
8
  export function makeSpawner(deps) {
9
- const timeoutMs = deps.readinessTimeoutMs ?? 10_000;
9
+ const timeoutMs = deps.readinessTimeoutMs ?? 45_000;
10
10
  const backoffMs = deps.retryBackoffMs ?? 30_000;
11
11
  const lastAttempt = new Map(); // requestId -> timestamp; in-memory back-off
12
12
  async function awaitReadiness(handle) {
13
13
  return new Promise((resolve) => {
14
14
  let buf = '';
15
+ let errBuf = '';
15
16
  let done = false;
16
- const finish = (ok) => { if (!done) {
17
- done = true;
18
- clearTimeout(timer);
19
- resolve(ok);
20
- } };
17
+ const finish = (ready) => {
18
+ if (!done) {
19
+ done = true;
20
+ clearTimeout(timer);
21
+ resolve({ ready, stdout: buf, stderr: errBuf });
22
+ }
23
+ };
21
24
  const timer = setTimeout(() => finish(false), timeoutMs);
22
25
  handle.stdout.on('data', (chunk) => {
23
26
  buf += chunk.toString();
24
27
  if (buf.includes(READINESS_REPLY))
25
28
  finish(true);
26
29
  });
30
+ handle.stderr?.on('data', (chunk) => { errBuf += chunk.toString(); });
27
31
  handle.stdout.on('end', () => finish(buf.includes(READINESS_REPLY)));
28
32
  handle.stdout.on('error', () => finish(false));
33
+ handle.stderr?.on('error', () => { });
29
34
  });
30
35
  }
31
36
  async function resolveLocalPath(projectId) {
@@ -66,10 +71,10 @@ export function makeSpawner(deps) {
66
71
  }
67
72
  const { cmd, args } = assembleCommand(row);
68
73
  const handle = deps.spawnAgent(cmd, args, cwd);
69
- const ready = await awaitReadiness(handle);
70
- if (!ready) {
74
+ const result = await awaitReadiness(handle);
75
+ if (!result.ready) {
71
76
  handle.kill();
72
- deps.log(`Readiness gate failed for ${row.id}; will retry`);
77
+ deps.log(`Readiness gate failed for ${row.id}; will retry. stdout=${quoteSnippet(result.stdout)} stderr=${quoteSnippet(result.stderr)}`);
73
78
  return;
74
79
  }
75
80
  await fulfil(row, handle.pid);
@@ -97,9 +102,18 @@ export function makeSpawner(deps) {
97
102
  }
98
103
  // Real spawn handle backed by node:child_process, used by the daemon (not in unit tests).
99
104
  export function nodeSpawnAgent(cmd, args, cwd) {
100
- const child = spawn(cmd, args, { cwd, stdio: ['ignore', 'pipe', 'ignore'] });
105
+ const child = spawn(cmd, args, { cwd, stdio: ['ignore', 'pipe', 'pipe'] });
101
106
  const stdout = new PassThrough();
107
+ const stderr = new PassThrough();
102
108
  child.stdout?.pipe(stdout);
103
- child.on('error', (err) => stdout.destroy(err));
104
- return { pid: child.pid ?? -1, stdout, kill: () => child.kill() };
109
+ child.stderr?.pipe(stderr);
110
+ child.on('error', (err) => {
111
+ stdout.destroy(err);
112
+ stderr.end();
113
+ });
114
+ return { pid: child.pid ?? -1, stdout, stderr, kill: () => child.kill() };
115
+ }
116
+ function quoteSnippet(value) {
117
+ const trimmed = value.replace(/\s+/g, ' ').trim().slice(0, 500);
118
+ return JSON.stringify(trimmed);
105
119
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ctrl-spc/cli",
3
- "version": "1.1.9",
3
+ "version": "1.1.10",
4
4
  "description": "Control Space CLI - machine setup and background daemon",
5
5
  "type": "module",
6
6
  "files": [