@phenx-inc/ctlsurf 0.17.0 → 0.17.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/bin/ctlsurf-worker.js +63 -6
- package/out/headless/index.mjs +1 -1
- package/out/headless/index.mjs.map +1 -1
- package/package.json +1 -1
- package/scripts/extract-electron.js +105 -0
package/bin/ctlsurf-worker.js
CHANGED
|
@@ -190,11 +190,14 @@ if (subcommand === 'doctor') {
|
|
|
190
190
|
console.log(` ${D}Run: ctlsurf setup${R}`)
|
|
191
191
|
}
|
|
192
192
|
|
|
193
|
-
// Desktop
|
|
194
|
-
|
|
195
|
-
|
|
193
|
+
// Desktop — check the binary actually resolves, not just that the package
|
|
194
|
+
// exists (a half-extracted electron still passes require.resolve)
|
|
195
|
+
if (electronResolves()) {
|
|
196
196
|
console.log(` ${G}✓${R} Electron ${D}(desktop mode available)${R}`)
|
|
197
|
-
}
|
|
197
|
+
} else if (fs.existsSync(path.join(ROOT, 'node_modules', 'electron'))) {
|
|
198
|
+
console.log(` ${Y}✗${R} Electron ${D}(installed but binary incomplete — desktop mode unavailable)${R}`)
|
|
199
|
+
console.log(` ${D}Repair: cd ${ROOT} && node scripts/extract-electron.js${R}`)
|
|
200
|
+
} else {
|
|
198
201
|
console.log(` ${D}-${R} Electron ${D}(not installed — desktop mode unavailable)${R}`)
|
|
199
202
|
console.log(` ${D}Install: cd ${ROOT} && npm install${R}`)
|
|
200
203
|
}
|
|
@@ -238,10 +241,34 @@ const mode = detectMode(args)
|
|
|
238
241
|
checkApiKey(mode).catch(() => {}).then(() => launch(mode))
|
|
239
242
|
|
|
240
243
|
function launch(launchMode) {
|
|
244
|
+
ensurePtyHelperExecutable()
|
|
241
245
|
if (launchMode === 'desktop') runDesktop()
|
|
242
246
|
else runTerminal()
|
|
243
247
|
}
|
|
244
248
|
|
|
249
|
+
// node-pty runs spawn-helper from whichever native dir it loaded (build/Release,
|
|
250
|
+
// else prebuilds/<platform>-<arch>). The prebuilt copy ships without the execute
|
|
251
|
+
// bit, so when our postinstall didn't compile build/Release (install scripts
|
|
252
|
+
// blocked, or no Xcode CLT) every spawn fails with "posix_spawnp failed".
|
|
253
|
+
function ensurePtyHelperExecutable() {
|
|
254
|
+
const ptyDir = path.join(ROOT, 'node_modules', 'node-pty')
|
|
255
|
+
const dirs = [path.join(ptyDir, 'build', 'Release')]
|
|
256
|
+
try {
|
|
257
|
+
for (const d of fs.readdirSync(path.join(ptyDir, 'prebuilds'))) {
|
|
258
|
+
if (d.startsWith(`${process.platform}-`)) dirs.push(path.join(ptyDir, 'prebuilds', d))
|
|
259
|
+
}
|
|
260
|
+
} catch { /* no prebuilds */ }
|
|
261
|
+
|
|
262
|
+
for (const dir of dirs) {
|
|
263
|
+
const helper = path.join(dir, 'spawn-helper')
|
|
264
|
+
try {
|
|
265
|
+
if ((fs.statSync(helper).mode & 0o111) === 0) fs.chmodSync(helper, 0o755)
|
|
266
|
+
} catch (err) {
|
|
267
|
+
if (err.code !== 'ENOENT') console.error(`${D}[ctlsurf] could not make ${helper} executable: ${err.message}${R}`)
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
245
272
|
function runDesktop() {
|
|
246
273
|
let electronPath
|
|
247
274
|
try {
|
|
@@ -297,13 +324,43 @@ function installElectron() {
|
|
|
297
324
|
cwd: ROOT,
|
|
298
325
|
stdio: ['ignore', 'ignore', 'inherit']
|
|
299
326
|
})
|
|
300
|
-
console.log(` ${G}✓${R} Electron installed.\n`)
|
|
301
|
-
return true
|
|
302
327
|
} catch (err) {
|
|
303
328
|
console.error(`\n${Y}!${R} Electron install failed: ${err.message}`)
|
|
304
329
|
console.error(` Try manually: cd ${ROOT} && npm install electron\n`)
|
|
305
330
|
return false
|
|
306
331
|
}
|
|
332
|
+
|
|
333
|
+
// electron's postinstall can exit 0 with a half-extracted binary (its
|
|
334
|
+
// extract-zip stalls on Node >= 26), and npm won't re-run it for a package
|
|
335
|
+
// that's already present — so unzip it ourselves with the system tool.
|
|
336
|
+
if (!electronResolves()) {
|
|
337
|
+
console.log(` ${D}Electron binary incomplete — extracting with system unzip...${R}`)
|
|
338
|
+
try {
|
|
339
|
+
execFileSync(process.execPath, [path.join(ROOT, 'scripts', 'extract-electron.js')], {
|
|
340
|
+
stdio: ['ignore', 'ignore', 'inherit']
|
|
341
|
+
})
|
|
342
|
+
} catch (err) {
|
|
343
|
+
console.error(`\n${Y}!${R} Electron extract failed: ${err.message}`)
|
|
344
|
+
console.error(` Try manually: cd ${ROOT} && node scripts/extract-electron.js\n`)
|
|
345
|
+
return false
|
|
346
|
+
}
|
|
347
|
+
if (!electronResolves()) {
|
|
348
|
+
console.error(`\n${Y}!${R} Electron binary still missing after extract.\n`)
|
|
349
|
+
return false
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
console.log(` ${G}✓${R} Electron installed.\n`)
|
|
354
|
+
return true
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
function electronResolves() {
|
|
358
|
+
try {
|
|
359
|
+
delete require.cache[require.resolve('electron')]
|
|
360
|
+
return fs.existsSync(require('electron'))
|
|
361
|
+
} catch {
|
|
362
|
+
return false
|
|
363
|
+
}
|
|
307
364
|
}
|
|
308
365
|
|
|
309
366
|
function runTerminal() {
|
package/out/headless/index.mjs
CHANGED
|
@@ -17314,7 +17314,7 @@ var require_package = __commonJS({
|
|
|
17314
17314
|
"package.json"(exports, module) {
|
|
17315
17315
|
module.exports = {
|
|
17316
17316
|
name: "@phenx-inc/ctlsurf",
|
|
17317
|
-
version: "0.17.
|
|
17317
|
+
version: "0.17.2",
|
|
17318
17318
|
description: "Agent-agnostic terminal and desktop app for ctlsurf \u2014 run Claude Code, Codex, or any coding agent with live session logging and remote control",
|
|
17319
17319
|
main: "out/main/index.js",
|
|
17320
17320
|
bin: {
|