@bazilio-san/glm-cc 1.0.17 → 1.0.19
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/bin/glm.js +60 -2
- package/package.json +1 -1
package/bin/glm.js
CHANGED
|
@@ -95,6 +95,54 @@ function showConfig(config) {
|
|
|
95
95
|
console.log(lines.join('\n'));
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
+
// Resolve `claude` into { cmd, args, useShell } without an extra cmd.exe
|
|
99
|
+
// layer on Windows. A nested cmd.exe breaks ConPty stdin for Ink-based TUIs
|
|
100
|
+
// (e.g. when glm is spawned via node-pty from a test harness).
|
|
101
|
+
function resolveClaude() {
|
|
102
|
+
if (process.platform !== 'win32') {
|
|
103
|
+
return { cmd: 'claude', prefix: [], useShell: false };
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const pathExts = (process.env.PATHEXT || '.COM;.EXE;.BAT;.CMD')
|
|
107
|
+
.split(';').map(e => e.toLowerCase()).filter(Boolean);
|
|
108
|
+
const pathDirs = (process.env.PATH || '').split(path.delimiter).filter(Boolean);
|
|
109
|
+
|
|
110
|
+
let exePath = null;
|
|
111
|
+
let cmdPath = null;
|
|
112
|
+
for (const dir of pathDirs) {
|
|
113
|
+
for (const ext of pathExts) {
|
|
114
|
+
const full = path.join(dir, 'claude' + ext);
|
|
115
|
+
if (!fs.existsSync(full)) continue;
|
|
116
|
+
if (ext === '.exe' && !exePath) exePath = full;
|
|
117
|
+
else if ((ext === '.cmd' || ext === '.bat') && !cmdPath) cmdPath = full;
|
|
118
|
+
}
|
|
119
|
+
if (exePath) break;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Prefer native .exe — spawn directly, no shell layer.
|
|
123
|
+
if (exePath) {
|
|
124
|
+
return { cmd: exePath, prefix: [], useShell: false };
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// npm shim on Windows looks like:
|
|
128
|
+
// @"C:\Program Files\nodejs\node.exe" "...\cli.js" %*
|
|
129
|
+
// Parse it and spawn node directly so we skip the shim's cmd.exe.
|
|
130
|
+
if (cmdPath) {
|
|
131
|
+
try {
|
|
132
|
+
const shim = fs.readFileSync(cmdPath, 'utf8');
|
|
133
|
+
const m = shim.match(/"([^"]+\\node\.exe)"\s+"([^"]+\.(?:js|mjs|cjs))"/i);
|
|
134
|
+
if (m) {
|
|
135
|
+
return { cmd: m[1], prefix: [m[2]], useShell: false };
|
|
136
|
+
}
|
|
137
|
+
} catch { /* fall through */ }
|
|
138
|
+
// Can't parse — must go through shell for .cmd execution.
|
|
139
|
+
return { cmd: cmdPath, prefix: [], useShell: true };
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Nothing found — let cmd.exe resolve at runtime (legacy behavior).
|
|
143
|
+
return { cmd: 'claude', prefix: [], useShell: true };
|
|
144
|
+
}
|
|
145
|
+
|
|
98
146
|
function launchClaude(config, args) {
|
|
99
147
|
const env = { ...process.env };
|
|
100
148
|
for (const field of CONFIG_FIELDS) {
|
|
@@ -102,11 +150,21 @@ function launchClaude(config, args) {
|
|
|
102
150
|
env[field.key] = config[field.key];
|
|
103
151
|
}
|
|
104
152
|
}
|
|
105
|
-
|
|
153
|
+
|
|
154
|
+
const { cmd, prefix, useShell } = resolveClaude();
|
|
155
|
+
const proc = spawn(cmd, [...prefix, ...args], {
|
|
106
156
|
env,
|
|
107
157
|
stdio: 'inherit',
|
|
108
|
-
shell:
|
|
158
|
+
shell: useShell,
|
|
109
159
|
});
|
|
160
|
+
|
|
161
|
+
const signals = ['SIGINT', 'SIGTERM', 'SIGHUP', 'SIGBREAK'];
|
|
162
|
+
for (const sig of signals) {
|
|
163
|
+
process.on(sig, () => {
|
|
164
|
+
try { proc.kill(sig); } catch { /* */ }
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
|
|
110
168
|
proc.on('exit', code => process.exit(code ?? 0));
|
|
111
169
|
proc.on('error', err => {
|
|
112
170
|
console.error(`Failed to launch claude: ${err.message}`);
|