@floless/app 0.6.1 → 0.6.3

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/launch.mjs CHANGED
@@ -123,7 +123,11 @@ function startServerDetached() {
123
123
  }
124
124
 
125
125
  function openBrowser(url) {
126
- if (isWin) spawn('cmd', ['/c', 'start', '', url], { windowsHide: true, detached: true }).unref();
126
+ // NO `detached` on Windows: Node #21825 makes `detached` defeat `windowsHide` for a CUI
127
+ // child (cmd.exe), flashing a console window. Without it, windowsHide hides cmd; `start`
128
+ // hands the URL to the browser via ShellExecute (independent of cmd's tree), so the browser
129
+ // still survives this launcher exiting. unref() keeps it from holding the event loop.
130
+ if (isWin) spawn('cmd', ['/c', 'start', '', url], { windowsHide: true }).unref();
127
131
  else spawn(process.platform === 'darwin' ? 'open' : 'xdg-open', [url], { detached: true }).unref();
128
132
  }
129
133
 
@@ -312,16 +316,32 @@ function enumerateProcesses() {
312
316
  }
313
317
  }
314
318
 
319
+ // Build the `taskkill` argv for one pid. `tree` (default true) adds /T to also kill the
320
+ // target's whole child-process tree — correct for teardown/uninstall, where the
321
+ // supervisor's spawned --serve child must die WITH it. The update-apply path running
322
+ // inside the SERVE passes tree:false: there the caller IS the supervisor's --serve child
323
+ // (and the process that must survive to launch Update.exe), so a /T tree-kill of the
324
+ // supervisor would also kill the caller itself. tree:false kills ONLY the supervisor and
325
+ // lets the serve exit on its own. Pure + exported so the /T decision is unit-tested.
326
+ export function taskkillArgs(pid, { tree = true } = {}) {
327
+ return tree ? ['/PID', String(pid), '/T', '/F'] : ['/PID', String(pid), '/F'];
328
+ }
329
+
315
330
  // Kill the --supervise watchdog FIRST (Codex B1) so it can't respawn the server in
316
331
  // the gap before stopServer(). Matches THIS app's exe + the supervise action, never
317
332
  // process.pid (self-kill guard lives in supervisorPidsToKill). Idempotent; win32-only.
318
333
  //
334
+ // `tree` (default true) tree-kills (/T) — teardown/uninstall, where the supervisor's
335
+ // --serve child must die too. The update-apply path INSIDE the serve passes {tree:false}
336
+ // (the serve is itself the supervisor's child and must survive to launch Update.exe, then
337
+ // exit on its own) — see taskkillArgs above and index.ts /api/update/apply.
338
+ //
319
339
  // SAFETY (review #1): in the npm channel process.execPath is the GENERIC node.exe, so
320
340
  // matching on it alone could kill ANY `node … supervise` process (e.g. a third-party
321
341
  // watchdog). When we detect that channel, also require the launcher script (this
322
342
  // launch.mjs) in the command line — our supervisor runs `node … launch.mjs supervise`.
323
343
  // The packaged exe (unique FlolessApp.exe) passes no scriptMatch — its match is exact.
324
- function killSupervisor() {
344
+ export function killSupervisor({ tree = true } = {}) {
325
345
  if (!isWin) return;
326
346
  const isNpmChannel = /^node(\.exe)?$/i.test(basename(process.execPath));
327
347
  const scriptMatch = isNpmChannel ? basename(fileURLToPath(import.meta.url)) : undefined; // 'launch.mjs'
@@ -339,7 +359,7 @@ function killSupervisor() {
339
359
  log(`stopping supervisor (pid ${pid})…`);
340
360
  // execFileSync (no shell) with an argv array — pid is already Number()-coerced in
341
361
  // parseProcessList, and avoiding the shell rules out any injection entirely.
342
- try { execFileSync('taskkill', ['/PID', String(pid), '/T', '/F'], { stdio: 'ignore', windowsHide: true }); } catch { /* already gone */ }
362
+ try { execFileSync('taskkill', taskkillArgs(pid, { tree }), { stdio: 'ignore', windowsHide: true }); } catch { /* already gone */ }
343
363
  }
344
364
  }
345
365
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@floless/app",
3
- "version": "0.6.1",
3
+ "version": "0.6.3",
4
4
  "type": "module",
5
5
  "description": "Thin localhost host for floless.app — serves web/ and shells the aware CLI. No engine, no LLM.",
6
6
  "bin": {