@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 +7 -1
- package/dist/spawner.js +26 -12
- package/package.json +1 -1
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 ??
|
|
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 = (
|
|
17
|
-
done
|
|
18
|
-
|
|
19
|
-
|
|
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
|
|
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', '
|
|
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.
|
|
104
|
-
|
|
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
|
}
|