@floless/app 0.12.0 → 0.12.1
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/floless-server.cjs +169 -128
- package/dist/web/app.css +19 -0
- package/dist/web/aware.js +45 -4
- package/dist/web/index.html +2 -1
- package/launch.mjs +11 -1
- package/package.json +1 -1
package/dist/floless-server.cjs
CHANGED
|
@@ -5489,7 +5489,7 @@ var require_thread_stream = __commonJS({
|
|
|
5489
5489
|
var { version } = require_package();
|
|
5490
5490
|
var { EventEmitter: EventEmitter2 } = require("events");
|
|
5491
5491
|
var { Worker } = require("worker_threads");
|
|
5492
|
-
var { join:
|
|
5492
|
+
var { join: join22 } = require("path");
|
|
5493
5493
|
var { pathToFileURL } = require("url");
|
|
5494
5494
|
var { wait } = require_wait();
|
|
5495
5495
|
var {
|
|
@@ -5540,7 +5540,7 @@ var require_thread_stream = __commonJS({
|
|
|
5540
5540
|
function createWorker(stream, opts) {
|
|
5541
5541
|
const { filename, workerData } = opts;
|
|
5542
5542
|
const bundlerOverrides = "__bundlerPathsOverrides" in globalThis ? globalThis.__bundlerPathsOverrides : {};
|
|
5543
|
-
const toExecute = bundlerOverrides["thread-stream-worker"] ||
|
|
5543
|
+
const toExecute = bundlerOverrides["thread-stream-worker"] || join22(__dirname, "lib", "worker.js");
|
|
5544
5544
|
const worker = new Worker(toExecute, {
|
|
5545
5545
|
...opts.workerOpts,
|
|
5546
5546
|
name: opts.workerOpts?.name || "thread-stream",
|
|
@@ -6006,9 +6006,9 @@ var require_transport = __commonJS({
|
|
|
6006
6006
|
"node_modules/pino/lib/transport.js"(exports2, module2) {
|
|
6007
6007
|
"use strict";
|
|
6008
6008
|
var { createRequire: createRequire4 } = require("module");
|
|
6009
|
-
var { existsSync:
|
|
6009
|
+
var { existsSync: existsSync20 } = require("node:fs");
|
|
6010
6010
|
var getCallers = require_caller();
|
|
6011
|
-
var { join:
|
|
6011
|
+
var { join: join22, isAbsolute: isAbsolute2, sep: sep3 } = require("node:path");
|
|
6012
6012
|
var { fileURLToPath: fileURLToPath4 } = require("node:url");
|
|
6013
6013
|
var sleep = require_atomic_sleep();
|
|
6014
6014
|
var onExit = require_on_exit_leak_free();
|
|
@@ -6080,7 +6080,7 @@ var require_transport = __commonJS({
|
|
|
6080
6080
|
return false;
|
|
6081
6081
|
}
|
|
6082
6082
|
}
|
|
6083
|
-
return isAbsolute2(path) && !
|
|
6083
|
+
return isAbsolute2(path) && !existsSync20(path);
|
|
6084
6084
|
}
|
|
6085
6085
|
function stripQuotes(value) {
|
|
6086
6086
|
const first = value[0];
|
|
@@ -6161,7 +6161,7 @@ var require_transport = __commonJS({
|
|
|
6161
6161
|
throw new Error("only one of target or targets can be specified");
|
|
6162
6162
|
}
|
|
6163
6163
|
if (targets) {
|
|
6164
|
-
target = bundlerOverrides["pino-worker"] ||
|
|
6164
|
+
target = bundlerOverrides["pino-worker"] || join22(__dirname, "worker.js");
|
|
6165
6165
|
options.targets = targets.filter((dest) => dest.target).map((dest) => {
|
|
6166
6166
|
return {
|
|
6167
6167
|
...dest,
|
|
@@ -6179,7 +6179,7 @@ var require_transport = __commonJS({
|
|
|
6179
6179
|
});
|
|
6180
6180
|
});
|
|
6181
6181
|
} else if (pipeline2) {
|
|
6182
|
-
target = bundlerOverrides["pino-worker"] ||
|
|
6182
|
+
target = bundlerOverrides["pino-worker"] || join22(__dirname, "worker.js");
|
|
6183
6183
|
options.pipelines = [pipeline2.map((dest) => {
|
|
6184
6184
|
return {
|
|
6185
6185
|
...dest,
|
|
@@ -6202,7 +6202,7 @@ var require_transport = __commonJS({
|
|
|
6202
6202
|
return origin;
|
|
6203
6203
|
}
|
|
6204
6204
|
if (origin === "pino/file") {
|
|
6205
|
-
return
|
|
6205
|
+
return join22(__dirname, "..", "file.js");
|
|
6206
6206
|
}
|
|
6207
6207
|
let fixTarget2;
|
|
6208
6208
|
for (const filePath of callers) {
|
|
@@ -7182,7 +7182,7 @@ var require_safe_stable_stringify = __commonJS({
|
|
|
7182
7182
|
return circularValue;
|
|
7183
7183
|
}
|
|
7184
7184
|
let res = "";
|
|
7185
|
-
let
|
|
7185
|
+
let join22 = ",";
|
|
7186
7186
|
const originalIndentation = indentation;
|
|
7187
7187
|
if (Array.isArray(value)) {
|
|
7188
7188
|
if (value.length === 0) {
|
|
@@ -7196,7 +7196,7 @@ var require_safe_stable_stringify = __commonJS({
|
|
|
7196
7196
|
indentation += spacer;
|
|
7197
7197
|
res += `
|
|
7198
7198
|
${indentation}`;
|
|
7199
|
-
|
|
7199
|
+
join22 = `,
|
|
7200
7200
|
${indentation}`;
|
|
7201
7201
|
}
|
|
7202
7202
|
const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
|
|
@@ -7204,13 +7204,13 @@ ${indentation}`;
|
|
|
7204
7204
|
for (; i < maximumValuesToStringify - 1; i++) {
|
|
7205
7205
|
const tmp2 = stringifyFnReplacer(String(i), value, stack, replacer, spacer, indentation);
|
|
7206
7206
|
res += tmp2 !== void 0 ? tmp2 : "null";
|
|
7207
|
-
res +=
|
|
7207
|
+
res += join22;
|
|
7208
7208
|
}
|
|
7209
7209
|
const tmp = stringifyFnReplacer(String(i), value, stack, replacer, spacer, indentation);
|
|
7210
7210
|
res += tmp !== void 0 ? tmp : "null";
|
|
7211
7211
|
if (value.length - 1 > maximumBreadth) {
|
|
7212
7212
|
const removedKeys = value.length - maximumBreadth - 1;
|
|
7213
|
-
res += `${
|
|
7213
|
+
res += `${join22}"... ${getItemCount(removedKeys)} not stringified"`;
|
|
7214
7214
|
}
|
|
7215
7215
|
if (spacer !== "") {
|
|
7216
7216
|
res += `
|
|
@@ -7231,7 +7231,7 @@ ${originalIndentation}`;
|
|
|
7231
7231
|
let separator = "";
|
|
7232
7232
|
if (spacer !== "") {
|
|
7233
7233
|
indentation += spacer;
|
|
7234
|
-
|
|
7234
|
+
join22 = `,
|
|
7235
7235
|
${indentation}`;
|
|
7236
7236
|
whitespace = " ";
|
|
7237
7237
|
}
|
|
@@ -7245,13 +7245,13 @@ ${indentation}`;
|
|
|
7245
7245
|
const tmp = stringifyFnReplacer(key2, value, stack, replacer, spacer, indentation);
|
|
7246
7246
|
if (tmp !== void 0) {
|
|
7247
7247
|
res += `${separator}${strEscape(key2)}:${whitespace}${tmp}`;
|
|
7248
|
-
separator =
|
|
7248
|
+
separator = join22;
|
|
7249
7249
|
}
|
|
7250
7250
|
}
|
|
7251
7251
|
if (keyLength > maximumBreadth) {
|
|
7252
7252
|
const removedKeys = keyLength - maximumBreadth;
|
|
7253
7253
|
res += `${separator}"...":${whitespace}"${getItemCount(removedKeys)} not stringified"`;
|
|
7254
|
-
separator =
|
|
7254
|
+
separator = join22;
|
|
7255
7255
|
}
|
|
7256
7256
|
if (spacer !== "" && separator.length > 1) {
|
|
7257
7257
|
res = `
|
|
@@ -7292,7 +7292,7 @@ ${originalIndentation}`;
|
|
|
7292
7292
|
}
|
|
7293
7293
|
const originalIndentation = indentation;
|
|
7294
7294
|
let res = "";
|
|
7295
|
-
let
|
|
7295
|
+
let join22 = ",";
|
|
7296
7296
|
if (Array.isArray(value)) {
|
|
7297
7297
|
if (value.length === 0) {
|
|
7298
7298
|
return "[]";
|
|
@@ -7305,7 +7305,7 @@ ${originalIndentation}`;
|
|
|
7305
7305
|
indentation += spacer;
|
|
7306
7306
|
res += `
|
|
7307
7307
|
${indentation}`;
|
|
7308
|
-
|
|
7308
|
+
join22 = `,
|
|
7309
7309
|
${indentation}`;
|
|
7310
7310
|
}
|
|
7311
7311
|
const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
|
|
@@ -7313,13 +7313,13 @@ ${indentation}`;
|
|
|
7313
7313
|
for (; i < maximumValuesToStringify - 1; i++) {
|
|
7314
7314
|
const tmp2 = stringifyArrayReplacer(String(i), value[i], stack, replacer, spacer, indentation);
|
|
7315
7315
|
res += tmp2 !== void 0 ? tmp2 : "null";
|
|
7316
|
-
res +=
|
|
7316
|
+
res += join22;
|
|
7317
7317
|
}
|
|
7318
7318
|
const tmp = stringifyArrayReplacer(String(i), value[i], stack, replacer, spacer, indentation);
|
|
7319
7319
|
res += tmp !== void 0 ? tmp : "null";
|
|
7320
7320
|
if (value.length - 1 > maximumBreadth) {
|
|
7321
7321
|
const removedKeys = value.length - maximumBreadth - 1;
|
|
7322
|
-
res += `${
|
|
7322
|
+
res += `${join22}"... ${getItemCount(removedKeys)} not stringified"`;
|
|
7323
7323
|
}
|
|
7324
7324
|
if (spacer !== "") {
|
|
7325
7325
|
res += `
|
|
@@ -7332,7 +7332,7 @@ ${originalIndentation}`;
|
|
|
7332
7332
|
let whitespace = "";
|
|
7333
7333
|
if (spacer !== "") {
|
|
7334
7334
|
indentation += spacer;
|
|
7335
|
-
|
|
7335
|
+
join22 = `,
|
|
7336
7336
|
${indentation}`;
|
|
7337
7337
|
whitespace = " ";
|
|
7338
7338
|
}
|
|
@@ -7341,7 +7341,7 @@ ${indentation}`;
|
|
|
7341
7341
|
const tmp = stringifyArrayReplacer(key2, value[key2], stack, replacer, spacer, indentation);
|
|
7342
7342
|
if (tmp !== void 0) {
|
|
7343
7343
|
res += `${separator}${strEscape(key2)}:${whitespace}${tmp}`;
|
|
7344
|
-
separator =
|
|
7344
|
+
separator = join22;
|
|
7345
7345
|
}
|
|
7346
7346
|
}
|
|
7347
7347
|
if (spacer !== "" && separator.length > 1) {
|
|
@@ -7399,20 +7399,20 @@ ${originalIndentation}`;
|
|
|
7399
7399
|
indentation += spacer;
|
|
7400
7400
|
let res2 = `
|
|
7401
7401
|
${indentation}`;
|
|
7402
|
-
const
|
|
7402
|
+
const join23 = `,
|
|
7403
7403
|
${indentation}`;
|
|
7404
7404
|
const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
|
|
7405
7405
|
let i = 0;
|
|
7406
7406
|
for (; i < maximumValuesToStringify - 1; i++) {
|
|
7407
7407
|
const tmp2 = stringifyIndent(String(i), value[i], stack, spacer, indentation);
|
|
7408
7408
|
res2 += tmp2 !== void 0 ? tmp2 : "null";
|
|
7409
|
-
res2 +=
|
|
7409
|
+
res2 += join23;
|
|
7410
7410
|
}
|
|
7411
7411
|
const tmp = stringifyIndent(String(i), value[i], stack, spacer, indentation);
|
|
7412
7412
|
res2 += tmp !== void 0 ? tmp : "null";
|
|
7413
7413
|
if (value.length - 1 > maximumBreadth) {
|
|
7414
7414
|
const removedKeys = value.length - maximumBreadth - 1;
|
|
7415
|
-
res2 += `${
|
|
7415
|
+
res2 += `${join23}"... ${getItemCount(removedKeys)} not stringified"`;
|
|
7416
7416
|
}
|
|
7417
7417
|
res2 += `
|
|
7418
7418
|
${originalIndentation}`;
|
|
@@ -7428,16 +7428,16 @@ ${originalIndentation}`;
|
|
|
7428
7428
|
return '"[Object]"';
|
|
7429
7429
|
}
|
|
7430
7430
|
indentation += spacer;
|
|
7431
|
-
const
|
|
7431
|
+
const join22 = `,
|
|
7432
7432
|
${indentation}`;
|
|
7433
7433
|
let res = "";
|
|
7434
7434
|
let separator = "";
|
|
7435
7435
|
let maximumPropertiesToStringify = Math.min(keyLength, maximumBreadth);
|
|
7436
7436
|
if (isTypedArrayWithEntries(value)) {
|
|
7437
|
-
res += stringifyTypedArray(value,
|
|
7437
|
+
res += stringifyTypedArray(value, join22, maximumBreadth);
|
|
7438
7438
|
keys = keys.slice(value.length);
|
|
7439
7439
|
maximumPropertiesToStringify -= value.length;
|
|
7440
|
-
separator =
|
|
7440
|
+
separator = join22;
|
|
7441
7441
|
}
|
|
7442
7442
|
if (deterministic) {
|
|
7443
7443
|
keys = sort(keys, comparator);
|
|
@@ -7448,13 +7448,13 @@ ${indentation}`;
|
|
|
7448
7448
|
const tmp = stringifyIndent(key2, value[key2], stack, spacer, indentation);
|
|
7449
7449
|
if (tmp !== void 0) {
|
|
7450
7450
|
res += `${separator}${strEscape(key2)}: ${tmp}`;
|
|
7451
|
-
separator =
|
|
7451
|
+
separator = join22;
|
|
7452
7452
|
}
|
|
7453
7453
|
}
|
|
7454
7454
|
if (keyLength > maximumBreadth) {
|
|
7455
7455
|
const removedKeys = keyLength - maximumBreadth;
|
|
7456
7456
|
res += `${separator}"...": "${getItemCount(removedKeys)} not stringified"`;
|
|
7457
|
-
separator =
|
|
7457
|
+
separator = join22;
|
|
7458
7458
|
}
|
|
7459
7459
|
if (separator !== "") {
|
|
7460
7460
|
res = `
|
|
@@ -41991,7 +41991,7 @@ var require_send = __commonJS({
|
|
|
41991
41991
|
var { parseTokenList } = require_parseTokenList();
|
|
41992
41992
|
var { createHttpError } = require_createHttpError();
|
|
41993
41993
|
var extname2 = path.extname;
|
|
41994
|
-
var
|
|
41994
|
+
var join22 = path.join;
|
|
41995
41995
|
var normalize2 = path.normalize;
|
|
41996
41996
|
var resolve5 = path.resolve;
|
|
41997
41997
|
var sep3 = path.sep;
|
|
@@ -42078,7 +42078,7 @@ var require_send = __commonJS({
|
|
|
42078
42078
|
return { statusCode: 403 };
|
|
42079
42079
|
}
|
|
42080
42080
|
parts = path2.split(sep3);
|
|
42081
|
-
path2 = normalize2(
|
|
42081
|
+
path2 = normalize2(join22(root, path2));
|
|
42082
42082
|
} else {
|
|
42083
42083
|
if (UP_PATH_REGEXP.test(path2)) {
|
|
42084
42084
|
debug('malicious path "%s"', path2);
|
|
@@ -42361,7 +42361,7 @@ var require_send = __commonJS({
|
|
|
42361
42361
|
let err;
|
|
42362
42362
|
for (let i = 0; i < options.index.length; i++) {
|
|
42363
42363
|
const index = options.index[i];
|
|
42364
|
-
const p =
|
|
42364
|
+
const p = join22(path2, index);
|
|
42365
42365
|
const { error, stat: stat4 } = await tryStat(p);
|
|
42366
42366
|
if (error) {
|
|
42367
42367
|
err = error;
|
|
@@ -43145,8 +43145,8 @@ var require_static = __commonJS({
|
|
|
43145
43145
|
}
|
|
43146
43146
|
}
|
|
43147
43147
|
}
|
|
43148
|
-
for (const [
|
|
43149
|
-
const pathname =
|
|
43148
|
+
for (const [dirname10, rootPath] of indexDirs.entries()) {
|
|
43149
|
+
const pathname = dirname10 + (dirname10.endsWith("/") ? "" : "/");
|
|
43150
43150
|
const file = "/" + pathname.replace(prefix, "");
|
|
43151
43151
|
setUpHeadAndGet(routeOpts, pathname, file, rootPath);
|
|
43152
43152
|
if (opts.redirect === true) {
|
|
@@ -50827,9 +50827,9 @@ var import_node_readline2 = require("node:readline");
|
|
|
50827
50827
|
|
|
50828
50828
|
// index.ts
|
|
50829
50829
|
var import_node_url3 = require("node:url");
|
|
50830
|
-
var
|
|
50830
|
+
var import_node_path20 = require("node:path");
|
|
50831
50831
|
var import_node_os13 = require("node:os");
|
|
50832
|
-
var
|
|
50832
|
+
var import_node_fs21 = require("node:fs");
|
|
50833
50833
|
var import_node_child_process6 = require("node:child_process");
|
|
50834
50834
|
|
|
50835
50835
|
// log.mjs
|
|
@@ -52609,7 +52609,7 @@ function appVersion() {
|
|
|
52609
52609
|
return resolveVersion({
|
|
52610
52610
|
isSea: isSea2(),
|
|
52611
52611
|
sqVersionXml: readSqVersionXml(),
|
|
52612
|
-
define: true ? "0.12.
|
|
52612
|
+
define: true ? "0.12.1" : 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.
|
|
52622
|
+
return resolveChannel({ isSea: isSea2(), define: true ? "0.12.1" : void 0 });
|
|
52623
52623
|
}
|
|
52624
52624
|
|
|
52625
52625
|
// oauth-presets.ts
|
|
@@ -52964,6 +52964,13 @@ function writeTemplates(list) {
|
|
|
52964
52964
|
(0, import_node_fs12.renameSync)(tmp, TEMPLATES_FILE);
|
|
52965
52965
|
}
|
|
52966
52966
|
function addTemplate(input) {
|
|
52967
|
+
const list = listTemplates();
|
|
52968
|
+
if (!input.source?.nodeId && input.node.agent != null && input.node.command != null) {
|
|
52969
|
+
const dup = list.find(
|
|
52970
|
+
(t) => !t.source?.nodeId && t.node.agent === input.node.agent && t.node.command === input.node.command && t.node.kind === input.node.kind
|
|
52971
|
+
);
|
|
52972
|
+
if (dup) return dup;
|
|
52973
|
+
}
|
|
52967
52974
|
const tpl = {
|
|
52968
52975
|
id: (0, import_node_crypto4.randomUUID)(),
|
|
52969
52976
|
name: input.name.trim(),
|
|
@@ -52972,7 +52979,6 @@ function addTemplate(input) {
|
|
|
52972
52979
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
52973
52980
|
source: input.source
|
|
52974
52981
|
};
|
|
52975
|
-
const list = listTemplates();
|
|
52976
52982
|
list.push(tpl);
|
|
52977
52983
|
writeTemplates(list);
|
|
52978
52984
|
return tpl;
|
|
@@ -54026,10 +54032,39 @@ function unregisterAutostart() {
|
|
|
54026
54032
|
// updater.ts
|
|
54027
54033
|
var import_node_child_process4 = require("node:child_process");
|
|
54028
54034
|
var import_node_crypto5 = require("node:crypto");
|
|
54029
|
-
var
|
|
54035
|
+
var import_node_fs17 = require("node:fs");
|
|
54030
54036
|
var import_node_stream = require("node:stream");
|
|
54031
54037
|
var import_promises = require("node:stream/promises");
|
|
54038
|
+
var import_node_path15 = require("node:path");
|
|
54039
|
+
|
|
54040
|
+
// post-update-marker.mjs
|
|
54041
|
+
var import_node_fs16 = require("node:fs");
|
|
54032
54042
|
var import_node_path14 = require("node:path");
|
|
54043
|
+
function markerPath() {
|
|
54044
|
+
const override = (process.env.FLOLESS_POST_UPDATE_MARKER ?? "").trim();
|
|
54045
|
+
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");
|
|
54047
|
+
}
|
|
54048
|
+
function writePostUpdateMarker() {
|
|
54049
|
+
try {
|
|
54050
|
+
(0, import_node_fs16.writeFileSync)(markerPath(), (/* @__PURE__ */ new Date()).toISOString());
|
|
54051
|
+
return true;
|
|
54052
|
+
} catch {
|
|
54053
|
+
return false;
|
|
54054
|
+
}
|
|
54055
|
+
}
|
|
54056
|
+
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;
|
|
54064
|
+
}
|
|
54065
|
+
}
|
|
54066
|
+
|
|
54067
|
+
// updater.ts
|
|
54033
54068
|
var CHANNEL = "win";
|
|
54034
54069
|
var FEED_TIMEOUT_MS = 15e3;
|
|
54035
54070
|
var DOWNLOAD_TIMEOUT_MS = 3e5;
|
|
@@ -54038,13 +54073,13 @@ function currentVersion() {
|
|
|
54038
54073
|
return appVersion();
|
|
54039
54074
|
}
|
|
54040
54075
|
function installRoot() {
|
|
54041
|
-
return (0,
|
|
54076
|
+
return (0, import_node_path15.dirname)((0, import_node_path15.dirname)(process.execPath));
|
|
54042
54077
|
}
|
|
54043
54078
|
function updateExePath() {
|
|
54044
|
-
return (0,
|
|
54079
|
+
return (0, import_node_path15.join)(installRoot(), "Update.exe");
|
|
54045
54080
|
}
|
|
54046
54081
|
function packagesDir() {
|
|
54047
|
-
return (0,
|
|
54082
|
+
return (0, import_node_path15.join)(installRoot(), "packages");
|
|
54048
54083
|
}
|
|
54049
54084
|
function feedUrl() {
|
|
54050
54085
|
const env2 = (process.env.FLOLESS_UPDATE_URL ?? "").trim().replace(/\/+$/, "");
|
|
@@ -54137,22 +54172,22 @@ async function checkForUpdate() {
|
|
|
54137
54172
|
}
|
|
54138
54173
|
async function sha1OfFile(path) {
|
|
54139
54174
|
const hash = (0, import_node_crypto5.createHash)("sha1");
|
|
54140
|
-
await (0, import_promises.pipeline)((0,
|
|
54175
|
+
await (0, import_promises.pipeline)((0, import_node_fs17.createReadStream)(path), hash);
|
|
54141
54176
|
return hash.digest("hex").toUpperCase();
|
|
54142
54177
|
}
|
|
54143
54178
|
async function downloadPackage(asset) {
|
|
54144
54179
|
if (!NUPKG_NAME.test(asset.FileName)) throw new Error(`refusing suspicious package name: ${asset.FileName}`);
|
|
54145
54180
|
const want = asset.SHA1.toUpperCase();
|
|
54146
54181
|
const dir = packagesDir();
|
|
54147
|
-
(0,
|
|
54148
|
-
const dest = (0,
|
|
54149
|
-
if ((0,
|
|
54182
|
+
(0, import_node_fs17.mkdirSync)(dir, { recursive: true });
|
|
54183
|
+
const dest = (0, import_node_path15.join)(dir, asset.FileName);
|
|
54184
|
+
if ((0, import_node_fs17.existsSync)(dest) && await sha1OfFile(dest) === want) return dest;
|
|
54150
54185
|
const res = await authedFetch(`${feedUrl()}/${encodeURIComponent(asset.FileName)}`, {
|
|
54151
54186
|
redirect: "follow",
|
|
54152
54187
|
signal: AbortSignal.timeout(DOWNLOAD_TIMEOUT_MS)
|
|
54153
54188
|
});
|
|
54154
54189
|
if (!res.ok || !res.body) throw new Error(`download failed: HTTP ${res.status} for ${asset.FileName}`);
|
|
54155
|
-
await (0, import_promises.pipeline)(import_node_stream.Readable.fromWeb(res.body), (0,
|
|
54190
|
+
await (0, import_promises.pipeline)(import_node_stream.Readable.fromWeb(res.body), (0, import_node_fs17.createWriteStream)(dest));
|
|
54156
54191
|
const got = await sha1OfFile(dest);
|
|
54157
54192
|
if (got !== want) throw new Error(`SHA1 mismatch for ${asset.FileName}: feed=${want} got=${got}`);
|
|
54158
54193
|
return dest;
|
|
@@ -54161,7 +54196,7 @@ async function applyUpdate(check, opts) {
|
|
|
54161
54196
|
if (!check.supported) return { applied: false, message: check.reason ?? "auto-update not supported in this runtime" };
|
|
54162
54197
|
if (!check.updateAvailable || !check.asset) return { applied: false, message: check.reason ?? "no update available" };
|
|
54163
54198
|
const exe = updateExePath();
|
|
54164
|
-
if (!(0,
|
|
54199
|
+
if (!(0, import_node_fs17.existsSync)(exe)) {
|
|
54165
54200
|
return { applied: false, message: `Update.exe not found at ${exe} \u2014 is this a Velopack install?` };
|
|
54166
54201
|
}
|
|
54167
54202
|
const pkg = await downloadPackage(check.asset);
|
|
@@ -54179,6 +54214,7 @@ async function applyUpdate(check, opts) {
|
|
|
54179
54214
|
resolve5();
|
|
54180
54215
|
});
|
|
54181
54216
|
});
|
|
54217
|
+
writePostUpdateMarker();
|
|
54182
54218
|
return { applied: true, message: `updating to v${check.targetVersion}\u2026 the app will relaunch` };
|
|
54183
54219
|
}
|
|
54184
54220
|
|
|
@@ -54369,12 +54405,12 @@ function isTraceCorrupt(events) {
|
|
|
54369
54405
|
|
|
54370
54406
|
// launch.mjs
|
|
54371
54407
|
var import_node_child_process5 = require("node:child_process");
|
|
54372
|
-
var
|
|
54408
|
+
var import_node_path16 = require("node:path");
|
|
54373
54409
|
var import_node_url = require("node:url");
|
|
54374
|
-
var
|
|
54410
|
+
var import_node_fs18 = require("node:fs");
|
|
54375
54411
|
var import_node_http = __toESM(require("node:http"), 1);
|
|
54376
54412
|
var import_node_readline = require("node:readline");
|
|
54377
|
-
var __dirname2 = (0,
|
|
54413
|
+
var __dirname2 = (0, import_node_path16.dirname)((0, import_node_url.fileURLToPath)(__import_meta_url));
|
|
54378
54414
|
var PORT = Number(process.env.PORT ?? 4317);
|
|
54379
54415
|
var HEALTH_URL = `http://127.0.0.1:${PORT}/api/health`;
|
|
54380
54416
|
var BROWSER_URL = `http://floless.localhost:${PORT}`;
|
|
@@ -54446,8 +54482,8 @@ async function waitHealthy(timeoutMs = 3e4) {
|
|
|
54446
54482
|
function resolveServerStart() {
|
|
54447
54483
|
const packaged = /flolessapp\.exe$/i.test(process.execPath);
|
|
54448
54484
|
if (packaged) return { cmd: process.execPath, args: ["--serve"], shell: false };
|
|
54449
|
-
const bundle = (0,
|
|
54450
|
-
if ((0,
|
|
54485
|
+
const bundle = (0, import_node_path16.join)(__dirname2, "dist", "floless-server.cjs");
|
|
54486
|
+
if ((0, import_node_fs18.existsSync)(bundle)) return { cmd: process.execPath, args: [bundle, "--serve"], shell: false };
|
|
54451
54487
|
return { cmd: "npm", args: ["run", "start"], shell: isWin2 };
|
|
54452
54488
|
}
|
|
54453
54489
|
function startServerDetached() {
|
|
@@ -54495,6 +54531,7 @@ async function ensureServerUp() {
|
|
|
54495
54531
|
log("server up");
|
|
54496
54532
|
}
|
|
54497
54533
|
async function cmdOpen() {
|
|
54534
|
+
const postUpdate = consumePostUpdateMarker();
|
|
54498
54535
|
if (await ping()) {
|
|
54499
54536
|
const running = await probeVersion();
|
|
54500
54537
|
if (shouldTakeOver(running, _selfVersion)) {
|
|
@@ -54503,11 +54540,15 @@ async function cmdOpen() {
|
|
|
54503
54540
|
await new Promise((r) => setTimeout(r, 500));
|
|
54504
54541
|
await ensureServerUp();
|
|
54505
54542
|
} else {
|
|
54506
|
-
log(`already running${running ? ` (v${running})` : ""}
|
|
54543
|
+
log(`already running${running ? ` (v${running})` : ""}`);
|
|
54507
54544
|
}
|
|
54508
54545
|
} else {
|
|
54509
54546
|
await ensureServerUp();
|
|
54510
54547
|
}
|
|
54548
|
+
if (postUpdate) {
|
|
54549
|
+
log("post-update relaunch \u2014 server up; the existing tab reconnects via its health poll (no new tab)");
|
|
54550
|
+
return;
|
|
54551
|
+
}
|
|
54511
54552
|
log(`opening ${BROWSER_URL}`);
|
|
54512
54553
|
openBrowser2(BROWSER_URL);
|
|
54513
54554
|
}
|
|
@@ -54595,8 +54636,8 @@ function taskkillArgs(pid, { tree = true } = {}) {
|
|
|
54595
54636
|
}
|
|
54596
54637
|
function killSupervisor({ tree = true } = {}) {
|
|
54597
54638
|
if (!isWin2) return;
|
|
54598
|
-
const isNpmChannel = /^node(\.exe)?$/i.test((0,
|
|
54599
|
-
const scriptMatch = isNpmChannel ? (0,
|
|
54639
|
+
const isNpmChannel = /^node(\.exe)?$/i.test((0, import_node_path16.basename)(process.execPath));
|
|
54640
|
+
const scriptMatch = isNpmChannel ? (0, import_node_path16.basename)((0, import_node_url.fileURLToPath)(__import_meta_url)) : void 0;
|
|
54600
54641
|
const realExe = resolveRealInstallExe(process.execPath);
|
|
54601
54642
|
const exeMatch = realExe === process.execPath ? process.execPath : [process.execPath, realExe];
|
|
54602
54643
|
const pids = supervisorPidsToKill(enumerateProcesses(), process.pid, exeMatch, scriptMatch);
|
|
@@ -54761,7 +54802,7 @@ async function runAction(arg, flagArgv = [], selfVersion = null) {
|
|
|
54761
54802
|
}
|
|
54762
54803
|
await action(parseTeardownFlags(flagArgv));
|
|
54763
54804
|
}
|
|
54764
|
-
var entry = (0,
|
|
54805
|
+
var entry = (0, import_node_path16.basename)(process.argv[1] ?? "").toLowerCase();
|
|
54765
54806
|
if (entry === "launch.mjs") {
|
|
54766
54807
|
runAction(process.argv[2], process.argv.slice(3)).catch((e) => {
|
|
54767
54808
|
log(`error: ${e?.message ?? e}`);
|
|
@@ -54835,9 +54876,9 @@ function awareUpgradeBlockReason(s) {
|
|
|
54835
54876
|
}
|
|
54836
54877
|
|
|
54837
54878
|
// skill-sync.ts
|
|
54838
|
-
var
|
|
54879
|
+
var import_node_fs19 = require("node:fs");
|
|
54839
54880
|
var import_node_os11 = require("node:os");
|
|
54840
|
-
var
|
|
54881
|
+
var import_node_path17 = require("node:path");
|
|
54841
54882
|
var import_node_url2 = require("node:url");
|
|
54842
54883
|
var import_yaml5 = __toESM(require_dist6(), 1);
|
|
54843
54884
|
|
|
@@ -54862,14 +54903,14 @@ function selectShippedSkillNames(names) {
|
|
|
54862
54903
|
}
|
|
54863
54904
|
|
|
54864
54905
|
// skill-sync.ts
|
|
54865
|
-
var __dirname3 = (0,
|
|
54906
|
+
var __dirname3 = (0, import_node_path17.dirname)((0, import_node_url2.fileURLToPath)(__import_meta_url));
|
|
54866
54907
|
function bundledSkillsRoot() {
|
|
54867
54908
|
const candidates = [
|
|
54868
|
-
(0,
|
|
54869
|
-
(0,
|
|
54870
|
-
(0,
|
|
54909
|
+
(0, import_node_path17.join)(__dirname3, "skills"),
|
|
54910
|
+
(0, import_node_path17.join)((0, import_node_path17.dirname)(process.execPath), "skills"),
|
|
54911
|
+
(0, import_node_path17.join)(__dirname3, "..", ".claude", "skills")
|
|
54871
54912
|
];
|
|
54872
|
-
return candidates.find((p) => (0,
|
|
54913
|
+
return candidates.find((p) => (0, import_node_fs19.existsSync)(p)) ?? null;
|
|
54873
54914
|
}
|
|
54874
54915
|
function targetConfigDirs() {
|
|
54875
54916
|
const override = process.env.FLOLESS_SKILL_TARGETS;
|
|
@@ -54878,14 +54919,14 @@ function targetConfigDirs() {
|
|
|
54878
54919
|
}
|
|
54879
54920
|
const home = (0, import_node_os11.homedir)();
|
|
54880
54921
|
return [
|
|
54881
|
-
{ runtime: "claude", dir: (0,
|
|
54882
|
-
{ runtime: "codex", dir: (0,
|
|
54883
|
-
{ runtime: "opencode", dir: (0,
|
|
54922
|
+
{ runtime: "claude", dir: (0, import_node_path17.join)(home, ".claude") },
|
|
54923
|
+
{ runtime: "codex", dir: (0, import_node_path17.join)(home, ".codex") },
|
|
54924
|
+
{ runtime: "opencode", dir: (0, import_node_path17.join)(home, ".opencode") }
|
|
54884
54925
|
];
|
|
54885
54926
|
}
|
|
54886
54927
|
function skillVersion(skillMdPath) {
|
|
54887
54928
|
try {
|
|
54888
|
-
const text = (0,
|
|
54929
|
+
const text = (0, import_node_fs19.readFileSync)(skillMdPath, "utf8");
|
|
54889
54930
|
const m = /^---\r?\n([\s\S]*?)\r?\n---/.exec(text);
|
|
54890
54931
|
if (!m || m[1] === void 0) return null;
|
|
54891
54932
|
const fm = (0, import_yaml5.parse)(m[1]);
|
|
@@ -54925,21 +54966,21 @@ function decideAction(installed, bundled) {
|
|
|
54925
54966
|
function bundledSkills(root) {
|
|
54926
54967
|
let entries = [];
|
|
54927
54968
|
try {
|
|
54928
|
-
entries = selectShippedSkillNames((0,
|
|
54969
|
+
entries = selectShippedSkillNames((0, import_node_fs19.readdirSync)(root));
|
|
54929
54970
|
} catch {
|
|
54930
54971
|
return [];
|
|
54931
54972
|
}
|
|
54932
54973
|
const out = [];
|
|
54933
54974
|
for (const name of entries) {
|
|
54934
|
-
const dir = (0,
|
|
54975
|
+
const dir = (0, import_node_path17.join)(root, name);
|
|
54935
54976
|
let isDir = false;
|
|
54936
54977
|
try {
|
|
54937
|
-
isDir = (0,
|
|
54978
|
+
isDir = (0, import_node_fs19.statSync)(dir).isDirectory();
|
|
54938
54979
|
} catch {
|
|
54939
54980
|
isDir = false;
|
|
54940
54981
|
}
|
|
54941
54982
|
if (!isDir) continue;
|
|
54942
|
-
const v = skillVersion((0,
|
|
54983
|
+
const v = skillVersion((0, import_node_path17.join)(dir, "SKILL.md"));
|
|
54943
54984
|
if (!v) continue;
|
|
54944
54985
|
out.push({ name, dir, version: v });
|
|
54945
54986
|
}
|
|
@@ -54952,17 +54993,17 @@ function syncSkills() {
|
|
|
54952
54993
|
const skills = bundledSkills(root);
|
|
54953
54994
|
if (!skills.length) return results;
|
|
54954
54995
|
for (const { runtime, dir: cfg } of targetConfigDirs()) {
|
|
54955
|
-
if (!(0,
|
|
54956
|
-
const skillsDir = (0,
|
|
54996
|
+
if (!(0, import_node_fs19.existsSync)(cfg)) continue;
|
|
54997
|
+
const skillsDir = (0, import_node_path17.join)(cfg, "skills");
|
|
54957
54998
|
for (const s of skills) {
|
|
54958
|
-
const dest = (0,
|
|
54959
|
-
const installedMd = (0,
|
|
54960
|
-
const installed = (0,
|
|
54999
|
+
const dest = (0, import_node_path17.join)(skillsDir, s.name);
|
|
55000
|
+
const installedMd = (0, import_node_path17.join)(dest, "SKILL.md");
|
|
55001
|
+
const installed = (0, import_node_fs19.existsSync)(installedMd) ? skillVersion(installedMd) : null;
|
|
54961
55002
|
const action = decideAction(installed, s.version);
|
|
54962
55003
|
if (action === "installed" || action === "updated") {
|
|
54963
55004
|
try {
|
|
54964
|
-
if (action === "updated") (0,
|
|
54965
|
-
(0,
|
|
55005
|
+
if (action === "updated") (0, import_node_fs19.rmSync)(dest, { recursive: true, force: true });
|
|
55006
|
+
(0, import_node_fs19.cpSync)(s.dir, dest, { recursive: true });
|
|
54966
55007
|
results.push({ runtime, skill: s.name, action, from: installed, to: s.version });
|
|
54967
55008
|
} catch {
|
|
54968
55009
|
}
|
|
@@ -54976,8 +55017,8 @@ function syncSkills() {
|
|
|
54976
55017
|
|
|
54977
55018
|
// watch.ts
|
|
54978
55019
|
var import_node_os12 = require("node:os");
|
|
54979
|
-
var
|
|
54980
|
-
var
|
|
55020
|
+
var import_node_path19 = require("node:path");
|
|
55021
|
+
var import_node_fs20 = require("node:fs");
|
|
54981
55022
|
|
|
54982
55023
|
// node_modules/chokidar/esm/index.js
|
|
54983
55024
|
var import_fs2 = require("fs");
|
|
@@ -54988,7 +55029,7 @@ var sysPath2 = __toESM(require("path"), 1);
|
|
|
54988
55029
|
// node_modules/readdirp/esm/index.js
|
|
54989
55030
|
var import_promises2 = require("node:fs/promises");
|
|
54990
55031
|
var import_node_stream2 = require("node:stream");
|
|
54991
|
-
var
|
|
55032
|
+
var import_node_path18 = require("node:path");
|
|
54992
55033
|
var EntryTypes = {
|
|
54993
55034
|
FILE_TYPE: "files",
|
|
54994
55035
|
DIR_TYPE: "directories",
|
|
@@ -55063,7 +55104,7 @@ var ReaddirpStream = class extends import_node_stream2.Readable {
|
|
|
55063
55104
|
this._wantsDir = type ? DIR_TYPES.has(type) : false;
|
|
55064
55105
|
this._wantsFile = type ? FILE_TYPES.has(type) : false;
|
|
55065
55106
|
this._wantsEverything = type === EntryTypes.EVERYTHING_TYPE;
|
|
55066
|
-
this._root = (0,
|
|
55107
|
+
this._root = (0, import_node_path18.resolve)(root);
|
|
55067
55108
|
this._isDirent = !opts.alwaysStat;
|
|
55068
55109
|
this._statsProp = this._isDirent ? "dirent" : "stats";
|
|
55069
55110
|
this._rdOptions = { encoding: "utf8", withFileTypes: this._isDirent };
|
|
@@ -55134,8 +55175,8 @@ var ReaddirpStream = class extends import_node_stream2.Readable {
|
|
|
55134
55175
|
let entry2;
|
|
55135
55176
|
const basename5 = this._isDirent ? dirent.name : dirent;
|
|
55136
55177
|
try {
|
|
55137
|
-
const fullPath = (0,
|
|
55138
|
-
entry2 = { path: (0,
|
|
55178
|
+
const fullPath = (0, import_node_path18.resolve)((0, import_node_path18.join)(path, basename5));
|
|
55179
|
+
entry2 = { path: (0, import_node_path18.relative)(this._root, fullPath), fullPath, basename: basename5 };
|
|
55139
55180
|
entry2[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);
|
|
55140
55181
|
} catch (err) {
|
|
55141
55182
|
this._onError(err);
|
|
@@ -55169,7 +55210,7 @@ var ReaddirpStream = class extends import_node_stream2.Readable {
|
|
|
55169
55210
|
}
|
|
55170
55211
|
if (entryRealPathStats.isDirectory()) {
|
|
55171
55212
|
const len = entryRealPath.length;
|
|
55172
|
-
if (full.startsWith(entryRealPath) && full.substr(len, 1) ===
|
|
55213
|
+
if (full.startsWith(entryRealPath) && full.substr(len, 1) === import_node_path18.sep) {
|
|
55173
55214
|
const recursiveError = new Error(`Circular symlink detected: "${full}" points to "${entryRealPath}"`);
|
|
55174
55215
|
recursiveError.code = RECURSIVE_ERROR_CODE;
|
|
55175
55216
|
return this._onError(recursiveError);
|
|
@@ -55708,9 +55749,9 @@ var NodeFsHandler = class {
|
|
|
55708
55749
|
if (this.fsw.closed) {
|
|
55709
55750
|
return;
|
|
55710
55751
|
}
|
|
55711
|
-
const
|
|
55752
|
+
const dirname10 = sysPath.dirname(file);
|
|
55712
55753
|
const basename5 = sysPath.basename(file);
|
|
55713
|
-
const parent = this.fsw._getWatchedDir(
|
|
55754
|
+
const parent = this.fsw._getWatchedDir(dirname10);
|
|
55714
55755
|
let prevStats = stats;
|
|
55715
55756
|
if (parent.has(basename5))
|
|
55716
55757
|
return;
|
|
@@ -55737,7 +55778,7 @@ var NodeFsHandler = class {
|
|
|
55737
55778
|
prevStats = newStats2;
|
|
55738
55779
|
}
|
|
55739
55780
|
} catch (error) {
|
|
55740
|
-
this.fsw._remove(
|
|
55781
|
+
this.fsw._remove(dirname10, basename5);
|
|
55741
55782
|
}
|
|
55742
55783
|
} else if (parent.has(basename5)) {
|
|
55743
55784
|
const at = newStats.atimeMs;
|
|
@@ -56677,33 +56718,33 @@ function appIdFromLogPath(path) {
|
|
|
56677
56718
|
return i >= 0 && parts[i + 1] ? parts[i + 1] : null;
|
|
56678
56719
|
}
|
|
56679
56720
|
function samePath(a, b) {
|
|
56680
|
-
const ra = (0,
|
|
56681
|
-
const rb = (0,
|
|
56721
|
+
const ra = (0, import_node_path19.resolve)(a);
|
|
56722
|
+
const rb = (0, import_node_path19.resolve)(b);
|
|
56682
56723
|
return process.platform === "win32" ? ra.toLowerCase() === rb.toLowerCase() : ra === rb;
|
|
56683
56724
|
}
|
|
56684
56725
|
function underDir(path, dir) {
|
|
56685
|
-
const rp = (0,
|
|
56686
|
-
const rd = (0,
|
|
56726
|
+
const rp = (0, import_node_path19.resolve)(path);
|
|
56727
|
+
const rd = (0, import_node_path19.resolve)(dir);
|
|
56687
56728
|
const [p, d] = process.platform === "win32" ? [rp.toLowerCase(), rd.toLowerCase()] : [rp, rd];
|
|
56688
|
-
return p === d || p.startsWith(d +
|
|
56729
|
+
return p === d || p.startsWith(d + import_node_path19.sep);
|
|
56689
56730
|
}
|
|
56690
56731
|
function startWatcher() {
|
|
56691
|
-
const awareDir = process.env.AWARE_HOME ?? (0,
|
|
56692
|
-
const credentialsDir = (0,
|
|
56693
|
-
if (!(0,
|
|
56732
|
+
const awareDir = process.env.AWARE_HOME ?? (0, import_node_path19.join)((0, import_node_os12.homedir)(), ".aware");
|
|
56733
|
+
const credentialsDir = (0, import_node_path19.join)(awareDir, "credentials");
|
|
56734
|
+
if (!(0, import_node_fs20.existsSync)(credentialsDir)) {
|
|
56694
56735
|
try {
|
|
56695
|
-
(0,
|
|
56736
|
+
(0, import_node_fs20.mkdirSync)(credentialsDir, { recursive: true });
|
|
56696
56737
|
} catch {
|
|
56697
56738
|
}
|
|
56698
56739
|
}
|
|
56699
|
-
if (!(0,
|
|
56740
|
+
if (!(0, import_node_fs20.existsSync)(uiDir)) {
|
|
56700
56741
|
try {
|
|
56701
|
-
(0,
|
|
56742
|
+
(0, import_node_fs20.mkdirSync)(uiDir, { recursive: true });
|
|
56702
56743
|
} catch {
|
|
56703
56744
|
}
|
|
56704
56745
|
}
|
|
56705
|
-
const targets = ["apps", "logs", "credentials"].map((d) => (0,
|
|
56706
|
-
if ((0,
|
|
56746
|
+
const targets = ["apps", "logs", "credentials"].map((d) => (0, import_node_path19.join)(awareDir, d)).filter((p) => (0, import_node_fs20.existsSync)(p));
|
|
56747
|
+
if ((0, import_node_fs20.existsSync)(uiDir)) targets.push(uiDir);
|
|
56707
56748
|
if (targets.length === 0) {
|
|
56708
56749
|
return null;
|
|
56709
56750
|
}
|
|
@@ -56733,11 +56774,11 @@ function startWatcher() {
|
|
|
56733
56774
|
const isCredential = path.split(/[\\/]/).includes("credentials");
|
|
56734
56775
|
const kind = isCredential ? "credential" : path.endsWith(".jsonl") ? "trace" : path.endsWith(".lock") ? "lock" : path.endsWith(".flo") || path.endsWith(".app") ? "source" : "file";
|
|
56735
56776
|
broadcast({ type: "fs-change", kind, event, path });
|
|
56736
|
-
if (kind === "trace" && event !== "unlink" && (0,
|
|
56777
|
+
if (kind === "trace" && event !== "unlink" && (0, import_node_fs20.existsSync)(path)) {
|
|
56737
56778
|
const id = appIdFromLogPath(path);
|
|
56738
56779
|
if (!id) return;
|
|
56739
56780
|
try {
|
|
56740
|
-
broadcast({ type: "trace-file", id, runId: path.split(
|
|
56781
|
+
broadcast({ type: "trace-file", id, runId: path.split(import_node_path19.sep).pop()?.replace(/\.jsonl$/, "") ?? null, events: parseTrace((0, import_node_fs20.readFileSync)(path, "utf8")) });
|
|
56741
56782
|
} catch {
|
|
56742
56783
|
}
|
|
56743
56784
|
}
|
|
@@ -56746,10 +56787,10 @@ function startWatcher() {
|
|
|
56746
56787
|
}
|
|
56747
56788
|
|
|
56748
56789
|
// index.ts
|
|
56749
|
-
var __dirname4 = (0,
|
|
56750
|
-
var WEB_ROOT = [(0,
|
|
56751
|
-
(p) => (0,
|
|
56752
|
-
) ?? (0,
|
|
56790
|
+
var __dirname4 = (0, import_node_path20.dirname)((0, import_node_url3.fileURLToPath)(__import_meta_url));
|
|
56791
|
+
var WEB_ROOT = [(0, import_node_path20.join)(__dirname4, "web"), (0, import_node_path20.join)((0, import_node_path20.dirname)(process.execPath), "web"), (0, import_node_path20.join)(__dirname4, "..", "web")].find(
|
|
56792
|
+
(p) => (0, import_node_fs21.existsSync)(p)
|
|
56793
|
+
) ?? (0, import_node_path20.join)(__dirname4, "..", "web");
|
|
56753
56794
|
var PORT2 = Number(process.env.PORT ?? 4317);
|
|
56754
56795
|
var HOST = "127.0.0.1";
|
|
56755
56796
|
function extractReportHtml(events) {
|
|
@@ -56776,7 +56817,7 @@ function installCrashHandlers() {
|
|
|
56776
56817
|
${stack}
|
|
56777
56818
|
`;
|
|
56778
56819
|
try {
|
|
56779
|
-
(0,
|
|
56820
|
+
(0, import_node_fs21.appendFileSync)(logFilePath(), line);
|
|
56780
56821
|
} catch {
|
|
56781
56822
|
}
|
|
56782
56823
|
if (process.stderr.isTTY) process.stderr.write(line);
|
|
@@ -57121,13 +57162,13 @@ async function startServer() {
|
|
|
57121
57162
|
}
|
|
57122
57163
|
const inputs = appData.inputs.map((i) => ({ name: i.name, type: i.type }));
|
|
57123
57164
|
const baked = bakeFloSource(appData.source.text, inputs);
|
|
57124
|
-
const tmpRoot = (0,
|
|
57125
|
-
const backupDir = (0,
|
|
57126
|
-
const bakeDir = (0,
|
|
57127
|
-
(0,
|
|
57128
|
-
(0,
|
|
57165
|
+
const tmpRoot = (0, import_node_fs21.mkdtempSync)((0, import_node_path20.join)((0, import_node_os13.tmpdir)(), "floless-bake-"));
|
|
57166
|
+
const backupDir = (0, import_node_path20.join)(tmpRoot, `${id}-backup`);
|
|
57167
|
+
const bakeDir = (0, import_node_path20.join)(tmpRoot, id);
|
|
57168
|
+
(0, import_node_fs21.cpSync)(appDir(id), backupDir, { recursive: true });
|
|
57169
|
+
(0, import_node_fs21.cpSync)(appDir(id), bakeDir, { recursive: true });
|
|
57129
57170
|
const floName = appData.source.path.split(/[\\/]/).pop();
|
|
57130
|
-
(0,
|
|
57171
|
+
(0, import_node_fs21.writeFileSync)((0, import_node_path20.join)(bakeDir, floName), baked);
|
|
57131
57172
|
let appInstalled = true;
|
|
57132
57173
|
try {
|
|
57133
57174
|
await aware.uninstall(id);
|
|
@@ -57149,17 +57190,17 @@ async function startServer() {
|
|
|
57149
57190
|
throw installErr;
|
|
57150
57191
|
}
|
|
57151
57192
|
try {
|
|
57152
|
-
await aware.compile((0,
|
|
57193
|
+
await aware.compile((0, import_node_path20.join)(appDir(id), floName));
|
|
57153
57194
|
} catch (compileErr) {
|
|
57154
57195
|
app.log.warn({ id, compileErr: String(compileErr) }, "bake: post-install recompile failed (app baked but may need a manual Compile)");
|
|
57155
57196
|
}
|
|
57156
57197
|
broadcast({ type: "baked", id });
|
|
57157
57198
|
return { ok: true, id, agent: id, inputs };
|
|
57158
57199
|
} finally {
|
|
57159
|
-
if (appInstalled) (0,
|
|
57200
|
+
if (appInstalled) (0, import_node_fs21.rmSync)(tmpRoot, { recursive: true, force: true });
|
|
57160
57201
|
}
|
|
57161
57202
|
});
|
|
57162
|
-
const graftAgentsDir = () => (0,
|
|
57203
|
+
const graftAgentsDir = () => (0, import_node_path20.join)((0, import_node_os13.homedir)(), ".aware", "agents");
|
|
57163
57204
|
app.post("/api/graft/match", async (req, reply) => {
|
|
57164
57205
|
const { glob } = req.body ?? {};
|
|
57165
57206
|
if (!glob) return reply.status(400).send({ ok: false, error: "glob required" });
|
|
@@ -57176,7 +57217,7 @@ async function startServer() {
|
|
|
57176
57217
|
if (!sourceKind || !sourceRef) {
|
|
57177
57218
|
return reply.status(400).send({ ok: false, error: "sourceKind and sourceRef required" });
|
|
57178
57219
|
}
|
|
57179
|
-
const tempHome = (0,
|
|
57220
|
+
const tempHome = (0, import_node_fs21.mkdtempSync)((0, import_node_path20.join)((0, import_node_os13.tmpdir)(), "floless-graft-"));
|
|
57180
57221
|
let result;
|
|
57181
57222
|
try {
|
|
57182
57223
|
result = await aware.build({
|
|
@@ -57189,19 +57230,19 @@ async function startServer() {
|
|
|
57189
57230
|
awareHome: tempHome
|
|
57190
57231
|
});
|
|
57191
57232
|
} catch (err) {
|
|
57192
|
-
(0,
|
|
57233
|
+
(0, import_node_fs21.rmSync)(tempHome, { recursive: true, force: true });
|
|
57193
57234
|
const msg = err instanceof AwareError ? err.message : String(err?.message ?? err);
|
|
57194
57235
|
return reply.status(422).send({ ok: false, error: msg });
|
|
57195
57236
|
}
|
|
57196
57237
|
const manifest = readStagedManifest(result.agentDir);
|
|
57197
57238
|
if (!manifest) {
|
|
57198
|
-
(0,
|
|
57239
|
+
(0, import_node_fs21.rmSync)(tempHome, { recursive: true, force: true });
|
|
57199
57240
|
return reply.status(502).send({ ok: false, error: `build produced output at ${result.agentDir} but no manifest.yaml` });
|
|
57200
57241
|
}
|
|
57201
57242
|
const token = (0, import_node_crypto6.randomUUID)();
|
|
57202
57243
|
registerStage(token, tempHome, result.agentId);
|
|
57203
57244
|
const preview = buildPreview(manifest, sourceKind, sourceRef, token);
|
|
57204
|
-
if ((0,
|
|
57245
|
+
if ((0, import_node_fs21.existsSync)((0, import_node_path20.join)(graftAgentsDir(), result.agentId))) {
|
|
57205
57246
|
preview.warnings.unshift(`An agent named "${result.agentId}" is already installed \u2014 creating it will overwrite it.`);
|
|
57206
57247
|
}
|
|
57207
57248
|
return { ok: true, preview };
|
|
@@ -57220,7 +57261,7 @@ async function startServer() {
|
|
|
57220
57261
|
registerStage(stagedRef, stage.tempDir, stage.agentId);
|
|
57221
57262
|
return reply.status(409).send({ ok: false, error: err.message, agentId: stage.agentId, collision: true });
|
|
57222
57263
|
}
|
|
57223
|
-
(0,
|
|
57264
|
+
(0, import_node_fs21.rmSync)(stage.tempDir, { recursive: true, force: true });
|
|
57224
57265
|
throw err;
|
|
57225
57266
|
}
|
|
57226
57267
|
broadcast({ type: "grafted", id: stage.agentId });
|
|
@@ -57394,11 +57435,11 @@ async function startServer() {
|
|
|
57394
57435
|
app.get("/api/requests/:id/snapshot/:n", async (req, reply) => {
|
|
57395
57436
|
const n = Number.parseInt(req.params.n, 10);
|
|
57396
57437
|
const p = Number.isInteger(n) ? snapshotPathFor(req.params.id, n) : null;
|
|
57397
|
-
if (!p || !(0,
|
|
57438
|
+
if (!p || !(0, import_node_fs21.existsSync)(p)) return reply.status(404).send({ ok: false, error: "snapshot not found" });
|
|
57398
57439
|
const ext = p.split(".").pop().toLowerCase();
|
|
57399
57440
|
reply.header("Content-Type", ext === "png" ? "image/png" : ext === "webp" ? "image/webp" : "image/jpeg");
|
|
57400
57441
|
reply.header("Cache-Control", "no-store");
|
|
57401
|
-
return (0,
|
|
57442
|
+
return (0, import_node_fs21.readFileSync)(p);
|
|
57402
57443
|
});
|
|
57403
57444
|
app.post(
|
|
57404
57445
|
"/api/tweak",
|
|
@@ -57492,7 +57533,7 @@ async function startServer() {
|
|
|
57492
57533
|
warn(`last-run-status:${ref} \u2014 trace exists but couldn't be parsed (corrupt/truncated)`);
|
|
57493
57534
|
let finishedAt2 = null;
|
|
57494
57535
|
try {
|
|
57495
|
-
finishedAt2 = (0,
|
|
57536
|
+
finishedAt2 = (0, import_node_fs21.statSync)(latest.path).mtime.toISOString();
|
|
57496
57537
|
} catch {
|
|
57497
57538
|
finishedAt2 = null;
|
|
57498
57539
|
}
|
|
@@ -57502,7 +57543,7 @@ async function startServer() {
|
|
|
57502
57543
|
let finishedAt = typeof runEnd?.ts === "string" ? runEnd.ts : null;
|
|
57503
57544
|
if (!finishedAt) {
|
|
57504
57545
|
try {
|
|
57505
|
-
finishedAt = (0,
|
|
57546
|
+
finishedAt = (0, import_node_fs21.statSync)(latest.path).mtime.toISOString();
|
|
57506
57547
|
} catch {
|
|
57507
57548
|
finishedAt = null;
|
|
57508
57549
|
}
|
package/dist/web/app.css
CHANGED
|
@@ -1935,6 +1935,25 @@ body {
|
|
|
1935
1935
|
.run-state.drift { color: var(--warn); border-color: color-mix(in srgb, var(--warn) 40%, transparent); }
|
|
1936
1936
|
.run-state.uncompiled { color: var(--text-muted); border-color: var(--border-strong); }
|
|
1937
1937
|
|
|
1938
|
+
/* Header Stop — the always-reachable escape hatch during a run, regardless of whether
|
|
1939
|
+
the HTML Viewer modal is open or closed (#39). Shown only while a run is in flight.
|
|
1940
|
+
Mirrors the in-modal .overlay-stop: a quiet destructive action — warn-tinted outline
|
|
1941
|
+
that fills on hover, never a primary. Inherits the header button's size/radius/font;
|
|
1942
|
+
only the colours are overridden here. */
|
|
1943
|
+
.run-stop-btn {
|
|
1944
|
+
background: transparent;
|
|
1945
|
+
color: var(--warn);
|
|
1946
|
+
border: 1px solid color-mix(in srgb, var(--warn) 45%, transparent);
|
|
1947
|
+
font-weight: 600;
|
|
1948
|
+
letter-spacing: 0.04em;
|
|
1949
|
+
}
|
|
1950
|
+
.run-stop-btn:hover {
|
|
1951
|
+
background: color-mix(in srgb, var(--warn) 16%, transparent);
|
|
1952
|
+
border-color: var(--warn);
|
|
1953
|
+
color: var(--text);
|
|
1954
|
+
}
|
|
1955
|
+
.run-stop-btn:disabled { opacity: 0.6; cursor: default; }
|
|
1956
|
+
|
|
1938
1957
|
/* Compile-notes strip over the canvas (CONCERNS §1). These are info-level FYIs
|
|
1939
1958
|
(e.g. AWARE's read-mode-on-exec note), so they read as info — not a warning —
|
|
1940
1959
|
and collapse to a faint one-line pill so they don't eat canvas height. */
|
package/dist/web/aware.js
CHANGED
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
const $reportOpen = document.getElementById('report-open');
|
|
25
25
|
const $reportShare = document.getElementById('report-share');
|
|
26
26
|
const $reportClose = document.getElementById('report-close');
|
|
27
|
+
const $stopRunBtn = document.getElementById('stop-run-btn');
|
|
27
28
|
|
|
28
29
|
// One persistent array the inspect Execution tab reads; we mutate in place so
|
|
29
30
|
// every AGENTS[node].execution reference stays valid across re-renders.
|
|
@@ -327,7 +328,10 @@
|
|
|
327
328
|
};
|
|
328
329
|
$runState.dataset.tip = stateTips[app.runState] || '';
|
|
329
330
|
|
|
330
|
-
|
|
331
|
+
// Keep Run disabled (and the header Stop shown) if a gate re-paint lands mid-run (#39) —
|
|
332
|
+
// never let a re-render re-arm Run while a run is still in flight.
|
|
333
|
+
$runBtn.disabled = !app.runnable || reportRunning || state.running;
|
|
334
|
+
if ($stopRunBtn) $stopRunBtn.hidden = !(reportRunning || state.running);
|
|
331
335
|
$runBtn.dataset.tip = app.runnable
|
|
332
336
|
? 'Run the approved workflow'
|
|
333
337
|
: app.runState === 'drift'
|
|
@@ -896,6 +900,35 @@
|
|
|
896
900
|
// double-click LOAD the last result instantly instead of re-running.
|
|
897
901
|
const lastReportByApp = new Map();
|
|
898
902
|
|
|
903
|
+
// Reflect run-in-flight state in the ALWAYS-VISIBLE header so a run is stoppable even
|
|
904
|
+
// when the HTML Viewer modal is closed (#39). The header ■ Stop run appears for the whole
|
|
905
|
+
// duration of either run path (the modal run `reportRunning` and the inline run
|
|
906
|
+
// `state.running`) and disappears when neither is active. Run stays disabled while a run
|
|
907
|
+
// is in flight; when idle it falls back to the compile-gate's runnable state. Also tells
|
|
908
|
+
// the user, on the modal's × tooltip, that closing leaves the run going (Stop is in the
|
|
909
|
+
// header) — the canvas keeps showing progress (markCanvasRunning), by design.
|
|
910
|
+
function syncRunControls() {
|
|
911
|
+
const running = reportRunning || state.running;
|
|
912
|
+
if ($stopRunBtn) {
|
|
913
|
+
$stopRunBtn.hidden = !running;
|
|
914
|
+
// Reset to a fresh, clickable Stop each run; stopRun() flips it to "Cancelling…".
|
|
915
|
+
if (running && !cancelRequested) { $stopRunBtn.disabled = false; $stopRunBtn.textContent = '■ Stop run'; }
|
|
916
|
+
}
|
|
917
|
+
if (running) {
|
|
918
|
+
$runBtn.disabled = true;
|
|
919
|
+
} else {
|
|
920
|
+
const app = currentId && apps.get(currentId);
|
|
921
|
+
$runBtn.disabled = !(app && app.runnable);
|
|
922
|
+
}
|
|
923
|
+
// Rely on the native `disabled` attribute for AT state (paintGate also flips it); a
|
|
924
|
+
// separate aria-disabled would be redundant and could go stale on a gate re-paint.
|
|
925
|
+
if ($reportClose) {
|
|
926
|
+
$reportClose.dataset.tip = reportRunning
|
|
927
|
+
? 'Close viewer (the run keeps going — ■ Stop run is in the header)'
|
|
928
|
+
: 'Close';
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
|
|
899
932
|
// Stop the in-flight run (the escape hatch for a hung/unattached host). Marks
|
|
900
933
|
// cancelRequested so the catch shows "cancelled", clears the canvas running
|
|
901
934
|
// pulse, and asks the server to kill the `aware app run` child. The in-flight
|
|
@@ -904,8 +937,10 @@
|
|
|
904
937
|
if (!reportRunning && !state.running) return;
|
|
905
938
|
cancelRequested = true;
|
|
906
939
|
clearNodeStatus();
|
|
940
|
+
// Reflect "cancelling" on BOTH Stop surfaces — the in-modal overlay and the header.
|
|
907
941
|
const stopBtn = document.querySelector('.overlay-stop');
|
|
908
942
|
if (stopBtn) { stopBtn.disabled = true; stopBtn.textContent = 'Cancelling…'; }
|
|
943
|
+
if ($stopRunBtn) { $stopRunBtn.disabled = true; $stopRunBtn.textContent = 'Cancelling…'; }
|
|
909
944
|
try { await api('/api/run/stop', { method: 'POST' }); } catch { /* the run's own catch surfaces it */ }
|
|
910
945
|
}
|
|
911
946
|
|
|
@@ -946,6 +981,7 @@
|
|
|
946
981
|
reportRunning = true;
|
|
947
982
|
cancelRequested = false;
|
|
948
983
|
markCanvasRunning(); // paints behind the modal; visible once it's closed
|
|
984
|
+
syncRunControls(); // header ■ Stop run + Run disabled — reachable even if the modal is closed (#39)
|
|
949
985
|
|
|
950
986
|
const inputs = currentInputs();
|
|
951
987
|
const inputBadge = Object.entries(inputs).map(([k, v]) => `${k}=${v}`).join(' · ');
|
|
@@ -1004,6 +1040,7 @@
|
|
|
1004
1040
|
}
|
|
1005
1041
|
} finally {
|
|
1006
1042
|
reportRunning = false;
|
|
1043
|
+
syncRunControls(); // run ended — hide the header Stop, restore Run from the gate
|
|
1007
1044
|
}
|
|
1008
1045
|
}
|
|
1009
1046
|
|
|
@@ -1264,6 +1301,8 @@
|
|
|
1264
1301
|
// The Stop button is rebuilt into the overlay each run — delegate so one
|
|
1265
1302
|
// listener survives every innerHTML swap.
|
|
1266
1303
|
$reportOverlay.addEventListener('click', (e) => { if (e.target.closest('.overlay-stop')) stopRun(); });
|
|
1304
|
+
// The header ■ Stop run — the always-reachable twin of the overlay Stop (#39).
|
|
1305
|
+
if ($stopRunBtn) $stopRunBtn.onclick = () => stopRun();
|
|
1267
1306
|
$reportOpen.onclick = () => {
|
|
1268
1307
|
const html = $reportFrame.srcdoc;
|
|
1269
1308
|
if (!html) return;
|
|
@@ -2064,6 +2103,7 @@
|
|
|
2064
2103
|
$runBtn.disabled = true;
|
|
2065
2104
|
if ($simBtn) $simBtn.disabled = true;
|
|
2066
2105
|
$runBtn.textContent = '◆ Running…';
|
|
2106
|
+
syncRunControls(); // surface the header ■ Stop run for the inline (no-modal) run too (#39)
|
|
2067
2107
|
liveTrace.length = 0;
|
|
2068
2108
|
state.hasRun = true;
|
|
2069
2109
|
try {
|
|
@@ -2102,6 +2142,7 @@
|
|
|
2102
2142
|
$runBtn.disabled = false;
|
|
2103
2143
|
if ($simBtn) $simBtn.disabled = false;
|
|
2104
2144
|
$runBtn.textContent = '▶ Run workflow';
|
|
2145
|
+
syncRunControls(); // hide the header Stop; reconcile Run with the gate's runnable state
|
|
2105
2146
|
}
|
|
2106
2147
|
}
|
|
2107
2148
|
$runBtn.onclick = () => runApp({ simulate: false });
|
|
@@ -2592,7 +2633,7 @@
|
|
|
2592
2633
|
// (popover + what's-new). Empty until /api/health reports it → links omitted.
|
|
2593
2634
|
if (h && h.webBase) webBase = h.webBase;
|
|
2594
2635
|
const av = document.getElementById('app-version');
|
|
2595
|
-
if (av && h && h.appVersion && !shownVersion) { av.textContent = '
|
|
2636
|
+
if (av && h && h.appVersion && !shownVersion) { av.textContent = 'FloLess ' + h.appVersion; shownVersion = true; }
|
|
2596
2637
|
// After the build version is stamped, reveal the relaunch-surviving what's-new
|
|
2597
2638
|
// panel iff this is the build we just self-updated into (guarded to once).
|
|
2598
2639
|
maybeShowWhatsNew();
|
|
@@ -3716,7 +3757,7 @@
|
|
|
3716
3757
|
riAwareVersion = h.awareVersion || '';
|
|
3717
3758
|
const app = currentId && apps.get(currentId);
|
|
3718
3759
|
const wf = app ? ` · workflow "${app.displayName || currentId}"` : '';
|
|
3719
|
-
$riContext.textContent = `Also sent automatically: FloLess
|
|
3760
|
+
$riContext.textContent = `Also sent automatically: FloLess ${h.appVersion || '?'}, AWARE ${h.awareVersion || '?'}${wf}`;
|
|
3720
3761
|
}).catch(() => { /* keep the generic line on a health blip */ });
|
|
3721
3762
|
showModal($riModal);
|
|
3722
3763
|
setTimeout(() => $riTitle.focus(), 0);
|
|
@@ -3971,7 +4012,7 @@
|
|
|
3971
4012
|
// /api/health is un-gated, so this works even while unlicensed.
|
|
3972
4013
|
fetch('/api/health', { cache: 'no-store' })
|
|
3973
4014
|
.then((r) => r.json())
|
|
3974
|
-
.then((h) => { if (h && h.appVersion) document.getElementById('lg-version').textContent = '
|
|
4015
|
+
.then((h) => { if (h && h.appVersion) document.getElementById('lg-version').textContent = 'FloLess ' + h.appVersion; })
|
|
3975
4016
|
.catch(() => { /* version is a nicety; never block the gate on it */ });
|
|
3976
4017
|
document.getElementById('lg-signin').onclick = async () => {
|
|
3977
4018
|
const s = document.getElementById('lg-status');
|
package/dist/web/index.html
CHANGED
|
@@ -60,10 +60,11 @@
|
|
|
60
60
|
<button id="browse-btn" data-tip="Browse all installed agents">⊞ Agents</button>
|
|
61
61
|
<button id="routines-btn" data-tip="Routines — run a workflow on a schedule or a live trigger">⏱ Routines</button>
|
|
62
62
|
<span class="ctl-sep" aria-hidden="true"></span>
|
|
63
|
-
<span class="run-state" id="run-state"></span>
|
|
63
|
+
<span class="run-state" id="run-state" role="status" aria-live="polite"></span>
|
|
64
64
|
<button id="compile-btn" data-tip="Compile + approve → freeze the .lock">⎙ Compile</button>
|
|
65
65
|
<button id="sim-btn" data-tip="Simulate: stub every node from its output schema — no live host is contacted. Validates the workflow's composition end-to-end, even when the real agents aren't connected yet.">Simulate</button>
|
|
66
66
|
<button id="run-btn" data-tip="Run the workflow for real against the live host (uses the inputs; renders the report node in the HTML Viewer)">▶ Run workflow</button>
|
|
67
|
+
<button id="stop-run-btn" class="run-stop-btn" type="button" aria-label="Stop the current run" data-tip="Stop the in-flight run (always reachable, even with the HTML Viewer closed)" hidden>■ Stop run</button>
|
|
67
68
|
</div>
|
|
68
69
|
</header>
|
|
69
70
|
|
package/launch.mjs
CHANGED
|
@@ -17,6 +17,7 @@ import { createInterface } from 'node:readline';
|
|
|
17
17
|
import { rotateLog, openLogFd } from './log.mjs';
|
|
18
18
|
import { supervisorPidsToKill, teardownDecision, awareIsPresent, RUN_KEY, RUN_VALUE, PROTOCOL_KEY } from './teardown.mjs';
|
|
19
19
|
import { resolveRealInstallExe } from './install-path.mjs';
|
|
20
|
+
import { consumePostUpdateMarker } from './post-update-marker.mjs';
|
|
20
21
|
|
|
21
22
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
22
23
|
const PORT = Number(process.env.PORT ?? 4317);
|
|
@@ -163,6 +164,11 @@ async function ensureServerUp() {
|
|
|
163
164
|
}
|
|
164
165
|
|
|
165
166
|
export async function cmdOpen() {
|
|
167
|
+
// A post-self-update relaunch must start the server but NOT open a second browser tab —
|
|
168
|
+
// Velopack relaunches FlolessApp.exe bare (→ this `open` action), while the user's existing
|
|
169
|
+
// tab is still alive and reconnects via its 5s health poll (#37). Consume the one-shot
|
|
170
|
+
// marker the updater dropped before the Update.exe handoff; if present, behave like `start`.
|
|
171
|
+
const postUpdate = consumePostUpdateMarker();
|
|
166
172
|
if (await ping()) {
|
|
167
173
|
// Something is already serving the port. If it's a DIFFERENT, OLDER floless.app build than
|
|
168
174
|
// this one, take it over ("newest wins") so the version the user just launched is the one
|
|
@@ -174,11 +180,15 @@ export async function cmdOpen() {
|
|
|
174
180
|
await new Promise((r) => setTimeout(r, 500)); // let the OS release the port
|
|
175
181
|
await ensureServerUp();
|
|
176
182
|
} else {
|
|
177
|
-
log(`already running${running ? ` (v${running})` : ''}
|
|
183
|
+
log(`already running${running ? ` (v${running})` : ''}`);
|
|
178
184
|
}
|
|
179
185
|
} else {
|
|
180
186
|
await ensureServerUp();
|
|
181
187
|
}
|
|
188
|
+
if (postUpdate) {
|
|
189
|
+
log('post-update relaunch — server up; the existing tab reconnects via its health poll (no new tab)');
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
182
192
|
log(`opening ${BROWSER_URL}`);
|
|
183
193
|
openBrowser(BROWSER_URL);
|
|
184
194
|
}
|