@floless/app 0.6.0 → 0.6.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/web/aware.js CHANGED
@@ -473,7 +473,16 @@
473
473
  const $wfList = document.getElementById('wf-list');
474
474
  let comboHi = -1; // index into the currently-visible options (-1 = none)
475
475
 
476
- function setComboTriggerLabel(text) { if ($wfTriggerLabel) $wfTriggerLabel.textContent = text || 'select workflow'; }
476
+ // Status placeholders that flow through setComboTriggerLabel but are NOT workflow names.
477
+ const WF_STATUS_TEXT = new Set(['loading…', 'no workflows installed', 'server unreachable', 'select workflow', '']);
478
+ function setComboTriggerLabel(text) {
479
+ if ($wfTriggerLabel) $wfTriggerLabel.textContent = text || 'select workflow';
480
+ // App tab title — kept distinct from the marketing site's "FloLess — Workflow
481
+ // Automation for AEC": show "<workflow> — FloLess" when a workflow is selected so
482
+ // parallel browser tabs are tellable apart, else the static "FloLess Workspace"
483
+ // (which is also the initial <title> in index.html).
484
+ document.title = (text && !WF_STATUS_TEXT.has(text)) ? `${text} — FloLess` : 'FloLess Workspace';
485
+ }
477
486
  function setComboSelected(id) {
478
487
  if (!$wfList) return;
479
488
  $wfList.querySelectorAll('.wf-option').forEach((o) => {
@@ -3,7 +3,7 @@
3
3
  <head>
4
4
  <meta charset="UTF-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1">
6
- <title>floless.app — prompt-native front door to AWARE</title>
6
+ <title>FloLess Workspace</title>
7
7
  <meta name="theme-color" content="#1E3A5F" />
8
8
  <!-- Favicons (mirrors floless-web) -->
9
9
  <link rel="icon" type="image/svg+xml" href="/favicon.svg?v=2" />
package/launch.mjs CHANGED
@@ -312,16 +312,32 @@ function enumerateProcesses() {
312
312
  }
313
313
  }
314
314
 
315
+ // Build the `taskkill` argv for one pid. `tree` (default true) adds /T to also kill the
316
+ // target's whole child-process tree — correct for teardown/uninstall, where the
317
+ // supervisor's spawned --serve child must die WITH it. The update-apply path running
318
+ // inside the SERVE passes tree:false: there the caller IS the supervisor's --serve child
319
+ // (and the process that must survive to launch Update.exe), so a /T tree-kill of the
320
+ // supervisor would also kill the caller itself. tree:false kills ONLY the supervisor and
321
+ // lets the serve exit on its own. Pure + exported so the /T decision is unit-tested.
322
+ export function taskkillArgs(pid, { tree = true } = {}) {
323
+ return tree ? ['/PID', String(pid), '/T', '/F'] : ['/PID', String(pid), '/F'];
324
+ }
325
+
315
326
  // Kill the --supervise watchdog FIRST (Codex B1) so it can't respawn the server in
316
327
  // the gap before stopServer(). Matches THIS app's exe + the supervise action, never
317
328
  // process.pid (self-kill guard lives in supervisorPidsToKill). Idempotent; win32-only.
318
329
  //
330
+ // `tree` (default true) tree-kills (/T) — teardown/uninstall, where the supervisor's
331
+ // --serve child must die too. The update-apply path INSIDE the serve passes {tree:false}
332
+ // (the serve is itself the supervisor's child and must survive to launch Update.exe, then
333
+ // exit on its own) — see taskkillArgs above and index.ts /api/update/apply.
334
+ //
319
335
  // SAFETY (review #1): in the npm channel process.execPath is the GENERIC node.exe, so
320
336
  // matching on it alone could kill ANY `node … supervise` process (e.g. a third-party
321
337
  // watchdog). When we detect that channel, also require the launcher script (this
322
338
  // launch.mjs) in the command line — our supervisor runs `node … launch.mjs supervise`.
323
339
  // The packaged exe (unique FlolessApp.exe) passes no scriptMatch — its match is exact.
324
- function killSupervisor() {
340
+ export function killSupervisor({ tree = true } = {}) {
325
341
  if (!isWin) return;
326
342
  const isNpmChannel = /^node(\.exe)?$/i.test(basename(process.execPath));
327
343
  const scriptMatch = isNpmChannel ? basename(fileURLToPath(import.meta.url)) : undefined; // 'launch.mjs'
@@ -339,7 +355,7 @@ function killSupervisor() {
339
355
  log(`stopping supervisor (pid ${pid})…`);
340
356
  // execFileSync (no shell) with an argv array — pid is already Number()-coerced in
341
357
  // 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 */ }
358
+ try { execFileSync('taskkill', taskkillArgs(pid, { tree }), { stdio: 'ignore', windowsHide: true }); } catch { /* already gone */ }
343
359
  }
344
360
  }
345
361
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@floless/app",
3
- "version": "0.6.0",
3
+ "version": "0.6.2",
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": {