@lkangd/cc-settings-preset 1.1.1 → 1.1.2
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/core/spawn.js +94 -3
- package/dist/core/spawn.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/dist/core/spawn.js
CHANGED
|
@@ -1,20 +1,111 @@
|
|
|
1
|
+
import { constants } from 'node:os';
|
|
1
2
|
import spawn from 'cross-spawn';
|
|
2
3
|
import { CliError } from './errors.js';
|
|
4
|
+
// Signals whose default disposition is to terminate the process. We must handle
|
|
5
|
+
// these explicitly: otherwise Node tears ccsp down immediately (without firing
|
|
6
|
+
// the 'exit' event) and the inherited `claude` child is left orphaned to pid 1.
|
|
7
|
+
//
|
|
8
|
+
// tty-generated signals (SIGINT/SIGQUIT via Ctrl+C / Ctrl+\) are intentionally
|
|
9
|
+
// excluded: the tty delivers them to the whole foreground process group, so
|
|
10
|
+
// claude already receives them directly — forwarding would double-deliver and
|
|
11
|
+
// break claude's own interrupt handling. SIGHUP (terminal close) and SIGTERM
|
|
12
|
+
// (external kill) are not tty-generated, so forwarding them is unambiguous.
|
|
13
|
+
const TERMINATION_SIGNALS = ['SIGHUP', 'SIGTERM'];
|
|
14
|
+
// Grace period between forwarding the terminating signal and force-killing a
|
|
15
|
+
// child that refuses to exit (e.g. claude ignores SIGHUP while in raw mode).
|
|
16
|
+
const FORCE_KILL_DELAY_MS = 5000;
|
|
3
17
|
export async function spawnClaude(settingsPath, claudeArgs) {
|
|
4
18
|
return new Promise((resolve, reject) => {
|
|
5
19
|
const child = spawn('claude', ['--settings', settingsPath, ...claudeArgs], {
|
|
6
20
|
stdio: 'inherit',
|
|
7
21
|
});
|
|
22
|
+
let settled = false;
|
|
23
|
+
let forceKillTimer;
|
|
24
|
+
// Liveness must be derived from exit/signal codes, not `child.killed`:
|
|
25
|
+
// `killed` only records that kill() was *called* (true the moment we forward
|
|
26
|
+
// SIGHUP), so using it here would make the escalation timer skip the SIGKILL
|
|
27
|
+
// it exists to deliver. Both codes stay null until the child actually exits.
|
|
28
|
+
const childAlive = () => child.exitCode === null && child.signalCode === null;
|
|
29
|
+
// Forward a terminating signal to the child so it can shut down gracefully,
|
|
30
|
+
// then escalate to SIGKILL if it ignores the signal. This binds claude's
|
|
31
|
+
// lifetime to ccsp's, so closing the terminal can't leave an orphan behind.
|
|
32
|
+
const forwardSignal = (signal) => {
|
|
33
|
+
if (!childAlive())
|
|
34
|
+
return;
|
|
35
|
+
try {
|
|
36
|
+
child.kill(signal);
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
// Child is already gone; nothing to forward.
|
|
40
|
+
}
|
|
41
|
+
if (!forceKillTimer) {
|
|
42
|
+
forceKillTimer = setTimeout(() => {
|
|
43
|
+
if (childAlive()) {
|
|
44
|
+
try {
|
|
45
|
+
child.kill('SIGKILL');
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
// Already exited between the check and the kill.
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}, FORCE_KILL_DELAY_MS);
|
|
52
|
+
// Don't let the escalation timer keep ccsp alive on its own.
|
|
53
|
+
forceKillTimer.unref?.();
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
// Last-resort guarantee: if ccsp exits through any path while the child is
|
|
57
|
+
// still alive, take the child down with it. The 'exit' handler runs
|
|
58
|
+
// synchronously, so only a synchronous kill is reliable here.
|
|
59
|
+
const onProcessExit = () => {
|
|
60
|
+
if (childAlive()) {
|
|
61
|
+
try {
|
|
62
|
+
child.kill('SIGKILL');
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
// Already exited.
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
for (const signal of TERMINATION_SIGNALS) {
|
|
70
|
+
process.on(signal, forwardSignal);
|
|
71
|
+
}
|
|
72
|
+
process.on('exit', onProcessExit);
|
|
73
|
+
const cleanup = () => {
|
|
74
|
+
if (forceKillTimer) {
|
|
75
|
+
clearTimeout(forceKillTimer);
|
|
76
|
+
forceKillTimer = undefined;
|
|
77
|
+
}
|
|
78
|
+
for (const signal of TERMINATION_SIGNALS) {
|
|
79
|
+
process.removeListener(signal, forwardSignal);
|
|
80
|
+
}
|
|
81
|
+
process.removeListener('exit', onProcessExit);
|
|
82
|
+
};
|
|
8
83
|
child.once('error', error => {
|
|
9
|
-
if (
|
|
84
|
+
if (settled)
|
|
85
|
+
return;
|
|
86
|
+
settled = true;
|
|
87
|
+
cleanup();
|
|
88
|
+
const err = error;
|
|
89
|
+
if (err.code === 'ENOENT') {
|
|
10
90
|
reject(new CliError('Claude Code executable not found. Install Claude Code or check PATH.'));
|
|
11
91
|
return;
|
|
12
92
|
}
|
|
13
|
-
|
|
93
|
+
// Wrap every other spawn failure (EACCES, EMFILE, …) in a CliError so the
|
|
94
|
+
// caller sets a non-zero process.exitCode and prints a clean message,
|
|
95
|
+
// instead of surfacing a raw unhandled rejection.
|
|
96
|
+
reject(new CliError(`Failed to launch Claude Code: ${err.message}`));
|
|
14
97
|
});
|
|
15
98
|
child.once('close', (exitCode, signal) => {
|
|
99
|
+
if (settled)
|
|
100
|
+
return;
|
|
101
|
+
settled = true;
|
|
102
|
+
cleanup();
|
|
16
103
|
if (signal) {
|
|
17
|
-
|
|
104
|
+
// Signal death is the expected outcome of our own forwarding (terminal
|
|
105
|
+
// close / external kill), not an error. Report it with the conventional
|
|
106
|
+
// 128+signum exit status so callers can both detect it and stay quiet.
|
|
107
|
+
const signum = constants.signals[signal] ?? 0;
|
|
108
|
+
resolve(128 + signum);
|
|
18
109
|
return;
|
|
19
110
|
}
|
|
20
111
|
if (exitCode === null) {
|
package/dist/core/spawn.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spawn.js","sourceRoot":"","sources":["../../src/core/spawn.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,aAAa,CAAA;AAE/B,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAEtC,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,YAAoB,EAAE,UAAoB;IAC1E,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,KAAK,GAAG,KAAK,CAAC,QAAQ,EAAE,CAAC,YAAY,EAAE,YAAY,EAAE,GAAG,UAAU,CAAC,EAAE;YACzE,KAAK,EAAE,SAAS;SACjB,CAAC,CAAA;QAEF,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,EAAE;YAC1B,
|
|
1
|
+
{"version":3,"file":"spawn.js","sourceRoot":"","sources":["../../src/core/spawn.ts"],"names":[],"mappings":"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"}
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const VERSION = "1.1.
|
|
1
|
+
export declare const VERSION = "1.1.2";
|
package/dist/version.js
CHANGED