@floless/app 0.12.1 → 0.12.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.
@@ -43012,7 +43012,7 @@ var require_static = __commonJS({
43012
43012
  "use strict";
43013
43013
  var path = require("node:path");
43014
43014
  var { fileURLToPath: fileURLToPath4 } = require("node:url");
43015
- var { statSync: statSync7 } = require("node:fs");
43015
+ var { statSync: statSync8 } = require("node:fs");
43016
43016
  var { glob } = require_commonjs6();
43017
43017
  var fp = require_plugin2();
43018
43018
  var send = require_send2();
@@ -43375,7 +43375,7 @@ var require_static = __commonJS({
43375
43375
  }
43376
43376
  let pathStat;
43377
43377
  try {
43378
- pathStat = statSync7(rootPath);
43378
+ pathStat = statSync8(rootPath);
43379
43379
  } catch (e) {
43380
43380
  if (e.code === "ENOENT") {
43381
43381
  fastify.log.warn(`"root" path "${rootPath}" must exist`);
@@ -43399,7 +43399,7 @@ var require_static = __commonJS({
43399
43399
  return indexFiles.find((filename) => {
43400
43400
  const p = path.join(root, pathname, filename);
43401
43401
  try {
43402
- const stats = statSync7(p);
43402
+ const stats = statSync8(p);
43403
43403
  return !stats.isDirectory();
43404
43404
  } catch {
43405
43405
  return false;
@@ -50828,7 +50828,7 @@ var import_node_readline2 = require("node:readline");
50828
50828
  // index.ts
50829
50829
  var import_node_url3 = require("node:url");
50830
50830
  var import_node_path20 = require("node:path");
50831
- var import_node_os13 = require("node:os");
50831
+ var import_node_os14 = require("node:os");
50832
50832
  var import_node_fs21 = require("node:fs");
50833
50833
  var import_node_child_process6 = require("node:child_process");
50834
50834
 
@@ -52609,7 +52609,7 @@ function appVersion() {
52609
52609
  return resolveVersion({
52610
52610
  isSea: isSea2(),
52611
52611
  sqVersionXml: readSqVersionXml(),
52612
- define: true ? "0.12.1" : void 0,
52612
+ define: true ? "0.12.3" : void 0,
52613
52613
  pkgVersion: readPkgVersion()
52614
52614
  });
52615
52615
  }
@@ -52619,7 +52619,7 @@ function resolveChannel(s) {
52619
52619
  return "dev";
52620
52620
  }
52621
52621
  function appChannel() {
52622
- return resolveChannel({ isSea: isSea2(), define: true ? "0.12.1" : void 0 });
52622
+ return resolveChannel({ isSea: isSea2(), define: true ? "0.12.3" : void 0 });
52623
52623
  }
52624
52624
 
52625
52625
  // oauth-presets.ts
@@ -54039,29 +54039,48 @@ var import_node_path15 = require("node:path");
54039
54039
 
54040
54040
  // post-update-marker.mjs
54041
54041
  var import_node_fs16 = require("node:fs");
54042
+ var import_node_os11 = require("node:os");
54042
54043
  var import_node_path14 = require("node:path");
54044
+ var FRESH_MS = 12e4;
54043
54045
  function markerPath() {
54044
54046
  const override = (process.env.FLOLESS_POST_UPDATE_MARKER ?? "").trim();
54045
54047
  if (override) return override;
54046
- return (0, import_node_path14.join)((0, import_node_path14.dirname)((0, import_node_path14.dirname)(process.execPath)), ".floless-post-update");
54048
+ const root = process.env.FLOLESS_HOME ?? (0, import_node_path14.join)((0, import_node_os11.homedir)(), ".floless");
54049
+ return (0, import_node_path14.join)(root, ".post-update");
54047
54050
  }
54048
- function writePostUpdateMarker() {
54051
+ function legacyMarkerPath() {
54052
+ if ((process.env.FLOLESS_POST_UPDATE_MARKER ?? "").trim()) return null;
54049
54053
  try {
54050
- (0, import_node_fs16.writeFileSync)(markerPath(), (/* @__PURE__ */ new Date()).toISOString());
54051
- return true;
54054
+ return (0, import_node_path14.join)((0, import_node_path14.dirname)((0, import_node_path14.dirname)(process.execPath)), ".floless-post-update");
54052
54055
  } catch {
54053
- return false;
54056
+ return null;
54057
+ }
54058
+ }
54059
+ function writePostUpdateMarker() {
54060
+ let wrote = false;
54061
+ for (const p of [markerPath(), legacyMarkerPath()]) {
54062
+ if (!p) continue;
54063
+ try {
54064
+ (0, import_node_fs16.writeFileSync)(p, (/* @__PURE__ */ new Date()).toISOString());
54065
+ wrote = true;
54066
+ } catch {
54067
+ }
54054
54068
  }
54069
+ return wrote;
54055
54070
  }
54056
54071
  function consumePostUpdateMarker() {
54057
- const p = markerPath();
54058
- try {
54059
- if (!(0, import_node_fs16.existsSync)(p)) return false;
54060
- (0, import_node_fs16.rmSync)(p, { force: true });
54061
- return true;
54062
- } catch {
54063
- return false;
54072
+ let fresh = false;
54073
+ for (const p of [markerPath(), legacyMarkerPath()]) {
54074
+ if (!p) continue;
54075
+ try {
54076
+ if (!(0, import_node_fs16.existsSync)(p)) continue;
54077
+ const ageMs = Date.now() - (0, import_node_fs16.statSync)(p).mtimeMs;
54078
+ (0, import_node_fs16.rmSync)(p, { force: true });
54079
+ if (ageMs < FRESH_MS) fresh = true;
54080
+ } catch {
54081
+ }
54064
54082
  }
54083
+ return fresh;
54065
54084
  }
54066
54085
 
54067
54086
  // updater.ts
@@ -54877,7 +54896,7 @@ function awareUpgradeBlockReason(s) {
54877
54896
 
54878
54897
  // skill-sync.ts
54879
54898
  var import_node_fs19 = require("node:fs");
54880
- var import_node_os11 = require("node:os");
54899
+ var import_node_os12 = require("node:os");
54881
54900
  var import_node_path17 = require("node:path");
54882
54901
  var import_node_url2 = require("node:url");
54883
54902
  var import_yaml5 = __toESM(require_dist6(), 1);
@@ -54917,7 +54936,7 @@ function targetConfigDirs() {
54917
54936
  if (override) {
54918
54937
  return override.split(";").map((d) => d.trim()).filter(Boolean).map((dir) => ({ runtime: "custom", dir }));
54919
54938
  }
54920
- const home = (0, import_node_os11.homedir)();
54939
+ const home = (0, import_node_os12.homedir)();
54921
54940
  return [
54922
54941
  { runtime: "claude", dir: (0, import_node_path17.join)(home, ".claude") },
54923
54942
  { runtime: "codex", dir: (0, import_node_path17.join)(home, ".codex") },
@@ -55016,7 +55035,7 @@ function syncSkills() {
55016
55035
  }
55017
55036
 
55018
55037
  // watch.ts
55019
- var import_node_os12 = require("node:os");
55038
+ var import_node_os13 = require("node:os");
55020
55039
  var import_node_path19 = require("node:path");
55021
55040
  var import_node_fs20 = require("node:fs");
55022
55041
 
@@ -56729,7 +56748,7 @@ function underDir(path, dir) {
56729
56748
  return p === d || p.startsWith(d + import_node_path19.sep);
56730
56749
  }
56731
56750
  function startWatcher() {
56732
- const awareDir = process.env.AWARE_HOME ?? (0, import_node_path19.join)((0, import_node_os12.homedir)(), ".aware");
56751
+ const awareDir = process.env.AWARE_HOME ?? (0, import_node_path19.join)((0, import_node_os13.homedir)(), ".aware");
56733
56752
  const credentialsDir = (0, import_node_path19.join)(awareDir, "credentials");
56734
56753
  if (!(0, import_node_fs20.existsSync)(credentialsDir)) {
56735
56754
  try {
@@ -57162,7 +57181,7 @@ async function startServer() {
57162
57181
  }
57163
57182
  const inputs = appData.inputs.map((i) => ({ name: i.name, type: i.type }));
57164
57183
  const baked = bakeFloSource(appData.source.text, inputs);
57165
- const tmpRoot = (0, import_node_fs21.mkdtempSync)((0, import_node_path20.join)((0, import_node_os13.tmpdir)(), "floless-bake-"));
57184
+ const tmpRoot = (0, import_node_fs21.mkdtempSync)((0, import_node_path20.join)((0, import_node_os14.tmpdir)(), "floless-bake-"));
57166
57185
  const backupDir = (0, import_node_path20.join)(tmpRoot, `${id}-backup`);
57167
57186
  const bakeDir = (0, import_node_path20.join)(tmpRoot, id);
57168
57187
  (0, import_node_fs21.cpSync)(appDir(id), backupDir, { recursive: true });
@@ -57200,7 +57219,7 @@ async function startServer() {
57200
57219
  if (appInstalled) (0, import_node_fs21.rmSync)(tmpRoot, { recursive: true, force: true });
57201
57220
  }
57202
57221
  });
57203
- const graftAgentsDir = () => (0, import_node_path20.join)((0, import_node_os13.homedir)(), ".aware", "agents");
57222
+ const graftAgentsDir = () => (0, import_node_path20.join)((0, import_node_os14.homedir)(), ".aware", "agents");
57204
57223
  app.post("/api/graft/match", async (req, reply) => {
57205
57224
  const { glob } = req.body ?? {};
57206
57225
  if (!glob) return reply.status(400).send({ ok: false, error: "glob required" });
@@ -57217,7 +57236,7 @@ async function startServer() {
57217
57236
  if (!sourceKind || !sourceRef) {
57218
57237
  return reply.status(400).send({ ok: false, error: "sourceKind and sourceRef required" });
57219
57238
  }
57220
- const tempHome = (0, import_node_fs21.mkdtempSync)((0, import_node_path20.join)((0, import_node_os13.tmpdir)(), "floless-graft-"));
57239
+ const tempHome = (0, import_node_fs21.mkdtempSync)((0, import_node_path20.join)((0, import_node_os14.tmpdir)(), "floless-graft-"));
57221
57240
  let result;
57222
57241
  try {
57223
57242
  result = await aware.build({
@@ -57745,6 +57764,7 @@ async function main() {
57745
57764
  const realExe = resolveRealInstallExe(process.execPath);
57746
57765
  registerProtocol(realExe);
57747
57766
  registerAutostart(realExe);
57767
+ if (veloHook === "--veloapp-updated") writePostUpdateMarker();
57748
57768
  } else if (veloHook === "--veloapp-uninstall") {
57749
57769
  unregisterProtocol();
57750
57770
  unregisterAutostart();
package/dist/web/aware.js CHANGED
@@ -791,11 +791,22 @@
791
791
  const saveItem = document.querySelector('.menu-item[data-action="save"]');
792
792
  if (saveItem) saveItem.classList.toggle('menu-item-dirty', dirty);
793
793
  }
794
+ // Set while WE programmatically reload to adopt a self-update (#37) — an in-place build
795
+ // adoption is not the user navigating away, so it must NOT trigger the unsaved-changes
796
+ // prompt below (that would strand the tab behind a modal). The reload path persists the
797
+ // inputs first, so nothing is lost.
798
+ let selfUpdating = false;
794
799
  // Refresh/close guard: unsaved input values live only in memory, so warn before
795
800
  // the page unloads while dirty (the browser shows its own generic confirm).
796
801
  window.addEventListener('beforeunload', (e) => {
797
- if (isInputsDirty(currentId)) { e.preventDefault(); e.returnValue = ''; }
802
+ if (!selfUpdating && isInputsDirty(currentId)) { e.preventDefault(); e.returnValue = ''; }
798
803
  });
804
+ // Persist the active app's inputs to localStorage (the new build restores them on load).
805
+ // Used before a self-update reload so an in-place adoption never drops unsaved edits.
806
+ function persistCurrentInputs() {
807
+ if (!currentId) return;
808
+ try { localStorage.setItem(lsInputsKey(currentId), JSON.stringify(appInputValues.get(currentId) || {})); } catch { /* private mode / quota */ }
809
+ }
799
810
 
800
811
  function seedAppInputs(app) {
801
812
  if (app && Array.isArray(app.inputs) && app.inputs.length) {
@@ -2613,6 +2624,7 @@
2613
2624
  }
2614
2625
  }
2615
2626
  let shownVersion = false;
2627
+ let loadedAppVersion = null; // the build this tab is running against (first health wins)
2616
2628
  function startHealthPoll() {
2617
2629
  const tick = async () => {
2618
2630
  let ok = false;
@@ -2634,6 +2646,24 @@
2634
2646
  if (h && h.webBase) webBase = h.webBase;
2635
2647
  const av = document.getElementById('app-version');
2636
2648
  if (av && h && h.appVersion && !shownVersion) { av.textContent = 'FloLess ' + h.appVersion; shownVersion = true; }
2649
+ // Adopt a self-update IN PLACE (#37): this tab loaded build X, but the server now
2650
+ // reports build Y — a self-update swapped the build under us. Reload so the tab runs
2651
+ // the NEW build's web assets (and a fresh footer + what's-new) instead of being
2652
+ // stranded on the old build's UI — stuck "Updating…", a frozen version, version skew.
2653
+ // This is what makes the post-update tab genuinely "reusable": the existing tab
2654
+ // becomes the new-version tab. Only fires on a real version change (first health sets
2655
+ // the baseline), so normal restarts / same-version polls never reload.
2656
+ if (h && h.appVersion) {
2657
+ if (loadedAppVersion === null) loadedAppVersion = h.appVersion;
2658
+ else if (h.appVersion !== loadedAppVersion) {
2659
+ // Persist unsaved inputs and suppress the beforeunload prompt (this is an
2660
+ // in-place build adoption, not the user leaving) before reloading.
2661
+ selfUpdating = true;
2662
+ persistCurrentInputs();
2663
+ location.reload();
2664
+ return;
2665
+ }
2666
+ }
2637
2667
  // After the build version is stamped, reveal the relaunch-surviving what's-new
2638
2668
  // panel iff this is the build we just self-updated into (guarded to once).
2639
2669
  maybeShowWhatsNew();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@floless/app",
3
- "version": "0.12.1",
3
+ "version": "0.12.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": {