@ctrl-spc/cli 1.1.8 → 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.
package/dist/launchd.js CHANGED
@@ -126,11 +126,17 @@ export async function restartDaemon(home = homedir(), exec = defaultExec) {
126
126
  throw new Error(RESTART_FAILED_MESSAGE);
127
127
  const plistPath = writeDaemonPlist(home);
128
128
  try {
129
+ exec('launchctl', bootoutArgs(uid, plistPath));
130
+ }
131
+ catch {
132
+ // Already stopped or not loaded; bootstrap below covers both cases.
133
+ }
134
+ try {
135
+ exec('launchctl', bootstrapArgs(uid, plistPath));
129
136
  exec('launchctl', kickstartArgs(uid));
130
137
  }
131
138
  catch {
132
139
  try {
133
- exec('launchctl', bootstrapArgs(uid, plistPath));
134
140
  exec('launchctl', kickstartArgs(uid));
135
141
  }
136
142
  catch {
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.8",
3
+ "version": "1.1.10",
4
4
  "description": "Control Space CLI - machine setup and background daemon",
5
5
  "type": "module",
6
6
  "files": [