@floless/app 0.70.0 → 0.72.0

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.
@@ -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: Worker2 } = require("worker_threads");
5492
- var { join: join30 } = require("path");
5492
+ var { join: join31 } = 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"] || join30(__dirname, "lib", "worker.js");
5543
+ const toExecute = bundlerOverrides["thread-stream-worker"] || join31(__dirname, "lib", "worker.js");
5544
5544
  const worker = new Worker2(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: createRequire5 } = require("module");
6009
- var { existsSync: existsSync26 } = require("node:fs");
6009
+ var { existsSync: existsSync27 } = require("node:fs");
6010
6010
  var getCallers = require_caller();
6011
- var { join: join30, isAbsolute: isAbsolute2, sep: sep4 } = require("node:path");
6011
+ var { join: join31, isAbsolute: isAbsolute2, sep: sep4 } = require("node:path");
6012
6012
  var { fileURLToPath: fileURLToPath6 } = 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) && !existsSync26(path);
6083
+ return isAbsolute2(path) && !existsSync27(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"] || join30(__dirname, "worker.js");
6164
+ target = bundlerOverrides["pino-worker"] || join31(__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"] || join30(__dirname, "worker.js");
6182
+ target = bundlerOverrides["pino-worker"] || join31(__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 join30(__dirname, "..", "file.js");
6205
+ return join31(__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 join30 = ",";
7185
+ let join31 = ",";
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
- join30 = `,
7199
+ join31 = `,
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 += join30;
7207
+ res += join31;
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 += `${join30}"... ${getItemCount(removedKeys)} not stringified"`;
7213
+ res += `${join31}"... ${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
- join30 = `,
7234
+ join31 = `,
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 = join30;
7248
+ separator = join31;
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 = join30;
7254
+ separator = join31;
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 join30 = ",";
7295
+ let join31 = ",";
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
- join30 = `,
7308
+ join31 = `,
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 += join30;
7316
+ res += join31;
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 += `${join30}"... ${getItemCount(removedKeys)} not stringified"`;
7322
+ res += `${join31}"... ${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
- join30 = `,
7335
+ join31 = `,
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 = join30;
7344
+ separator = join31;
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 join31 = `,
7402
+ const join32 = `,
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 += join31;
7409
+ res2 += join32;
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 += `${join31}"... ${getItemCount(removedKeys)} not stringified"`;
7415
+ res2 += `${join32}"... ${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 join30 = `,
7431
+ const join31 = `,
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, join30, maximumBreadth);
7437
+ res += stringifyTypedArray(value, join31, maximumBreadth);
7438
7438
  keys = keys.slice(value.length);
7439
7439
  maximumPropertiesToStringify -= value.length;
7440
- separator = join30;
7440
+ separator = join31;
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 = join30;
7451
+ separator = join31;
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 = join30;
7457
+ separator = join31;
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 extname3 = path.extname;
41994
- var join30 = path.join;
41994
+ var join31 = path.join;
41995
41995
  var normalize2 = path.normalize;
41996
41996
  var resolve6 = path.resolve;
41997
41997
  var sep4 = path.sep;
@@ -42078,7 +42078,7 @@ var require_send = __commonJS({
42078
42078
  return { statusCode: 403 };
42079
42079
  }
42080
42080
  parts = path2.split(sep4);
42081
- path2 = normalize2(join30(root, path2));
42081
+ path2 = normalize2(join31(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 err2;
42362
42362
  for (let i = 0; i < options.index.length; i++) {
42363
42363
  const index = options.index[i];
42364
- const p = join30(path2, index);
42364
+ const p = join31(path2, index);
42365
42365
  const { error, stat: stat4 } = await tryStat(p);
42366
42366
  if (error) {
42367
42367
  err2 = error;
@@ -43145,8 +43145,8 @@ var require_static = __commonJS({
43145
43145
  }
43146
43146
  }
43147
43147
  }
43148
- for (const [dirname14, rootPath] of indexDirs.entries()) {
43149
- const pathname = dirname14 + (dirname14.endsWith("/") ? "" : "/");
43148
+ for (const [dirname15, rootPath] of indexDirs.entries()) {
43149
+ const pathname = dirname15 + (dirname15.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_url5 = require("node:url");
50830
- var import_node_path29 = require("node:path");
50831
- var import_node_os20 = require("node:os");
50832
- var import_node_fs31 = require("node:fs");
50830
+ var import_node_path30 = require("node:path");
50831
+ var import_node_os21 = require("node:os");
50832
+ var import_node_fs32 = require("node:fs");
50833
50833
  var import_node_child_process8 = require("node:child_process");
50834
50834
 
50835
50835
  // log.mjs
@@ -53022,7 +53022,7 @@ function appVersion() {
53022
53022
  return resolveVersion({
53023
53023
  isSea: isSea2(),
53024
53024
  sqVersionXml: readSqVersionXml(),
53025
- define: true ? "0.70.0" : void 0,
53025
+ define: true ? "0.72.0" : void 0,
53026
53026
  pkgVersion: readPkgVersion()
53027
53027
  });
53028
53028
  }
@@ -53032,7 +53032,7 @@ function resolveChannel(s) {
53032
53032
  return "dev";
53033
53033
  }
53034
53034
  function appChannel() {
53035
- return resolveChannel({ isSea: isSea2(), define: true ? "0.70.0" : void 0 });
53035
+ return resolveChannel({ isSea: isSea2(), define: true ? "0.72.0" : void 0 });
53036
53036
  }
53037
53037
 
53038
53038
  // workflow-update.ts
@@ -53395,7 +53395,7 @@ function extractSavedPath(events) {
53395
53395
  var aisc_shapes_default = { "C10X15.3": 2.6, C10X20: 2.74, C10X25: 2.89, C10X30: 3.03, "C12X20.7": 2.94, C12X25: 3.05, C12X30: 3.17, "C15X33.9": 3.4, C15X40: 3.52, C15X50: 3.72, "C3X3.5": 1.37, "C3X4.1": 1.41, C3X5: 1.5, C3X6: 1.6, "C4X4.5": 1.52, "C4X5.4": 1.58, "C4X6.25": 1.65, "C4X7.25": 1.72, "C5X6.7": 1.75, C5X9: 1.89, "C6X10.5": 2.03, C6X13: 2.16, "C6X8.2": 1.92, "C7X12.25": 2.19, "C7X14.75": 2.3, "C7X9.8": 2.09, "C8X11.5": 2.26, "C8X13.75": 2.34, "C8X18.75": 2.53, "C9X13.4": 2.43, C9X15: 2.49, C9X20: 2.65, HP10X42: 10.1, HP10X57: 10.2, HP12X53: 12, HP12X63: 12.1, HP12X74: 12.2, HP12X84: 12.3, HP12X89: 12.3, HP14X102: 14.8, HP14X117: 14.9, HP14X73: 14.6, HP14X89: 14.7, HP16X101: 15.8, HP16X121: 15.9, HP16X141: 16, HP16X162: 16.1, HP16X183: 16.3, HP16X88: 15.7, HP18X135: 17.8, HP18X157: 17.9, HP18X181: 18, HP18X204: 18.1, HP8X36: 8.16, "M10X7.5": 2.69, M10X8: 2.69, M10X9: 2.69, "M12.5X11.6": 3.5, "M12.5X12.4": 3.75, M12X10: 3.25, "M12X10.8": 3.07, "M12X11.8": 3.07, "M3X2.9": 2.25, "M4X3.2": 2.25, "M4X3.45": 2.25, "M4X4.08": 2.25, M4X6: 3.8, "M5X18.9": 5, "M6X3.7": 2, "M6X4.4": 1.84, "M8X6.2": 2.28, "M8X6.5": 2.28, MC10X22: 3.32, MC10X25: 3.41, "MC10X28.5": 3.95, "MC10X33.6": 4.1, "MC10X41.1": 4.32, "MC10X6.5": 1.17, "MC10X8.4": 1.5, "MC12X10.6": 1.5, "MC12X14.3": 2.12, MC12X31: 3.67, MC12X35: 3.77, MC12X40: 3.89, MC12X45: 4.01, MC12X50: 4.14, "MC13X31.8": 4, MC13X35: 4.07, MC13X40: 4.19, MC13X50: 4.41, "MC18X42.7": 3.95, "MC18X45.8": 4, "MC18X51.9": 4.1, MC18X58: 4.2, "MC3X7.1": 1.94, "MC4X13.8": 2.5, MC6X12: 2.5, "MC6X15.1": 2.94, "MC6X15.3": 3.5, "MC6X16.3": 3, MC6X18: 3.5, "MC6X6.5": 1.85, MC6X7: 1.88, "MC7X19.1": 3.45, "MC7X22.7": 3.6, "MC8X18.7": 2.98, MC8X20: 3.03, "MC8X21.4": 3.45, "MC8X22.8": 3.5, "MC8X8.5": 1.87, "MC9X23.9": 3.45, "MC9X25.4": 3.5, "MT2.5X9.45": 5, MT2X3: 3.8, "MT3X1.85": 2, "MT3X2.2": 1.84, "MT4X3.1": 2.28, "MT4X3.25": 2.28, "MT5X3.75": 2.69, MT5X4: 2.69, "MT5X4.5": 2.69, "MT6.25X5.8": 3.5, "MT6.25X6.2": 3.75, MT6X5: 3.25, "MT6X5.4": 3.07, "MT6X5.9": 3.07, "S10X25.4": 4.66, S10X35: 4.94, "S12X31.8": 5, S12X35: 5.08, "S12X40.8": 5.25, S12X50: 5.48, "S15X42.9": 5.5, S15X50: 5.64, "S18X54.7": 6, S18X70: 6.25, S20X66: 6.26, S20X75: 6.39, S20X86: 7.06, S20X96: 7.2, S24X100: 7.25, S24X106: 7.87, S24X121: 8.05, S24X80: 7, S24X90: 7.13, "S3X5.7": 2.33, "S3X7.5": 2.51, "S4X7.7": 2.66, "S4X9.5": 2.8, S5X10: 3, "S6X12.5": 3.33, "S6X17.25": 3.57, "S8X18.4": 4, S8X23: 4.17, "ST1.5X2.85": 2.33, "ST1.5X3.75": 2.51, ST10X33: 6.26, "ST10X37.5": 6.39, ST10X43: 7.06, ST10X48: 7.2, ST12X40: 7, ST12X45: 7.13, ST12X50: 7.25, ST12X53: 7.87, "ST12X60.5": 8.05, "ST2.5X5": 3, "ST2X3.85": 2.66, "ST2X4.75": 2.8, "ST3X6.25": 3.33, "ST3X8.6": 3.57, "ST4X11.5": 4.17, "ST4X9.2": 4, "ST5X12.7": 4.66, "ST5X17.5": 4.94, "ST6X15.9": 5, "ST6X17.5": 5.08, "ST6X20.4": 5.25, ST6X25: 5.48, "ST7.5X21.45": 5.5, "ST7.5X25": 5.64, "ST9X27.35": 6, ST9X35: 6.25, W10X100: 10.3, W10X112: 10.4, W10X12: 3.96, W10X15: 4, W10X17: 4.01, W10X19: 4.02, W10X22: 5.75, W10X26: 5.77, W10X30: 5.81, W10X33: 7.96, W10X39: 7.99, W10X45: 8.02, W10X49: 10, W10X54: 10, W10X60: 10.1, W10X68: 10.1, W10X77: 10.2, W10X88: 10.3, W12X106: 12.2, W12X120: 12.3, W12X136: 12.4, W12X14: 3.97, W12X152: 12.5, W12X16: 3.99, W12X170: 12.6, W12X19: 4.01, W12X190: 12.7, W12X210: 12.8, W12X22: 4.03, W12X230: 12.9, W12X252: 13, W12X26: 6.49, W12X279: 13.1, W12X30: 6.52, W12X305: 13.2, W12X336: 13.4, W12X35: 6.56, W12X40: 8.01, W12X45: 8.05, W12X50: 8.08, W12X53: 10, W12X58: 10, W12X65: 12, W12X72: 12, W12X79: 12.1, W12X87: 12.1, W12X96: 12.2, W14X109: 14.6, W14X120: 14.7, W14X132: 14.7, W14X145: 15.5, W14X159: 15.6, W14X176: 15.7, W14X193: 15.7, W14X211: 15.8, W14X22: 5, W14X233: 15.9, W14X257: 16, W14X26: 5.03, W14X283: 16.1, W14X30: 6.73, W14X311: 16.2, W14X34: 6.75, W14X342: 16.4, W14X370: 16.5, W14X38: 6.77, W14X398: 16.6, W14X426: 16.7, W14X43: 8, W14X455: 16.8, W14X48: 8.03, W14X500: 17, W14X53: 8.06, W14X550: 17.2, W14X605: 17.4, W14X61: 10, W14X665: 17.7, W14X68: 10, W14X730: 17.9, W14X74: 10.1, W14X808: 18.6, W14X82: 10.1, W14X873: 18.8, W14X90: 14.5, W14X99: 14.6, W16X100: 10.4, W16X26: 5.5, W16X31: 5.53, W16X36: 6.99, W16X40: 7, W16X45: 7.04, W16X50: 7.07, W16X57: 7.12, W16X67: 10.2, W16X77: 10.3, W16X89: 10.4, W18X106: 11.2, W18X119: 11.3, W18X130: 11.2, W18X143: 11.2, W18X158: 11.3, W18X175: 11.4, W18X192: 11.5, W18X211: 11.6, W18X234: 11.7, W18X258: 11.8, W18X283: 11.9, W18X311: 12, W18X35: 6, W18X40: 6.02, W18X46: 6.06, W18X50: 7.5, W18X55: 7.53, W18X60: 7.56, W18X65: 7.59, W18X71: 7.64, W18X76: 11, W18X86: 11.1, W18X97: 11.1, W21X101: 12.3, W21X111: 12.3, W21X122: 12.4, W21X132: 12.4, W21X147: 12.5, W21X166: 12.4, W21X182: 12.5, W21X201: 12.6, W21X223: 12.7, W21X248: 12.8, W21X275: 12.9, W21X44: 6.5, W21X48: 8.14, W21X50: 6.53, W21X55: 8.22, W21X57: 6.56, W21X62: 8.24, W21X68: 8.27, W21X73: 8.3, W21X83: 8.36, W21X93: 8.42, W24X103: 9, W24X104: 12.8, W24X117: 12.8, W24X131: 12.9, W24X146: 12.9, W24X162: 13, W24X176: 12.9, W24X192: 13, W24X207: 13, W24X229: 13.1, W24X250: 13.2, W24X279: 13.3, W24X306: 13.4, W24X335: 13.5, W24X370: 13.7, W24X55: 7.01, W24X62: 7.04, W24X68: 8.97, W24X76: 8.99, W24X84: 9.02, W24X94: 9.07, W27X102: 10, W27X114: 10.1, W27X129: 10, W27X146: 14, W27X161: 14, W27X178: 14.1, W27X194: 14, W27X217: 14.1, W27X235: 14.2, W27X258: 14.3, W27X281: 14.4, W27X307: 14.4, W27X336: 14.6, W27X368: 14.7, W27X539: 15.3, W27X84: 10, W27X94: 10, W30X108: 10.5, W30X116: 10.5, W30X124: 10.5, W30X132: 10.5, W30X148: 10.5, W30X173: 15, W30X191: 15, W30X211: 15.1, W30X235: 15.1, W30X261: 15.2, W30X292: 15.3, W30X326: 15.4, W30X357: 15.5, W30X391: 15.6, W30X90: 10.4, W30X99: 10.5, W33X118: 11.5, W33X130: 11.5, W33X141: 11.5, W33X152: 11.6, W33X169: 11.5, W33X201: 15.7, W33X221: 15.8, W33X241: 15.9, W33X263: 15.8, W33X291: 15.9, W33X318: 16, W33X354: 16.1, W33X387: 16.2, W36X135: 12, W36X150: 12, W36X160: 12, W36X170: 12, W36X182: 12.1, W36X194: 12.1, W36X210: 12.2, W36X231: 16.5, W36X232: 12.1, W36X247: 16.5, W36X256: 12.2, W36X262: 16.6, W36X282: 16.6, W36X302: 16.7, W36X330: 16.6, W36X361: 16.7, W36X395: 16.8, W36X441: 17, W36X487: 17.1, W36X529: 17.2, W36X652: 17.6, W36X723: 17.8, W36X802: 18, W36X853: 18.2, W36X925: 18.6, W40X149: 11.8, W40X167: 11.8, W40X183: 11.8, W40X199: 15.8, W40X211: 11.8, W40X215: 15.8, W40X235: 11.9, W40X249: 15.8, W40X264: 11.9, W40X277: 15.8, W40X278: 12, W40X294: 12, W40X297: 15.8, W40X324: 15.9, W40X327: 12.1, W40X331: 12.2, W40X362: 16, W40X372: 16.1, W40X392: 12.4, W40X397: 16.1, W40X431: 16.2, W40X503: 16.4, W40X593: 16.7, W40X655: 16.9, W44X230: 15.8, W44X262: 15.8, W44X290: 15.8, W44X335: 15.9, W4X13: 4.06, W5X16: 5, W5X19: 5.03, W6X12: 4, W6X15: 5.99, W6X16: 4.03, W6X20: 6.02, W6X25: 6.08, "W6X8.5": 3.94, W6X9: 3.94, W8X10: 3.94, W8X13: 4, W8X15: 4.02, W8X18: 5.25, W8X21: 5.27, W8X24: 6.5, W8X28: 6.54, W8X31: 8, W8X35: 8.02, W8X40: 8.07, W8X48: 8.11, W8X58: 8.22, W8X67: 8.28, "WT10.5X100.5": 12.6, "WT10.5X111.5": 12.7, "WT10.5X124": 12.8, "WT10.5X137.5": 12.9, "WT10.5X22": 6.5, "WT10.5X24": 8.14, "WT10.5X25": 6.53, "WT10.5X27.5": 8.22, "WT10.5X28.5": 6.56, "WT10.5X31": 8.24, "WT10.5X34": 8.27, "WT10.5X36.5": 8.3, "WT10.5X41.5": 8.36, "WT10.5X46.5": 8.42, "WT10.5X50.5": 12.3, "WT10.5X55.5": 12.3, "WT10.5X61": 12.4, "WT10.5X66": 12.4, "WT10.5X73.5": 12.5, "WT10.5X83": 12.4, "WT10.5X91": 12.5, "WT12X103.5": 13, "WT12X114.5": 13.1, WT12X125: 13.2, "WT12X139.5": 13.3, WT12X153: 13.4, "WT12X167.5": 13.5, WT12X185: 13.7, "WT12X27.5": 7.01, WT12X31: 7.04, WT12X34: 8.97, WT12X38: 8.99, WT12X42: 9.02, WT12X47: 9.07, "WT12X51.5": 9, WT12X52: 12.8, "WT12X58.5": 12.8, "WT12X65.5": 12.9, WT12X73: 12.9, WT12X81: 13, WT12X88: 12.9, WT12X96: 13, "WT13.5X108.5": 14.1, "WT13.5X117.5": 14.2, "WT13.5X129": 14.3, "WT13.5X140.5": 14.4, "WT13.5X153.5": 14.4, "WT13.5X168": 14.6, "WT13.5X184": 14.7, "WT13.5X269.5": 15.3, "WT13.5X42": 10, "WT13.5X47": 10, "WT13.5X51": 10, "WT13.5X57": 10.1, "WT13.5X64.5": 10, "WT13.5X73": 14, "WT13.5X80.5": 14, "WT13.5X89": 14.1, "WT13.5X97": 14, "WT15X105.5": 15.1, "WT15X117.5": 15.1, "WT15X130.5": 15.2, WT15X146: 15.3, WT15X163: 15.4, "WT15X178.5": 15.5, "WT15X195.5": 15.6, WT15X45: 10.4, "WT15X49.5": 10.5, WT15X54: 10.5, WT15X58: 10.5, WT15X62: 10.5, WT15X66: 10.5, WT15X74: 10.5, "WT15X86.5": 15, "WT15X95.5": 15, "WT16.5X100.5": 15.7, "WT16.5X110.5": 15.8, "WT16.5X120.5": 15.9, "WT16.5X131.5": 15.8, "WT16.5X145.5": 15.9, "WT16.5X159": 16, "WT16.5X177": 16.1, "WT16.5X193.5": 16.2, "WT16.5X59": 11.5, "WT16.5X65": 11.5, "WT16.5X70.5": 11.5, "WT16.5X76": 11.6, "WT16.5X84.5": 11.5, WT18X105: 12.2, "WT18X115.5": 16.5, WT18X116: 12.1, "WT18X123.5": 16.5, WT18X128: 12.2, WT18X131: 16.6, WT18X141: 16.6, WT18X151: 16.7, WT18X165: 16.6, "WT18X180.5": 16.7, "WT18X197.5": 16.8, "WT18X220.5": 17, "WT18X243.5": 17.1, "WT18X264.5": 17.2, WT18X326: 17.6, "WT18X361.5": 17.8, WT18X401: 18, "WT18X426.5": 18.2, "WT18X462.5": 18.6, "WT18X67.5": 12, WT18X75: 12, WT18X80: 12, WT18X85: 12, WT18X91: 12.1, WT18X97: 12.1, "WT2.5X8": 5, "WT2.5X9.5": 5.03, "WT20X105.5": 11.8, "WT20X107.5": 15.8, "WT20X117.5": 11.9, "WT20X124.5": 15.8, WT20X132: 11.9, "WT20X138.5": 15.8, WT20X139: 12, WT20X147: 12, "WT20X148.5": 15.8, WT20X162: 15.9, "WT20X163.5": 12.1, "WT20X165.5": 12.2, WT20X181: 16, WT20X186: 16.1, WT20X196: 12.4, "WT20X198.5": 16.1, "WT20X215.5": 16.2, "WT20X251.5": 16.4, "WT20X296.5": 16.7, "WT20X327.5": 16.9, "WT20X74.5": 11.8, "WT20X83.5": 11.8, "WT20X91.5": 11.8, "WT20X99.5": 15.8, WT22X115: 15.8, WT22X131: 15.8, WT22X145: 15.8, "WT22X167.5": 15.9, "WT2X6.5": 4.06, WT3X10: 6.02, "WT3X12.5": 6.08, "WT3X4.25": 3.94, "WT3X4.5": 3.94, WT3X6: 4, "WT3X7.5": 5.99, WT3X8: 4.03, "WT4X10.5": 5.27, WT4X12: 6.5, WT4X14: 6.54, "WT4X15.5": 8, "WT4X17.5": 8.02, WT4X20: 8.07, WT4X24: 8.11, WT4X29: 8.22, "WT4X33.5": 8.28, WT4X5: 3.94, "WT4X6.5": 4, "WT4X7.5": 4.02, WT4X9: 5.25, WT5X11: 5.75, WT5X13: 5.77, WT5X15: 5.81, "WT5X16.5": 7.96, "WT5X19.5": 7.99, "WT5X22.5": 8.02, "WT5X24.5": 10, WT5X27: 10, WT5X30: 10.1, WT5X34: 10.1, "WT5X38.5": 10.2, WT5X44: 10.3, WT5X50: 10.3, WT5X56: 10.4, WT5X6: 3.96, "WT5X7.5": 4, "WT5X8.5": 4.01, "WT5X9.5": 4.02, WT6X105: 12.8, WT6X11: 4.03, WT6X115: 12.9, WT6X126: 13, WT6X13: 6.49, "WT6X139.5": 13.1, WT6X15: 6.52, "WT6X152.5": 13.2, WT6X168: 13.4, "WT6X17.5": 6.56, WT6X20: 8.01, "WT6X22.5": 8.05, WT6X25: 8.08, "WT6X26.5": 10, WT6X29: 10, "WT6X32.5": 12, WT6X36: 12, "WT6X39.5": 12.1, "WT6X43.5": 12.1, WT6X48: 12.2, WT6X53: 12.2, WT6X60: 12.3, WT6X68: 12.4, WT6X7: 3.97, WT6X76: 12.5, WT6X8: 3.99, WT6X85: 12.6, "WT6X9.5": 4.01, WT6X95: 12.7, "WT7X105.5": 15.8, WT7X11: 5, "WT7X116.5": 15.9, "WT7X128.5": 16, WT7X13: 5.03, "WT7X141.5": 16.1, WT7X15: 6.73, "WT7X155.5": 16.2, WT7X17: 6.75, WT7X171: 16.4, WT7X185: 16.5, WT7X19: 6.77, WT7X199: 16.6, "WT7X21.5": 8, WT7X213: 16.7, "WT7X227.5": 16.8, WT7X24: 8.03, WT7X250: 17, "WT7X26.5": 8.06, WT7X275: 17.2, "WT7X30.5": 10, "WT7X302.5": 17.4, "WT7X332.5": 17.7, WT7X34: 10, WT7X365: 17.9, WT7X37: 10.1, WT7X404: 18.6, WT7X41: 10.1, "WT7X436.5": 18.8, WT7X45: 14.5, "WT7X49.5": 14.6, "WT7X54.5": 14.6, WT7X60: 14.7, WT7X66: 14.7, "WT7X72.5": 15.5, "WT7X79.5": 15.6, WT7X88: 15.7, "WT7X96.5": 15.7, WT8X13: 5.5, "WT8X15.5": 5.53, WT8X18: 6.99, WT8X20: 7, "WT8X22.5": 7.04, WT8X25: 7.07, "WT8X28.5": 7.12, "WT8X33.5": 10.2, "WT8X38.5": 10.3, "WT8X44.5": 10.4, WT8X50: 10.4, "WT9X105.5": 11.6, WT9X117: 11.7, WT9X129: 11.8, "WT9X141.5": 11.9, "WT9X155.5": 12, "WT9X17.5": 6, WT9X20: 6.02, WT9X23: 6.06, WT9X25: 7.5, "WT9X27.5": 7.53, WT9X30: 7.56, "WT9X32.5": 7.59, "WT9X35.5": 7.64, WT9X38: 11, WT9X43: 11.1, "WT9X48.5": 11.1, WT9X53: 11.2, "WT9X59.5": 11.3, WT9X65: 11.2, "WT9X71.5": 11.2, WT9X79: 11.3, "WT9X87.5": 11.4, WT9X96: 11.5 };
53396
53396
 
53397
53397
  // index.ts
53398
- var import_node_crypto7 = require("node:crypto");
53398
+ var import_node_crypto8 = require("node:crypto");
53399
53399
 
53400
53400
  // graft.ts
53401
53401
  var TEKLA_MARKER = "Recipe: Tekla model plug-in";
@@ -53898,11 +53898,16 @@ function safeId(appId) {
53898
53898
  if (!/^[a-z0-9][a-z0-9._-]*$/i.test(appId)) throw new ContractError(`invalid appId: ${appId}`);
53899
53899
  return appId;
53900
53900
  }
53901
- function contractPath(appId) {
53901
+ function safeProjectSeg(projectId) {
53902
+ if (!/^[a-z0-9][a-z0-9-]*$/.test(projectId)) throw new ContractError(`invalid project id: ${projectId}`);
53903
+ return projectId;
53904
+ }
53905
+ function contractPath(appId, projectId) {
53906
+ if (projectId) return (0, import_node_path16.join)(ROOT3, "projects", safeProjectSeg(projectId), "contract.json");
53902
53907
  return (0, import_node_path16.join)(DIR, `${safeId(appId)}.json`);
53903
53908
  }
53904
- function readContract(appId) {
53905
- const p = contractPath(appId);
53909
+ function readContract(appId, projectId) {
53910
+ const p = contractPath(appId, projectId);
53906
53911
  if (!(0, import_node_fs18.existsSync)(p)) return null;
53907
53912
  try {
53908
53913
  return JSON.parse((0, import_node_fs18.readFileSync)(p, "utf8"));
@@ -53911,14 +53916,18 @@ function readContract(appId) {
53911
53916
  return null;
53912
53917
  }
53913
53918
  }
53914
- function writeContract(appId, doc) {
53915
- const p = contractPath(appId);
53919
+ function writeContract(appId, doc, projectId) {
53920
+ const p = contractPath(appId, projectId);
53916
53921
  const res = validateContract(doc);
53917
53922
  if (!res.valid) {
53918
53923
  const first = res.errors.slice(0, 5).map((e) => `${e.path}: ${e.message}`).join("; ");
53919
53924
  throw new ContractError(`contract failed schema validation \u2014 ${first}`);
53920
53925
  }
53921
- if (!(0, import_node_fs18.existsSync)(DIR)) (0, import_node_fs18.mkdirSync)(DIR, { recursive: true });
53926
+ if (projectId) {
53927
+ if (!(0, import_node_fs18.existsSync)((0, import_node_path16.dirname)(p))) throw new ContractError(`unknown project: ${projectId}`);
53928
+ } else if (!(0, import_node_fs18.existsSync)(DIR)) {
53929
+ (0, import_node_fs18.mkdirSync)(DIR, { recursive: true });
53930
+ }
53922
53931
  (0, import_node_fs18.writeFileSync)(p, JSON.stringify(doc));
53923
53932
  }
53924
53933
 
@@ -53941,11 +53950,107 @@ function readContractForApp(appId, readAppFn = readApp) {
53941
53950
  return t;
53942
53951
  }
53943
53952
 
53944
- // contract-bake.ts
53953
+ // projects-store.ts
53945
53954
  var import_node_fs19 = require("node:fs");
53955
+ var import_node_path17 = require("node:path");
53956
+ var import_node_os13 = require("node:os");
53957
+ var import_node_crypto6 = require("node:crypto");
53958
+ var ProjectError = class extends Error {
53959
+ };
53960
+ var ROOT4 = process.env.FLOLESS_HOME ?? (0, import_node_path17.join)((0, import_node_os13.homedir)(), ".floless");
53961
+ var DIR2 = (0, import_node_path17.join)(ROOT4, "projects");
53962
+ var ARCHIVE = (0, import_node_path17.join)(DIR2, ".archive");
53963
+ function safeProjectId(id) {
53964
+ if (typeof id !== "string" || !/^[a-z0-9][a-z0-9-]*$/.test(id)) {
53965
+ throw new ProjectError(`invalid project id: ${String(id)}`);
53966
+ }
53967
+ return id;
53968
+ }
53969
+ function slugify(name) {
53970
+ const s = name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 40);
53971
+ return s || "project";
53972
+ }
53973
+ function projectDir(id) {
53974
+ return (0, import_node_path17.join)(DIR2, safeProjectId(id));
53975
+ }
53976
+ var metaPath = (id) => (0, import_node_path17.join)(projectDir(id), "project.json");
53977
+ function readMeta(id) {
53978
+ const p = metaPath(id);
53979
+ if (!(0, import_node_fs19.existsSync)(p)) return null;
53980
+ try {
53981
+ const meta = JSON.parse((0, import_node_fs19.readFileSync)(p, "utf8"));
53982
+ return meta && meta.id === id ? meta : null;
53983
+ } catch (e) {
53984
+ console.warn(`projects-store: ignoring unreadable project.json at ${p}: ${e instanceof Error ? e.message : e}`);
53985
+ return null;
53986
+ }
53987
+ }
53988
+ var writeMeta = (meta) => (0, import_node_fs19.writeFileSync)(metaPath(meta.id), JSON.stringify(meta, null, 2));
53989
+ function listProjects() {
53990
+ if (!(0, import_node_fs19.existsSync)(DIR2)) return [];
53991
+ const out = [];
53992
+ for (const entry2 of (0, import_node_fs19.readdirSync)(DIR2, { withFileTypes: true })) {
53993
+ if (!entry2.isDirectory() || entry2.name.startsWith(".")) continue;
53994
+ const meta = readMeta(entry2.name);
53995
+ if (meta) out.push(meta);
53996
+ }
53997
+ return out.sort((a, b) => a.updatedAt < b.updatedAt ? 1 : -1);
53998
+ }
53999
+ function getProject(id) {
54000
+ return readMeta(safeProjectId(id));
54001
+ }
54002
+ function createProject(input) {
54003
+ const name = typeof input.name === "string" ? input.name.trim() : "";
54004
+ const app = typeof input.app === "string" ? input.app.trim() : "";
54005
+ if (!name) throw new ProjectError("project name required");
54006
+ if (!/^[a-z0-9][a-z0-9._-]*$/i.test(app)) throw new ProjectError(`invalid app id: ${app || "(empty)"}`);
54007
+ let id = `${slugify(name)}-${(0, import_node_crypto6.randomBytes)(3).toString("hex")}`;
54008
+ while ((0, import_node_fs19.existsSync)(projectDir(id))) id = `${slugify(name)}-${(0, import_node_crypto6.randomBytes)(3).toString("hex")}`;
54009
+ (0, import_node_fs19.mkdirSync)(projectDir(id), { recursive: true });
54010
+ const now = (/* @__PURE__ */ new Date()).toISOString();
54011
+ const meta = { id, name, app, createdAt: now, updatedAt: now };
54012
+ writeMeta(meta);
54013
+ return meta;
54014
+ }
54015
+ function renameProject(id, name) {
54016
+ const meta = readMeta(safeProjectId(id));
54017
+ if (!meta) throw new ProjectError(`unknown project: ${id}`);
54018
+ if (typeof name !== "string" || !name.trim()) throw new ProjectError("project name required");
54019
+ const next = { ...meta, name: name.trim(), updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
54020
+ writeMeta(next);
54021
+ return next;
54022
+ }
54023
+ function touchProject(id) {
54024
+ const meta = readMeta(safeProjectId(id));
54025
+ if (meta) writeMeta({ ...meta, updatedAt: (/* @__PURE__ */ new Date()).toISOString() });
54026
+ }
54027
+ function duplicateProject(id, name) {
54028
+ const src = readMeta(safeProjectId(id));
54029
+ if (!src) throw new ProjectError(`unknown project: ${id}`);
54030
+ const copy = createProject({
54031
+ name: typeof name === "string" && name.trim() ? name.trim() : `${src.name} (copy)`,
54032
+ app: src.app
54033
+ });
54034
+ (0, import_node_fs19.cpSync)(projectDir(src.id), projectDir(copy.id), {
54035
+ recursive: true,
54036
+ filter: (p) => !p.endsWith("project.json")
54037
+ });
54038
+ return copy;
54039
+ }
54040
+ function archiveProject(id) {
54041
+ const dir = projectDir(id);
54042
+ if (!(0, import_node_fs19.existsSync)(dir)) throw new ProjectError(`unknown project: ${id}`);
54043
+ (0, import_node_fs19.mkdirSync)(ARCHIVE, { recursive: true });
54044
+ const dest = (0, import_node_path17.join)(ARCHIVE, id);
54045
+ if ((0, import_node_fs19.existsSync)(dest)) throw new ProjectError(`already archived: ${id}`);
54046
+ (0, import_node_fs19.renameSync)(dir, dest);
54047
+ }
54048
+
54049
+ // contract-bake.ts
54050
+ var import_node_fs20 = require("node:fs");
53946
54051
  var import_yaml5 = __toESM(require_dist6(), 1);
53947
54052
  function bakeContractIntoApp(sourcePath, contract) {
53948
- const doc = (0, import_yaml5.parseDocument)((0, import_node_fs19.readFileSync)(sourcePath, "utf8"));
54053
+ const doc = (0, import_yaml5.parseDocument)((0, import_node_fs20.readFileSync)(sourcePath, "utf8"));
53949
54054
  if (doc.errors.length > 0) {
53950
54055
  throw new Error(`contract bake: source is not valid YAML: ${doc.errors[0]?.message ?? "parse error"}`);
53951
54056
  }
@@ -53995,7 +54100,7 @@ function bakeContractIntoApp(sourcePath, contract) {
53995
54100
  );
53996
54101
  }
53997
54102
  doc.setIn(["nodes", idx, "config", "takeoff"], baked);
53998
- (0, import_node_fs19.writeFileSync)(sourcePath, doc.toString());
54103
+ (0, import_node_fs20.writeFileSync)(sourcePath, doc.toString());
53999
54104
  }
54000
54105
 
54001
54106
  // vectorize.ts
@@ -54698,6 +54803,8 @@ function expandJoints(joints, memberGeo) {
54698
54803
  return;
54699
54804
  }
54700
54805
  for (const part of expandBasePlate(j, col)) {
54806
+ part.conn = j.id;
54807
+ part.connKind = j.kind;
54701
54808
  elements.push(part);
54702
54809
  usedGroups.add(part.group);
54703
54810
  }
@@ -54719,6 +54826,8 @@ function expandJoints(joints, memberGeo) {
54719
54826
  return;
54720
54827
  }
54721
54828
  for (const part of parts) {
54829
+ part.conn = j.id;
54830
+ part.connKind = j.kind;
54722
54831
  elements.push(part);
54723
54832
  if (part.kind !== "cut") usedGroups.add(part.group);
54724
54833
  }
@@ -54921,11 +55030,11 @@ function contractToBom(contractInput) {
54921
55030
  }
54922
55031
 
54923
55032
  // bom-export.ts
54924
- var import_node_os13 = require("node:os");
54925
- var import_node_path17 = require("node:path");
55033
+ var import_node_os14 = require("node:os");
55034
+ var import_node_path18 = require("node:path");
54926
55035
 
54927
55036
  // node_modules/write-excel-file/modules/export/writeXlsxFileNode.js
54928
- var import_node_fs20 = __toESM(require("node:fs"), 1);
55037
+ var import_node_fs21 = __toESM(require("node:fs"), 1);
54929
55038
 
54930
55039
  // node_modules/write-excel-file/modules/xlsx/helpers/features/getAdditionalContent.js
54931
55040
  function _createForOfIteratorHelperLoose(r, e) {
@@ -59097,7 +59206,7 @@ function writeXlsxFile(arg1, arg2, arg3) {
59097
59206
  },
59098
59207
  toFile: function toFile(filePath) {
59099
59208
  return createReadableStream().then(function(readableStream) {
59100
- return pipe(readableStream, import_node_fs20.default.createWriteStream(filePath));
59209
+ return pipe(readableStream, import_node_fs21.default.createWriteStream(filePath));
59101
59210
  });
59102
59211
  }
59103
59212
  };
@@ -59122,8 +59231,8 @@ function pipe(readableStream, writableStream) {
59122
59231
 
59123
59232
  // bom-export.ts
59124
59233
  function bomExportPath(appId, format) {
59125
- const root = process.env.FLOLESS_HOME ?? (0, import_node_path17.join)((0, import_node_os13.homedir)(), ".floless");
59126
- return (0, import_node_path17.join)(root, "exports", appId, `${appId}-bom.${format}`);
59234
+ const root = process.env.FLOLESS_HOME ?? (0, import_node_path18.join)((0, import_node_os14.homedir)(), ".floless");
59235
+ return (0, import_node_path18.join)(root, "exports", appId, `${appId}-bom.${format}`);
59127
59236
  }
59128
59237
  function csvField(v) {
59129
59238
  let s = String(v);
@@ -59151,11 +59260,11 @@ async function bomToXlsx(bom) {
59151
59260
  }
59152
59261
 
59153
59262
  // scene-bake.ts
59154
- var import_node_fs21 = require("node:fs");
59155
- var import_node_path18 = require("node:path");
59263
+ var import_node_fs22 = require("node:fs");
59264
+ var import_node_path19 = require("node:path");
59156
59265
  var import_yaml6 = __toESM(require_dist6(), 1);
59157
59266
  function bakeSceneIntoApp(sourcePath, scene, agent = "viewer-3d") {
59158
- const doc = (0, import_yaml6.parseDocument)((0, import_node_fs21.readFileSync)(sourcePath, "utf8"));
59267
+ const doc = (0, import_yaml6.parseDocument)((0, import_node_fs22.readFileSync)(sourcePath, "utf8"));
59159
59268
  if (doc.errors.length > 0) {
59160
59269
  throw new Error(`scene bake: source is not valid YAML: ${doc.errors[0]?.message ?? "parse error"}`);
59161
59270
  }
@@ -59164,10 +59273,10 @@ function bakeSceneIntoApp(sourcePath, scene, agent = "viewer-3d") {
59164
59273
  const idx = items.findIndex((it) => ((0, import_yaml6.isMap)(it) ? it.toJSON() : null)?.agent === agent);
59165
59274
  if (idx < 0) throw new Error(`no ${agent} render node to bake the scene into`);
59166
59275
  doc.setIn(["nodes", idx, "config", "scene"], scene);
59167
- (0, import_node_fs21.writeFileSync)(sourcePath, doc.toString());
59276
+ (0, import_node_fs22.writeFileSync)(sourcePath, doc.toString());
59168
59277
  }
59169
59278
  function bakeNodeConfigById(sourcePath, nodeId, patch2) {
59170
- const doc = (0, import_yaml6.parseDocument)((0, import_node_fs21.readFileSync)(sourcePath, "utf8"));
59279
+ const doc = (0, import_yaml6.parseDocument)((0, import_node_fs22.readFileSync)(sourcePath, "utf8"));
59171
59280
  if (doc.errors.length > 0) {
59172
59281
  throw new Error(`node bake: source is not valid YAML: ${doc.errors[0]?.message ?? "parse error"}`);
59173
59282
  }
@@ -59176,12 +59285,12 @@ function bakeNodeConfigById(sourcePath, nodeId, patch2) {
59176
59285
  const idx = items.findIndex((it) => ((0, import_yaml6.isMap)(it) ? it.toJSON() : null)?.id === nodeId);
59177
59286
  if (idx < 0) throw new Error(`no node with id "${nodeId}"`);
59178
59287
  for (const [key, value] of Object.entries(patch2)) doc.setIn(["nodes", idx, "config", key], value);
59179
- (0, import_node_fs21.writeFileSync)(sourcePath, doc.toString());
59288
+ (0, import_node_fs22.writeFileSync)(sourcePath, doc.toString());
59180
59289
  }
59181
59290
  function writeViewer3dApp(dir, appId, scene) {
59182
- (0, import_node_fs21.mkdirSync)(dir, { recursive: true });
59183
- const flo = (0, import_node_path18.join)(dir, `${appId}.flo`);
59184
- (0, import_node_fs21.writeFileSync)(flo, [
59291
+ (0, import_node_fs22.mkdirSync)(dir, { recursive: true });
59292
+ const flo = (0, import_node_path19.join)(dir, `${appId}.flo`);
59293
+ (0, import_node_fs22.writeFileSync)(flo, [
59185
59294
  `app: ${appId}`,
59186
59295
  "version: 0.1.0",
59187
59296
  "display-name: Steel 3D",
@@ -59202,11 +59311,11 @@ function writeViewer3dApp(dir, appId, scene) {
59202
59311
  return flo;
59203
59312
  }
59204
59313
  function writeIfcApp(dir, appId, scene, outputPath, opts = {}) {
59205
- (0, import_node_fs21.mkdirSync)(dir, { recursive: true });
59206
- const flo = (0, import_node_path18.join)(dir, `${appId}.flo`);
59314
+ (0, import_node_fs22.mkdirSync)(dir, { recursive: true });
59315
+ const flo = (0, import_node_path19.join)(dir, `${appId}.flo`);
59207
59316
  const displayName = opts.displayName ?? "Steel IFC";
59208
59317
  const description = opts.description ?? "IFC file written from an approved steel.takeoff/v1 contract (a companion export; the contract is the source of truth).";
59209
- (0, import_node_fs21.writeFileSync)(flo, [
59318
+ (0, import_node_fs22.writeFileSync)(flo, [
59210
59319
  `app: ${appId}`,
59211
59320
  "version: 0.1.0",
59212
59321
  `display-name: ${displayName}`,
@@ -59229,9 +59338,9 @@ function writeIfcApp(dir, appId, scene, outputPath, opts = {}) {
59229
59338
  return flo;
59230
59339
  }
59231
59340
  function writeTeklaApp(dir, appId, scene, teklaVersion = "2026.0") {
59232
- (0, import_node_fs21.mkdirSync)(dir, { recursive: true });
59233
- const flo = (0, import_node_path18.join)(dir, `${appId}.flo`);
59234
- (0, import_node_fs21.writeFileSync)(flo, [
59341
+ (0, import_node_fs22.mkdirSync)(dir, { recursive: true });
59342
+ const flo = (0, import_node_path19.join)(dir, `${appId}.flo`);
59343
+ (0, import_node_fs22.writeFileSync)(flo, [
59235
59344
  `app: ${appId}`,
59236
59345
  "version: 0.1.0",
59237
59346
  "display-name: Steel to Tekla",
@@ -59639,13 +59748,13 @@ function scoreContract2(contractInput) {
59639
59748
  }
59640
59749
 
59641
59750
  // app-lifecycle.ts
59642
- var import_node_fs24 = require("node:fs");
59643
- var import_node_os15 = require("node:os");
59644
- var import_node_path21 = require("node:path");
59751
+ var import_node_fs25 = require("node:fs");
59752
+ var import_node_os16 = require("node:os");
59753
+ var import_node_path22 = require("node:path");
59645
59754
 
59646
59755
  // routines.ts
59647
- var import_node_fs23 = require("node:fs");
59648
- var import_node_path20 = require("node:path");
59756
+ var import_node_fs24 = require("node:fs");
59757
+ var import_node_path21 = require("node:path");
59649
59758
 
59650
59759
  // sse.ts
59651
59760
  var clients = /* @__PURE__ */ new Set();
@@ -59682,11 +59791,11 @@ function clientCount() {
59682
59791
  }
59683
59792
 
59684
59793
  // trigger-sessions.ts
59685
- var import_node_fs22 = require("node:fs");
59686
- var import_node_os14 = require("node:os");
59687
- var import_node_path19 = require("node:path");
59794
+ var import_node_fs23 = require("node:fs");
59795
+ var import_node_os15 = require("node:os");
59796
+ var import_node_path20 = require("node:path");
59688
59797
  var import_yaml7 = __toESM(require_dist6(), 1);
59689
- var AGENTS_DIR2 = process.env.AWARE_HOME ? (0, import_node_path19.join)(process.env.AWARE_HOME, "agents") : (0, import_node_path19.join)((0, import_node_os14.homedir)(), ".aware", "agents");
59798
+ var AGENTS_DIR2 = process.env.AWARE_HOME ? (0, import_node_path20.join)(process.env.AWARE_HOME, "agents") : (0, import_node_path20.join)((0, import_node_os15.homedir)(), ".aware", "agents");
59690
59799
  function summarizeFire(data) {
59691
59800
  if (!data) return "event";
59692
59801
  const type = typeof data.type === "string" ? data.type : "";
@@ -59703,10 +59812,10 @@ function mapTriggerState(phase) {
59703
59812
  function isHostBacked(agent, agentsDir = AGENTS_DIR2) {
59704
59813
  const safe = (n) => !n.includes("/") && !n.includes("\\") && !n.includes("..");
59705
59814
  if (!safe(agent)) return false;
59706
- const manifestPath = (0, import_node_path19.join)(agentsDir, agent, "manifest.yaml");
59707
- if (!(0, import_node_fs22.existsSync)(manifestPath)) return false;
59815
+ const manifestPath = (0, import_node_path20.join)(agentsDir, agent, "manifest.yaml");
59816
+ if (!(0, import_node_fs23.existsSync)(manifestPath)) return false;
59708
59817
  try {
59709
- const doc = (0, import_yaml7.parse)((0, import_node_fs22.readFileSync)(manifestPath, "utf8"));
59818
+ const doc = (0, import_yaml7.parse)((0, import_node_fs23.readFileSync)(manifestPath, "utf8"));
59710
59819
  const transport = doc?.transport;
59711
59820
  return !!(transport && typeof transport === "object" && "cli" in transport);
59712
59821
  } catch {
@@ -59991,7 +60100,7 @@ var RoutineError = class extends Error {
59991
60100
  }
59992
60101
  status;
59993
60102
  };
59994
- var ROUTINES_FILE = (0, import_node_path20.join)(flolessRoot, "routines.json");
60103
+ var ROUTINES_FILE = (0, import_node_path21.join)(flolessRoot, "routines.json");
59995
60104
  var routines = [];
59996
60105
  var loaded = false;
59997
60106
  function ensureLoaded() {
@@ -60027,10 +60136,10 @@ function sanitizeRoutine(raw) {
60027
60136
  };
60028
60137
  }
60029
60138
  function loadFromDisk() {
60030
- if (!(0, import_node_fs23.existsSync)(ROUTINES_FILE)) return [];
60139
+ if (!(0, import_node_fs24.existsSync)(ROUTINES_FILE)) return [];
60031
60140
  let text;
60032
60141
  try {
60033
- text = (0, import_node_fs23.readFileSync)(ROUTINES_FILE, "utf8");
60142
+ text = (0, import_node_fs24.readFileSync)(ROUTINES_FILE, "utf8");
60034
60143
  } catch {
60035
60144
  return [];
60036
60145
  }
@@ -60039,17 +60148,17 @@ function loadFromDisk() {
60039
60148
  return Array.isArray(parsed) ? parsed.map(sanitizeRoutine).filter((r) => r !== null) : [];
60040
60149
  } catch {
60041
60150
  try {
60042
- (0, import_node_fs23.renameSync)(ROUTINES_FILE, `${ROUTINES_FILE}.corrupt-${Date.now()}`);
60151
+ (0, import_node_fs24.renameSync)(ROUTINES_FILE, `${ROUTINES_FILE}.corrupt-${Date.now()}`);
60043
60152
  } catch {
60044
60153
  }
60045
60154
  return [];
60046
60155
  }
60047
60156
  }
60048
60157
  function saveRoutines() {
60049
- if (!(0, import_node_fs23.existsSync)(flolessRoot)) (0, import_node_fs23.mkdirSync)(flolessRoot, { recursive: true });
60158
+ if (!(0, import_node_fs24.existsSync)(flolessRoot)) (0, import_node_fs24.mkdirSync)(flolessRoot, { recursive: true });
60050
60159
  const tmp = `${ROUTINES_FILE}.${process.pid}.tmp`;
60051
- (0, import_node_fs23.writeFileSync)(tmp, JSON.stringify(routines, null, 2));
60052
- (0, import_node_fs23.renameSync)(tmp, ROUTINES_FILE);
60160
+ (0, import_node_fs24.writeFileSync)(tmp, JSON.stringify(routines, null, 2));
60161
+ (0, import_node_fs24.renameSync)(tmp, ROUTINES_FILE);
60053
60162
  }
60054
60163
  function listRoutines() {
60055
60164
  ensureLoaded();
@@ -60105,7 +60214,7 @@ function coerceInputs(app, raw) {
60105
60214
  }
60106
60215
  return out;
60107
60216
  }
60108
- function slugify(s) {
60217
+ function slugify2(s) {
60109
60218
  const base = s.toLowerCase().trim().replace(/[^a-z0-9._-]+/g, "-").replace(/^[-.]+|[-.]+$/g, "").slice(0, 48);
60110
60219
  return SLUG.test(base) ? base : "routine";
60111
60220
  }
@@ -60183,7 +60292,7 @@ function createRoutine(input) {
60183
60292
  }
60184
60293
  const now = /* @__PURE__ */ new Date();
60185
60294
  const r = {
60186
- id: uniqueId(slugify(name)),
60295
+ id: uniqueId(slugify2(name)),
60187
60296
  name,
60188
60297
  kind,
60189
60298
  workflow: app.id,
@@ -60457,13 +60566,13 @@ var AppLifecycleError = class extends Error {
60457
60566
  }
60458
60567
  };
60459
60568
  function appsDir() {
60460
- return process.env.AWARE_HOME ? (0, import_node_path21.join)(process.env.AWARE_HOME, "apps") : (0, import_node_path21.join)((0, import_node_os15.homedir)(), ".aware", "apps");
60569
+ return process.env.AWARE_HOME ? (0, import_node_path22.join)(process.env.AWARE_HOME, "apps") : (0, import_node_path22.join)((0, import_node_os16.homedir)(), ".aware", "apps");
60461
60570
  }
60462
60571
  function appDirPath(id) {
60463
- return (0, import_node_path21.join)(appsDir(), id);
60572
+ return (0, import_node_path22.join)(appsDir(), id);
60464
60573
  }
60465
60574
  function appInstalled(id) {
60466
- return APP_ID3.test(id) && (0, import_node_fs24.existsSync)(appDirPath(id));
60575
+ return APP_ID3.test(id) && (0, import_node_fs25.existsSync)(appDirPath(id));
60467
60576
  }
60468
60577
  function logCascade(what, e) {
60469
60578
  console.error(`[app-lifecycle] cascade step failed (${what}):`, e instanceof Error ? e.message : e);
@@ -60579,9 +60688,9 @@ function isGatedAwareRoute(url, method) {
60579
60688
 
60580
60689
  // autostart.mjs
60581
60690
  var import_node_child_process5 = require("node:child_process");
60582
- var import_node_fs25 = require("node:fs");
60583
- var import_node_os16 = require("node:os");
60584
- var import_node_path22 = require("node:path");
60691
+ var import_node_fs26 = require("node:fs");
60692
+ var import_node_os17 = require("node:os");
60693
+ var import_node_path23 = require("node:path");
60585
60694
 
60586
60695
  // teardown.mjs
60587
60696
  var RUN_KEY = "HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run";
@@ -60693,8 +60802,8 @@ function removeLegacyRunKey() {
60693
60802
  }
60694
60803
  function logLine(msg) {
60695
60804
  try {
60696
- (0, import_node_fs25.mkdirSync)(logDir(), { recursive: true });
60697
- (0, import_node_fs25.appendFileSync)(logFilePath(), `${(/* @__PURE__ */ new Date()).toISOString()} ${msg}
60805
+ (0, import_node_fs26.mkdirSync)(logDir(), { recursive: true });
60806
+ (0, import_node_fs26.appendFileSync)(logFilePath(), `${(/* @__PURE__ */ new Date()).toISOString()} ${msg}
60698
60807
  `);
60699
60808
  } catch {
60700
60809
  }
@@ -60702,8 +60811,8 @@ function logLine(msg) {
60702
60811
  function registerAutostart(exePath) {
60703
60812
  if (!isWin) return;
60704
60813
  const xml = buildAutostartTaskXml(exePath, currentUserId());
60705
- const tmp = (0, import_node_path22.join)((0, import_node_os16.tmpdir)(), `floless-autostart-${process.pid}-${Date.now()}.xml`);
60706
- (0, import_node_fs25.writeFileSync)(tmp, "\uFEFF" + xml, { encoding: "utf16le" });
60814
+ const tmp = (0, import_node_path23.join)((0, import_node_os17.tmpdir)(), `floless-autostart-${process.pid}-${Date.now()}.xml`);
60815
+ (0, import_node_fs26.writeFileSync)(tmp, "\uFEFF" + xml, { encoding: "utf16le" });
60707
60816
  try {
60708
60817
  (0, import_node_child_process5.execFileSync)("schtasks", ["/Create", "/TN", TASK_NAME, "/XML", tmp, "/F"], {
60709
60818
  stdio: ["ignore", "ignore", "ignore"],
@@ -60714,7 +60823,7 @@ function registerAutostart(exePath) {
60714
60823
  throw err2;
60715
60824
  } finally {
60716
60825
  try {
60717
- (0, import_node_fs25.rmSync)(tmp, { force: true });
60826
+ (0, import_node_fs26.rmSync)(tmp, { force: true });
60718
60827
  } catch {
60719
60828
  }
60720
60829
  }
@@ -60748,27 +60857,27 @@ function unregisterAutostart() {
60748
60857
 
60749
60858
  // updater.ts
60750
60859
  var import_node_child_process6 = require("node:child_process");
60751
- var import_node_crypto6 = require("node:crypto");
60752
- var import_node_fs27 = require("node:fs");
60860
+ var import_node_crypto7 = require("node:crypto");
60861
+ var import_node_fs28 = require("node:fs");
60753
60862
  var import_node_stream3 = require("node:stream");
60754
60863
  var import_promises = require("node:stream/promises");
60755
- var import_node_path24 = require("node:path");
60864
+ var import_node_path25 = require("node:path");
60756
60865
 
60757
60866
  // post-update-marker.mjs
60758
- var import_node_fs26 = require("node:fs");
60759
- var import_node_os17 = require("node:os");
60760
- var import_node_path23 = require("node:path");
60867
+ var import_node_fs27 = require("node:fs");
60868
+ var import_node_os18 = require("node:os");
60869
+ var import_node_path24 = require("node:path");
60761
60870
  var FRESH_MS = 12e4;
60762
60871
  function markerPath() {
60763
60872
  const override = (process.env.FLOLESS_POST_UPDATE_MARKER ?? "").trim();
60764
60873
  if (override) return override;
60765
- const root = process.env.FLOLESS_HOME ?? (0, import_node_path23.join)((0, import_node_os17.homedir)(), ".floless");
60766
- return (0, import_node_path23.join)(root, ".post-update");
60874
+ const root = process.env.FLOLESS_HOME ?? (0, import_node_path24.join)((0, import_node_os18.homedir)(), ".floless");
60875
+ return (0, import_node_path24.join)(root, ".post-update");
60767
60876
  }
60768
60877
  function legacyMarkerPath() {
60769
60878
  if ((process.env.FLOLESS_POST_UPDATE_MARKER ?? "").trim()) return null;
60770
60879
  try {
60771
- return (0, import_node_path23.join)((0, import_node_path23.dirname)((0, import_node_path23.dirname)(process.execPath)), ".floless-post-update");
60880
+ return (0, import_node_path24.join)((0, import_node_path24.dirname)((0, import_node_path24.dirname)(process.execPath)), ".floless-post-update");
60772
60881
  } catch {
60773
60882
  return null;
60774
60883
  }
@@ -60778,7 +60887,7 @@ function writePostUpdateMarker() {
60778
60887
  for (const p of [markerPath(), legacyMarkerPath()]) {
60779
60888
  if (!p) continue;
60780
60889
  try {
60781
- (0, import_node_fs26.writeFileSync)(p, (/* @__PURE__ */ new Date()).toISOString());
60890
+ (0, import_node_fs27.writeFileSync)(p, (/* @__PURE__ */ new Date()).toISOString());
60782
60891
  wrote = true;
60783
60892
  } catch {
60784
60893
  }
@@ -60790,9 +60899,9 @@ function consumePostUpdateMarker() {
60790
60899
  for (const p of [markerPath(), legacyMarkerPath()]) {
60791
60900
  if (!p) continue;
60792
60901
  try {
60793
- if (!(0, import_node_fs26.existsSync)(p)) continue;
60794
- const ageMs = Date.now() - (0, import_node_fs26.statSync)(p).mtimeMs;
60795
- (0, import_node_fs26.rmSync)(p, { force: true });
60902
+ if (!(0, import_node_fs27.existsSync)(p)) continue;
60903
+ const ageMs = Date.now() - (0, import_node_fs27.statSync)(p).mtimeMs;
60904
+ (0, import_node_fs27.rmSync)(p, { force: true });
60796
60905
  if (ageMs < FRESH_MS) fresh = true;
60797
60906
  } catch {
60798
60907
  }
@@ -60809,13 +60918,13 @@ function currentVersion() {
60809
60918
  return appVersion();
60810
60919
  }
60811
60920
  function installRoot() {
60812
- return (0, import_node_path24.dirname)((0, import_node_path24.dirname)(process.execPath));
60921
+ return (0, import_node_path25.dirname)((0, import_node_path25.dirname)(process.execPath));
60813
60922
  }
60814
60923
  function updateExePath() {
60815
- return (0, import_node_path24.join)(installRoot(), "Update.exe");
60924
+ return (0, import_node_path25.join)(installRoot(), "Update.exe");
60816
60925
  }
60817
60926
  function packagesDir() {
60818
- return (0, import_node_path24.join)(installRoot(), "packages");
60927
+ return (0, import_node_path25.join)(installRoot(), "packages");
60819
60928
  }
60820
60929
  function feedUrl() {
60821
60930
  const env2 = (process.env.FLOLESS_UPDATE_URL ?? "").trim().replace(/\/+$/, "");
@@ -60907,23 +61016,23 @@ async function checkForUpdate() {
60907
61016
  return { supported: true, currentVersion: cur, updateAvailable: true, targetVersion: latest.Version, asset: latest };
60908
61017
  }
60909
61018
  async function sha1OfFile(path) {
60910
- const hash = (0, import_node_crypto6.createHash)("sha1");
60911
- await (0, import_promises.pipeline)((0, import_node_fs27.createReadStream)(path), hash);
61019
+ const hash = (0, import_node_crypto7.createHash)("sha1");
61020
+ await (0, import_promises.pipeline)((0, import_node_fs28.createReadStream)(path), hash);
60912
61021
  return hash.digest("hex").toUpperCase();
60913
61022
  }
60914
61023
  async function downloadPackage(asset) {
60915
61024
  if (!NUPKG_NAME.test(asset.FileName)) throw new Error(`refusing suspicious package name: ${asset.FileName}`);
60916
61025
  const want = asset.SHA1.toUpperCase();
60917
61026
  const dir = packagesDir();
60918
- (0, import_node_fs27.mkdirSync)(dir, { recursive: true });
60919
- const dest = (0, import_node_path24.join)(dir, asset.FileName);
60920
- if ((0, import_node_fs27.existsSync)(dest) && await sha1OfFile(dest) === want) return dest;
61027
+ (0, import_node_fs28.mkdirSync)(dir, { recursive: true });
61028
+ const dest = (0, import_node_path25.join)(dir, asset.FileName);
61029
+ if ((0, import_node_fs28.existsSync)(dest) && await sha1OfFile(dest) === want) return dest;
60921
61030
  const res = await authedFetch(`${feedUrl()}/${encodeURIComponent(asset.FileName)}`, {
60922
61031
  redirect: "follow",
60923
61032
  signal: AbortSignal.timeout(DOWNLOAD_TIMEOUT_MS)
60924
61033
  });
60925
61034
  if (!res.ok || !res.body) throw new Error(`download failed: HTTP ${res.status} for ${asset.FileName}`);
60926
- await (0, import_promises.pipeline)(import_node_stream3.Readable.fromWeb(res.body), (0, import_node_fs27.createWriteStream)(dest));
61035
+ await (0, import_promises.pipeline)(import_node_stream3.Readable.fromWeb(res.body), (0, import_node_fs28.createWriteStream)(dest));
60927
61036
  const got = await sha1OfFile(dest);
60928
61037
  if (got !== want) throw new Error(`SHA1 mismatch for ${asset.FileName}: feed=${want} got=${got}`);
60929
61038
  return dest;
@@ -60932,7 +61041,7 @@ async function applyUpdate(check, opts) {
60932
61041
  if (!check.supported) return { applied: false, message: check.reason ?? "auto-update not supported in this runtime" };
60933
61042
  if (!check.updateAvailable || !check.asset) return { applied: false, message: check.reason ?? "no update available" };
60934
61043
  const exe = updateExePath();
60935
- if (!(0, import_node_fs27.existsSync)(exe)) {
61044
+ if (!(0, import_node_fs28.existsSync)(exe)) {
60936
61045
  return { applied: false, message: `Update.exe not found at ${exe} \u2014 is this a Velopack install?` };
60937
61046
  }
60938
61047
  const pkg = await downloadPackage(check.asset);
@@ -61172,12 +61281,12 @@ function isTraceCorrupt(events) {
61172
61281
 
61173
61282
  // launch.mjs
61174
61283
  var import_node_child_process7 = require("node:child_process");
61175
- var import_node_path25 = require("node:path");
61284
+ var import_node_path26 = require("node:path");
61176
61285
  var import_node_url3 = require("node:url");
61177
- var import_node_fs28 = require("node:fs");
61286
+ var import_node_fs29 = require("node:fs");
61178
61287
  var import_node_http = __toESM(require("node:http"), 1);
61179
61288
  var import_node_readline = require("node:readline");
61180
- var __dirname2 = (0, import_node_path25.dirname)((0, import_node_url3.fileURLToPath)(__import_meta_url));
61289
+ var __dirname2 = (0, import_node_path26.dirname)((0, import_node_url3.fileURLToPath)(__import_meta_url));
61181
61290
  var PORT = Number(process.env.PORT ?? 4317);
61182
61291
  var HEALTH_URL = `http://127.0.0.1:${PORT}/api/health`;
61183
61292
  var BROWSER_URL = `http://floless.localhost:${PORT}`;
@@ -61249,8 +61358,8 @@ async function waitHealthy(timeoutMs = 3e4) {
61249
61358
  function resolveServerStart() {
61250
61359
  const packaged = /flolessapp\.exe$/i.test(process.execPath);
61251
61360
  if (packaged) return { cmd: process.execPath, args: ["--serve"], shell: false };
61252
- const bundle = (0, import_node_path25.join)(__dirname2, "dist", "floless-server.cjs");
61253
- if ((0, import_node_fs28.existsSync)(bundle)) return { cmd: process.execPath, args: [bundle, "--serve"], shell: false };
61361
+ const bundle = (0, import_node_path26.join)(__dirname2, "dist", "floless-server.cjs");
61362
+ if ((0, import_node_fs29.existsSync)(bundle)) return { cmd: process.execPath, args: [bundle, "--serve"], shell: false };
61254
61363
  return { cmd: "npm", args: ["run", "start"], shell: isWin2 };
61255
61364
  }
61256
61365
  function startServerDetached() {
@@ -61403,8 +61512,8 @@ function taskkillArgs(pid, { tree = true } = {}) {
61403
61512
  }
61404
61513
  function killSupervisor({ tree = true } = {}) {
61405
61514
  if (!isWin2) return;
61406
- const isNpmChannel = /^node(\.exe)?$/i.test((0, import_node_path25.basename)(process.execPath));
61407
- const scriptMatch = isNpmChannel ? (0, import_node_path25.basename)((0, import_node_url3.fileURLToPath)(__import_meta_url)) : void 0;
61515
+ const isNpmChannel = /^node(\.exe)?$/i.test((0, import_node_path26.basename)(process.execPath));
61516
+ const scriptMatch = isNpmChannel ? (0, import_node_path26.basename)((0, import_node_url3.fileURLToPath)(__import_meta_url)) : void 0;
61408
61517
  const realExe = resolveRealInstallExe(process.execPath);
61409
61518
  const exeMatch = realExe === process.execPath ? process.execPath : [process.execPath, realExe];
61410
61519
  const pids = supervisorPidsToKill(enumerateProcesses(), process.pid, exeMatch, scriptMatch);
@@ -61569,7 +61678,7 @@ async function runAction(arg, flagArgv = [], selfVersion = null) {
61569
61678
  }
61570
61679
  await action(parseTeardownFlags(flagArgv));
61571
61680
  }
61572
- var entry = (0, import_node_path25.basename)(process.argv[1] ?? "").toLowerCase();
61681
+ var entry = (0, import_node_path26.basename)(process.argv[1] ?? "").toLowerCase();
61573
61682
  if (entry === "launch.mjs") {
61574
61683
  runAction(process.argv[2], process.argv.slice(3)).catch((e) => {
61575
61684
  log(`error: ${e?.message ?? e}`);
@@ -61643,9 +61752,9 @@ function awareUpgradeBlockReason(s) {
61643
61752
  }
61644
61753
 
61645
61754
  // skill-sync.ts
61646
- var import_node_fs29 = require("node:fs");
61647
- var import_node_os18 = require("node:os");
61648
- var import_node_path26 = require("node:path");
61755
+ var import_node_fs30 = require("node:fs");
61756
+ var import_node_os19 = require("node:os");
61757
+ var import_node_path27 = require("node:path");
61649
61758
  var import_node_url4 = require("node:url");
61650
61759
  var import_yaml8 = __toESM(require_dist6(), 1);
61651
61760
 
@@ -61688,30 +61797,30 @@ function selectShippedSkillNames(names) {
61688
61797
  }
61689
61798
 
61690
61799
  // skill-sync.ts
61691
- var __dirname3 = (0, import_node_path26.dirname)((0, import_node_url4.fileURLToPath)(__import_meta_url));
61800
+ var __dirname3 = (0, import_node_path27.dirname)((0, import_node_url4.fileURLToPath)(__import_meta_url));
61692
61801
  function bundledSkillsRoot() {
61693
61802
  const candidates = [
61694
- (0, import_node_path26.join)(__dirname3, "skills"),
61695
- (0, import_node_path26.join)((0, import_node_path26.dirname)(process.execPath), "skills"),
61696
- (0, import_node_path26.join)(__dirname3, "..", ".claude", "skills")
61803
+ (0, import_node_path27.join)(__dirname3, "skills"),
61804
+ (0, import_node_path27.join)((0, import_node_path27.dirname)(process.execPath), "skills"),
61805
+ (0, import_node_path27.join)(__dirname3, "..", ".claude", "skills")
61697
61806
  ];
61698
- return candidates.find((p) => (0, import_node_fs29.existsSync)(p)) ?? null;
61807
+ return candidates.find((p) => (0, import_node_fs30.existsSync)(p)) ?? null;
61699
61808
  }
61700
61809
  function targetConfigDirs() {
61701
61810
  const override = process.env.FLOLESS_SKILL_TARGETS;
61702
61811
  if (override) {
61703
61812
  return override.split(";").map((d) => d.trim()).filter(Boolean).map((dir) => ({ runtime: "custom", dir }));
61704
61813
  }
61705
- const home = (0, import_node_os18.homedir)();
61814
+ const home = (0, import_node_os19.homedir)();
61706
61815
  return [
61707
- { runtime: "claude", dir: (0, import_node_path26.join)(home, ".claude") },
61708
- { runtime: "codex", dir: (0, import_node_path26.join)(home, ".codex") },
61709
- { runtime: "opencode", dir: (0, import_node_path26.join)(home, ".opencode") }
61816
+ { runtime: "claude", dir: (0, import_node_path27.join)(home, ".claude") },
61817
+ { runtime: "codex", dir: (0, import_node_path27.join)(home, ".codex") },
61818
+ { runtime: "opencode", dir: (0, import_node_path27.join)(home, ".opencode") }
61710
61819
  ];
61711
61820
  }
61712
61821
  function skillVersion(skillMdPath) {
61713
61822
  try {
61714
- const text = (0, import_node_fs29.readFileSync)(skillMdPath, "utf8");
61823
+ const text = (0, import_node_fs30.readFileSync)(skillMdPath, "utf8");
61715
61824
  const m = /^---\r?\n([\s\S]*?)\r?\n---/.exec(text);
61716
61825
  if (!m || m[1] === void 0) return null;
61717
61826
  const fm = (0, import_yaml8.parse)(m[1]);
@@ -61751,21 +61860,21 @@ function decideAction(installed, bundled) {
61751
61860
  function bundledSkills(root) {
61752
61861
  let entries = [];
61753
61862
  try {
61754
- entries = selectShippedSkillNames((0, import_node_fs29.readdirSync)(root));
61863
+ entries = selectShippedSkillNames((0, import_node_fs30.readdirSync)(root));
61755
61864
  } catch {
61756
61865
  return [];
61757
61866
  }
61758
61867
  const out = [];
61759
61868
  for (const name of entries) {
61760
- const dir = (0, import_node_path26.join)(root, name);
61869
+ const dir = (0, import_node_path27.join)(root, name);
61761
61870
  let isDir = false;
61762
61871
  try {
61763
- isDir = (0, import_node_fs29.statSync)(dir).isDirectory();
61872
+ isDir = (0, import_node_fs30.statSync)(dir).isDirectory();
61764
61873
  } catch {
61765
61874
  isDir = false;
61766
61875
  }
61767
61876
  if (!isDir) continue;
61768
- const v = skillVersion((0, import_node_path26.join)(dir, "SKILL.md"));
61877
+ const v = skillVersion((0, import_node_path27.join)(dir, "SKILL.md"));
61769
61878
  if (!v) continue;
61770
61879
  out.push({ name, dir, version: v });
61771
61880
  }
@@ -61778,17 +61887,17 @@ function syncSkills() {
61778
61887
  const skills = bundledSkills(root);
61779
61888
  if (!skills.length) return results;
61780
61889
  for (const { runtime, dir: cfg } of targetConfigDirs()) {
61781
- if (!(0, import_node_fs29.existsSync)(cfg)) continue;
61782
- const skillsDir = (0, import_node_path26.join)(cfg, "skills");
61890
+ if (!(0, import_node_fs30.existsSync)(cfg)) continue;
61891
+ const skillsDir = (0, import_node_path27.join)(cfg, "skills");
61783
61892
  for (const s of skills) {
61784
- const dest = (0, import_node_path26.join)(skillsDir, s.name);
61785
- const installedMd = (0, import_node_path26.join)(dest, "SKILL.md");
61786
- const installed = (0, import_node_fs29.existsSync)(installedMd) ? skillVersion(installedMd) : null;
61893
+ const dest = (0, import_node_path27.join)(skillsDir, s.name);
61894
+ const installedMd = (0, import_node_path27.join)(dest, "SKILL.md");
61895
+ const installed = (0, import_node_fs30.existsSync)(installedMd) ? skillVersion(installedMd) : null;
61787
61896
  const action = decideAction(installed, s.version);
61788
61897
  if (action === "installed" || action === "updated") {
61789
61898
  try {
61790
- if (action === "updated") (0, import_node_fs29.rmSync)(dest, { recursive: true, force: true });
61791
- (0, import_node_fs29.cpSync)(s.dir, dest, { recursive: true });
61899
+ if (action === "updated") (0, import_node_fs30.rmSync)(dest, { recursive: true, force: true });
61900
+ (0, import_node_fs30.cpSync)(s.dir, dest, { recursive: true });
61792
61901
  results.push({ runtime, skill: s.name, action, from: installed, to: s.version });
61793
61902
  } catch {
61794
61903
  }
@@ -61801,9 +61910,9 @@ function syncSkills() {
61801
61910
  }
61802
61911
 
61803
61912
  // watch.ts
61804
- var import_node_os19 = require("node:os");
61805
- var import_node_path28 = require("node:path");
61806
- var import_node_fs30 = require("node:fs");
61913
+ var import_node_os20 = require("node:os");
61914
+ var import_node_path29 = require("node:path");
61915
+ var import_node_fs31 = require("node:fs");
61807
61916
 
61808
61917
  // node_modules/chokidar/esm/index.js
61809
61918
  var import_fs2 = require("fs");
@@ -61814,7 +61923,7 @@ var sysPath2 = __toESM(require("path"), 1);
61814
61923
  // node_modules/readdirp/esm/index.js
61815
61924
  var import_promises2 = require("node:fs/promises");
61816
61925
  var import_node_stream4 = require("node:stream");
61817
- var import_node_path27 = require("node:path");
61926
+ var import_node_path28 = require("node:path");
61818
61927
  var EntryTypes = {
61819
61928
  FILE_TYPE: "files",
61820
61929
  DIR_TYPE: "directories",
@@ -61889,7 +61998,7 @@ var ReaddirpStream = class extends import_node_stream4.Readable {
61889
61998
  this._wantsDir = type ? DIR_TYPES.has(type) : false;
61890
61999
  this._wantsFile = type ? FILE_TYPES.has(type) : false;
61891
62000
  this._wantsEverything = type === EntryTypes.EVERYTHING_TYPE;
61892
- this._root = (0, import_node_path27.resolve)(root);
62001
+ this._root = (0, import_node_path28.resolve)(root);
61893
62002
  this._isDirent = !opts.alwaysStat;
61894
62003
  this._statsProp = this._isDirent ? "dirent" : "stats";
61895
62004
  this._rdOptions = { encoding: "utf8", withFileTypes: this._isDirent };
@@ -61960,8 +62069,8 @@ var ReaddirpStream = class extends import_node_stream4.Readable {
61960
62069
  let entry2;
61961
62070
  const basename5 = this._isDirent ? dirent.name : dirent;
61962
62071
  try {
61963
- const fullPath = (0, import_node_path27.resolve)((0, import_node_path27.join)(path, basename5));
61964
- entry2 = { path: (0, import_node_path27.relative)(this._root, fullPath), fullPath, basename: basename5 };
62072
+ const fullPath = (0, import_node_path28.resolve)((0, import_node_path28.join)(path, basename5));
62073
+ entry2 = { path: (0, import_node_path28.relative)(this._root, fullPath), fullPath, basename: basename5 };
61965
62074
  entry2[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);
61966
62075
  } catch (err2) {
61967
62076
  this._onError(err2);
@@ -61995,7 +62104,7 @@ var ReaddirpStream = class extends import_node_stream4.Readable {
61995
62104
  }
61996
62105
  if (entryRealPathStats.isDirectory()) {
61997
62106
  const len2 = entryRealPath.length;
61998
- if (full.startsWith(entryRealPath) && full.substr(len2, 1) === import_node_path27.sep) {
62107
+ if (full.startsWith(entryRealPath) && full.substr(len2, 1) === import_node_path28.sep) {
61999
62108
  const recursiveError = new Error(`Circular symlink detected: "${full}" points to "${entryRealPath}"`);
62000
62109
  recursiveError.code = RECURSIVE_ERROR_CODE;
62001
62110
  return this._onError(recursiveError);
@@ -62534,9 +62643,9 @@ var NodeFsHandler = class {
62534
62643
  if (this.fsw.closed) {
62535
62644
  return;
62536
62645
  }
62537
- const dirname14 = sysPath.dirname(file);
62646
+ const dirname15 = sysPath.dirname(file);
62538
62647
  const basename5 = sysPath.basename(file);
62539
- const parent = this.fsw._getWatchedDir(dirname14);
62648
+ const parent = this.fsw._getWatchedDir(dirname15);
62540
62649
  let prevStats = stats;
62541
62650
  if (parent.has(basename5))
62542
62651
  return;
@@ -62563,7 +62672,7 @@ var NodeFsHandler = class {
62563
62672
  prevStats = newStats2;
62564
62673
  }
62565
62674
  } catch (error) {
62566
- this.fsw._remove(dirname14, basename5);
62675
+ this.fsw._remove(dirname15, basename5);
62567
62676
  }
62568
62677
  } else if (parent.has(basename5)) {
62569
62678
  const at = newStats.atimeMs;
@@ -63503,33 +63612,33 @@ function appIdFromLogPath(path) {
63503
63612
  return i >= 0 && parts[i + 1] ? parts[i + 1] : null;
63504
63613
  }
63505
63614
  function samePath(a, b) {
63506
- const ra = (0, import_node_path28.resolve)(a);
63507
- const rb = (0, import_node_path28.resolve)(b);
63615
+ const ra = (0, import_node_path29.resolve)(a);
63616
+ const rb = (0, import_node_path29.resolve)(b);
63508
63617
  return process.platform === "win32" ? ra.toLowerCase() === rb.toLowerCase() : ra === rb;
63509
63618
  }
63510
63619
  function underDir(path, dir) {
63511
- const rp = (0, import_node_path28.resolve)(path);
63512
- const rd = (0, import_node_path28.resolve)(dir);
63620
+ const rp = (0, import_node_path29.resolve)(path);
63621
+ const rd = (0, import_node_path29.resolve)(dir);
63513
63622
  const [p, d] = process.platform === "win32" ? [rp.toLowerCase(), rd.toLowerCase()] : [rp, rd];
63514
- return p === d || p.startsWith(d + import_node_path28.sep);
63623
+ return p === d || p.startsWith(d + import_node_path29.sep);
63515
63624
  }
63516
63625
  function startWatcher() {
63517
- const awareDir = process.env.AWARE_HOME ?? (0, import_node_path28.join)((0, import_node_os19.homedir)(), ".aware");
63518
- const credentialsDir = (0, import_node_path28.join)(awareDir, "credentials");
63519
- if (!(0, import_node_fs30.existsSync)(credentialsDir)) {
63626
+ const awareDir = process.env.AWARE_HOME ?? (0, import_node_path29.join)((0, import_node_os20.homedir)(), ".aware");
63627
+ const credentialsDir = (0, import_node_path29.join)(awareDir, "credentials");
63628
+ if (!(0, import_node_fs31.existsSync)(credentialsDir)) {
63520
63629
  try {
63521
- (0, import_node_fs30.mkdirSync)(credentialsDir, { recursive: true });
63630
+ (0, import_node_fs31.mkdirSync)(credentialsDir, { recursive: true });
63522
63631
  } catch {
63523
63632
  }
63524
63633
  }
63525
- if (!(0, import_node_fs30.existsSync)(uiDir)) {
63634
+ if (!(0, import_node_fs31.existsSync)(uiDir)) {
63526
63635
  try {
63527
- (0, import_node_fs30.mkdirSync)(uiDir, { recursive: true });
63636
+ (0, import_node_fs31.mkdirSync)(uiDir, { recursive: true });
63528
63637
  } catch {
63529
63638
  }
63530
63639
  }
63531
- const targets = ["apps", "logs", "credentials"].map((d) => (0, import_node_path28.join)(awareDir, d)).filter((p) => (0, import_node_fs30.existsSync)(p));
63532
- if ((0, import_node_fs30.existsSync)(uiDir)) targets.push(uiDir);
63640
+ const targets = ["apps", "logs", "credentials"].map((d) => (0, import_node_path29.join)(awareDir, d)).filter((p) => (0, import_node_fs31.existsSync)(p));
63641
+ if ((0, import_node_fs31.existsSync)(uiDir)) targets.push(uiDir);
63533
63642
  if (targets.length === 0) {
63534
63643
  return null;
63535
63644
  }
@@ -63558,11 +63667,11 @@ function startWatcher() {
63558
63667
  const isCredential = path.split(/[\\/]/).includes("credentials");
63559
63668
  const kind = isCredential ? "credential" : path.endsWith(".jsonl") ? "trace" : path.endsWith(".lock") ? "lock" : path.endsWith(".flo") || path.endsWith(".app") ? "source" : "file";
63560
63669
  broadcast({ type: "fs-change", kind, event, path });
63561
- if (kind === "trace" && event !== "unlink" && (0, import_node_fs30.existsSync)(path)) {
63670
+ if (kind === "trace" && event !== "unlink" && (0, import_node_fs31.existsSync)(path)) {
63562
63671
  const id = appIdFromLogPath(path);
63563
63672
  if (!id) return;
63564
63673
  try {
63565
- broadcast({ type: "trace-file", id, runId: path.split(import_node_path28.sep).pop()?.replace(/\.jsonl$/, "") ?? null, events: parseTrace((0, import_node_fs30.readFileSync)(path, "utf8")) });
63674
+ broadcast({ type: "trace-file", id, runId: path.split(import_node_path29.sep).pop()?.replace(/\.jsonl$/, "") ?? null, events: parseTrace((0, import_node_fs31.readFileSync)(path, "utf8")) });
63566
63675
  } catch {
63567
63676
  }
63568
63677
  }
@@ -63571,10 +63680,10 @@ function startWatcher() {
63571
63680
  }
63572
63681
 
63573
63682
  // index.ts
63574
- var __dirname4 = (0, import_node_path29.dirname)((0, import_node_url5.fileURLToPath)(__import_meta_url));
63575
- var WEB_ROOT = [(0, import_node_path29.join)(__dirname4, "web"), (0, import_node_path29.join)((0, import_node_path29.dirname)(process.execPath), "web"), (0, import_node_path29.join)(__dirname4, "..", "web")].find(
63576
- (p) => (0, import_node_fs31.existsSync)(p)
63577
- ) ?? (0, import_node_path29.join)(__dirname4, "..", "web");
63683
+ var __dirname4 = (0, import_node_path30.dirname)((0, import_node_url5.fileURLToPath)(__import_meta_url));
63684
+ var WEB_ROOT = [(0, import_node_path30.join)(__dirname4, "web"), (0, import_node_path30.join)((0, import_node_path30.dirname)(process.execPath), "web"), (0, import_node_path30.join)(__dirname4, "..", "web")].find(
63685
+ (p) => (0, import_node_fs32.existsSync)(p)
63686
+ ) ?? (0, import_node_path30.join)(__dirname4, "..", "web");
63578
63687
  var PORT2 = Number(process.env.PORT ?? 4317);
63579
63688
  var HOST = "127.0.0.1";
63580
63689
  var crashHandlersInstalled = false;
@@ -63590,7 +63699,7 @@ function installCrashHandlers() {
63590
63699
  ${stack}
63591
63700
  `;
63592
63701
  try {
63593
- (0, import_node_fs31.appendFileSync)(logFilePath(), line);
63702
+ (0, import_node_fs32.appendFileSync)(logFilePath(), line);
63594
63703
  } catch {
63595
63704
  }
63596
63705
  if (process.stderr.isTTY) process.stderr.write(line);
@@ -63884,9 +63993,9 @@ async function startServer() {
63884
63993
  const { id, templateId, templatePath, srcPath, appDirPath: appDirPath2, fromVersion, contract, verb } = opts;
63885
63994
  const bdir = backupDir(id, fromVersion, Date.now());
63886
63995
  try {
63887
- (0, import_node_fs31.mkdirSync)((0, import_node_path29.dirname)(bdir), { recursive: true });
63888
- (0, import_node_fs31.cpSync)(appDirPath2, bdir, { recursive: true });
63889
- (0, import_node_fs31.cpSync)(templatePath, srcPath);
63996
+ (0, import_node_fs32.mkdirSync)((0, import_node_path30.dirname)(bdir), { recursive: true });
63997
+ (0, import_node_fs32.cpSync)(appDirPath2, bdir, { recursive: true });
63998
+ (0, import_node_fs32.cpSync)(templatePath, srcPath);
63890
63999
  if (id !== templateId) stampSourceAppId(srcPath, id);
63891
64000
  if (contract != null) {
63892
64001
  bakeContractIntoApp(srcPath, contract);
@@ -63897,8 +64006,8 @@ async function startServer() {
63897
64006
  } catch (e) {
63898
64007
  const msg = e instanceof Error ? e.message : String(e);
63899
64008
  try {
63900
- (0, import_node_fs31.rmSync)(appDirPath2, { recursive: true, force: true });
63901
- (0, import_node_fs31.cpSync)(bdir, appDirPath2, { recursive: true });
64009
+ (0, import_node_fs32.rmSync)(appDirPath2, { recursive: true, force: true });
64010
+ (0, import_node_fs32.cpSync)(bdir, appDirPath2, { recursive: true });
63902
64011
  } catch (re) {
63903
64012
  const rmsg = re instanceof Error ? re.message : String(re);
63904
64013
  throw new TemplateSwapError(`${verb} failed (${msg}) AND rollback failed (${rmsg}) \u2014 restore manually from ${bdir}`, "rollback-failed", bdir);
@@ -63929,7 +64038,7 @@ async function startServer() {
63929
64038
  return reply.status(409).send({ ok: false, error: `"${id}" is already at ${fromVersion}`, code: "up-to-date" });
63930
64039
  }
63931
64040
  const contract = readContract(id);
63932
- if (contract == null && (0, import_node_fs31.existsSync)(contractPath(id))) {
64041
+ if (contract == null && (0, import_node_fs32.existsSync)(contractPath(id))) {
63933
64042
  return reply.status(409).send({ ok: false, error: `"${id}"'s saved data is unreadable \u2014 open it in the editor and re-save before updating`, code: "contract-corrupt" });
63934
64043
  }
63935
64044
  if (contract != null) {
@@ -64063,8 +64172,67 @@ async function startServer() {
64063
64172
  app.get("/api/app/:id", async (req) => {
64064
64173
  return { ok: true, app: readApp(req.params.id) };
64065
64174
  });
64175
+ app.get("/api/projects", async () => ({ ok: true, projects: listProjects() }));
64176
+ app.post(
64177
+ "/api/projects",
64178
+ async (req, reply) => {
64179
+ try {
64180
+ const project = createProject({ name: req.body?.name, app: req.body?.app });
64181
+ let seeded = false;
64182
+ if (req.body?.seedFromApp) {
64183
+ const legacy = readContract(project.app);
64184
+ if (legacy != null) {
64185
+ writeContract(project.app, legacy, project.id);
64186
+ seeded = true;
64187
+ }
64188
+ }
64189
+ return { ok: true, project, seeded };
64190
+ } catch (e) {
64191
+ if (e instanceof ProjectError || e instanceof ContractError) {
64192
+ return reply.status(400).send({ ok: false, error: e.message });
64193
+ }
64194
+ throw e;
64195
+ }
64196
+ }
64197
+ );
64198
+ app.patch("/api/projects/:id", async (req, reply) => {
64199
+ try {
64200
+ return { ok: true, project: renameProject(req.params.id, req.body?.name) };
64201
+ } catch (e) {
64202
+ if (e instanceof ProjectError) return reply.status(400).send({ ok: false, error: e.message });
64203
+ throw e;
64204
+ }
64205
+ });
64206
+ app.post("/api/projects/:id/duplicate", async (req, reply) => {
64207
+ try {
64208
+ return { ok: true, project: duplicateProject(req.params.id, req.body?.name) };
64209
+ } catch (e) {
64210
+ if (e instanceof ProjectError) return reply.status(400).send({ ok: false, error: e.message });
64211
+ throw e;
64212
+ }
64213
+ });
64214
+ app.post("/api/projects/:id/archive", async (req, reply) => {
64215
+ try {
64216
+ archiveProject(req.params.id);
64217
+ return { ok: true };
64218
+ } catch (e) {
64219
+ if (e instanceof ProjectError) return reply.status(400).send({ ok: false, error: e.message });
64220
+ throw e;
64221
+ }
64222
+ });
64223
+ function projectAppMismatch(appId, project) {
64224
+ const p = getProject(project);
64225
+ if (!p) return `unknown project: ${project}`;
64226
+ if (p.app !== appId) return `project "${project}" belongs to app "${p.app}", not "${appId}"`;
64227
+ return null;
64228
+ }
64066
64229
  app.get("/api/contract/:appId", async (req, reply) => {
64067
- const doc = readContractForApp(req.params.appId);
64230
+ const project = req.query.project || void 0;
64231
+ if (project) {
64232
+ const bad = projectAppMismatch(req.params.appId, project);
64233
+ if (bad) return reply.status(404).send({ ok: false, error: bad });
64234
+ }
64235
+ const doc = project ? readContract(req.params.appId, project) : readContractForApp(req.params.appId);
64068
64236
  if (doc == null) return reply.status(404).send({ ok: false, error: "no contract for this app yet" });
64069
64237
  if (doc && typeof doc === "object" && doc.type === "drawing.vector/v1") {
64070
64238
  return postProcess(doc);
@@ -64076,18 +64244,29 @@ async function startServer() {
64076
64244
  { bodyLimit: 25 * 1024 * 1024 },
64077
64245
  // contracts embed rasters
64078
64246
  async (req, reply) => {
64247
+ const project = req.query.project || void 0;
64248
+ if (project) {
64249
+ const bad = projectAppMismatch(req.params.appId, project);
64250
+ if (bad) return reply.status(404).send({ ok: false, error: bad });
64251
+ }
64079
64252
  try {
64080
- writeContract(req.params.appId, req.body);
64253
+ writeContract(req.params.appId, req.body, project);
64081
64254
  } catch (e) {
64082
64255
  if (e instanceof ContractError) return reply.status(400).send({ ok: false, error: e.message });
64083
64256
  throw e;
64084
64257
  }
64085
- broadcast({ type: "contract-changed", appId: req.params.appId });
64258
+ if (project) touchProject(project);
64259
+ broadcast({ type: "contract-changed", appId: req.params.appId, project });
64086
64260
  return { ok: true };
64087
64261
  }
64088
64262
  );
64089
64263
  app.post("/api/contract/:appId/approve", async (req, reply) => {
64090
- const doc = readContract(req.params.appId);
64264
+ const project = req.query.project || void 0;
64265
+ if (project) {
64266
+ const bad = projectAppMismatch(req.params.appId, project);
64267
+ if (bad) return reply.status(404).send({ ok: false, error: bad });
64268
+ }
64269
+ const doc = readContract(req.params.appId, project);
64091
64270
  if (doc == null) return reply.status(404).send({ ok: false, error: "no contract to approve" });
64092
64271
  const v = validateContract(doc);
64093
64272
  if (!v.valid) return reply.status(400).send({ ok: false, error: "stored contract is invalid \u2014 re-save it in the editor" });
@@ -64243,7 +64422,7 @@ async function startServer() {
64243
64422
  }
64244
64423
  const companionId = `${req.params.appId}-ifc`;
64245
64424
  const filename = `${req.params.appId}.ifc`;
64246
- const outPath = (0, import_node_path29.join)(appPath(companionId), filename);
64425
+ const outPath = (0, import_node_path30.join)(appPath(companionId), filename);
64247
64426
  let flo;
64248
64427
  try {
64249
64428
  flo = writeIfcApp(appPath(companionId), companionId, scene, outPath, writeOpts);
@@ -64266,8 +64445,8 @@ async function startServer() {
64266
64445
  }
64267
64446
  throw e;
64268
64447
  }
64269
- if (!(0, import_node_fs31.existsSync)(outPath)) return reply.send({ ok: false, error: "the IFC export produced no file" });
64270
- const content = (0, import_node_fs31.readFileSync)(outPath, "utf8");
64448
+ if (!(0, import_node_fs32.existsSync)(outPath)) return reply.send({ ok: false, error: "the IFC export produced no file" });
64449
+ const content = (0, import_node_fs32.readFileSync)(outPath, "utf8");
64271
64450
  broadcast({ type: "apps-changed" });
64272
64451
  return { ok: true, filename, content, bytes: Buffer.byteLength(content), skipped, ...extrusionsSkipped ? { extrusionsSkipped } : {} };
64273
64452
  });
@@ -64346,17 +64525,17 @@ async function startServer() {
64346
64525
  return reply.status(422).send({ ok: false, error: "no priced members to export \u2014 every member is an RFI (no AISC size / weight yet)" });
64347
64526
  }
64348
64527
  const outPath = bomExportPath(appId, format);
64349
- const dir = (0, import_node_path29.dirname)(outPath);
64528
+ const dir = (0, import_node_path30.dirname)(outPath);
64350
64529
  const filename = `${appId}-bom.${format}`;
64351
64530
  try {
64352
- (0, import_node_fs31.mkdirSync)(dir, { recursive: true });
64531
+ (0, import_node_fs32.mkdirSync)(dir, { recursive: true });
64353
64532
  if (format === "csv") {
64354
64533
  const text = bomToCsv(bom);
64355
- (0, import_node_fs31.writeFileSync)(outPath, text, "utf8");
64534
+ (0, import_node_fs32.writeFileSync)(outPath, text, "utf8");
64356
64535
  return { ok: true, filename, encoding: "utf8", content: text, bytes: Buffer.byteLength(text), savedTo: outPath };
64357
64536
  }
64358
64537
  const buf = await bomToXlsx(bom);
64359
- (0, import_node_fs31.writeFileSync)(outPath, buf);
64538
+ (0, import_node_fs32.writeFileSync)(outPath, buf);
64360
64539
  return { ok: true, filename, encoding: "base64", content: buf.toString("base64"), bytes: buf.length, savedTo: outPath };
64361
64540
  } catch (e) {
64362
64541
  app.log.error({ appId, format, err: e instanceof Error ? e.message : e }, "export-bom: generation failed");
@@ -64426,7 +64605,7 @@ async function startServer() {
64426
64605
  return reply.status(404).send({ ok: false, error: `"${id}" is not installed`, code: "not-installed" });
64427
64606
  }
64428
64607
  const contract = readContract(id);
64429
- if (contract == null && (0, import_node_fs31.existsSync)(contractPath(id))) {
64608
+ if (contract == null && (0, import_node_fs32.existsSync)(contractPath(id))) {
64430
64609
  return reply.status(409).send({ ok: false, error: `"${id}"'s saved data is unreadable \u2014 open it in the editor and re-save before restoring`, code: "contract-corrupt" });
64431
64610
  }
64432
64611
  if (contract != null) {
@@ -64504,11 +64683,11 @@ async function startServer() {
64504
64683
  if (appExists(id)) {
64505
64684
  return reply.status(409).send({ ok: false, error: `a workflow named "${id}" is already installed \u2014 remove it first, or rename the file's app: id`, code: "exists", id });
64506
64685
  }
64507
- const stageRoot = (0, import_node_fs31.mkdtempSync)((0, import_node_path29.join)((0, import_node_os20.tmpdir)(), "floless-import-"));
64686
+ const stageRoot = (0, import_node_fs32.mkdtempSync)((0, import_node_path30.join)((0, import_node_os21.tmpdir)(), "floless-import-"));
64508
64687
  try {
64509
- const stageDir = (0, import_node_path29.join)(stageRoot, id);
64510
- (0, import_node_fs31.mkdirSync)(stageDir);
64511
- (0, import_node_fs31.writeFileSync)((0, import_node_path29.join)(stageDir, `${id}.flo`), content);
64688
+ const stageDir = (0, import_node_path30.join)(stageRoot, id);
64689
+ (0, import_node_fs32.mkdirSync)(stageDir);
64690
+ (0, import_node_fs32.writeFileSync)((0, import_node_path30.join)(stageDir, `${id}.flo`), content);
64512
64691
  await aware.install(stageDir);
64513
64692
  } catch (err2) {
64514
64693
  try {
@@ -64518,7 +64697,7 @@ async function startServer() {
64518
64697
  const msg = err2 instanceof AwareError ? err2.message : String(err2?.message ?? err2);
64519
64698
  return reply.status(502).send({ ok: false, error: `import failed: ${msg}` });
64520
64699
  } finally {
64521
- (0, import_node_fs31.rmSync)(stageRoot, { recursive: true, force: true });
64700
+ (0, import_node_fs32.rmSync)(stageRoot, { recursive: true, force: true });
64522
64701
  }
64523
64702
  broadcast({ type: "apps-changed", id });
64524
64703
  return { ok: true, id };
@@ -64532,13 +64711,13 @@ async function startServer() {
64532
64711
  }
64533
64712
  const inputs = appData.inputs.map((i) => ({ name: i.name, type: i.type }));
64534
64713
  const baked = bakeFloSource(appData.source.text, inputs);
64535
- const tmpRoot = (0, import_node_fs31.mkdtempSync)((0, import_node_path29.join)((0, import_node_os20.tmpdir)(), "floless-bake-"));
64536
- const backupDir2 = (0, import_node_path29.join)(tmpRoot, `${id}-backup`);
64537
- const bakeDir = (0, import_node_path29.join)(tmpRoot, id);
64538
- (0, import_node_fs31.cpSync)(appDir(id), backupDir2, { recursive: true });
64539
- (0, import_node_fs31.cpSync)(appDir(id), bakeDir, { recursive: true });
64714
+ const tmpRoot = (0, import_node_fs32.mkdtempSync)((0, import_node_path30.join)((0, import_node_os21.tmpdir)(), "floless-bake-"));
64715
+ const backupDir2 = (0, import_node_path30.join)(tmpRoot, `${id}-backup`);
64716
+ const bakeDir = (0, import_node_path30.join)(tmpRoot, id);
64717
+ (0, import_node_fs32.cpSync)(appDir(id), backupDir2, { recursive: true });
64718
+ (0, import_node_fs32.cpSync)(appDir(id), bakeDir, { recursive: true });
64540
64719
  const floName = appData.source.path.split(/[\\/]/).pop();
64541
- (0, import_node_fs31.writeFileSync)((0, import_node_path29.join)(bakeDir, floName), baked);
64720
+ (0, import_node_fs32.writeFileSync)((0, import_node_path30.join)(bakeDir, floName), baked);
64542
64721
  let appInstalled2 = true;
64543
64722
  try {
64544
64723
  await aware.uninstall(id);
@@ -64560,17 +64739,17 @@ async function startServer() {
64560
64739
  throw installErr;
64561
64740
  }
64562
64741
  try {
64563
- await aware.compile((0, import_node_path29.join)(appDir(id), floName));
64742
+ await aware.compile((0, import_node_path30.join)(appDir(id), floName));
64564
64743
  } catch (compileErr) {
64565
64744
  app.log.warn({ id, compileErr: String(compileErr) }, "bake: post-install recompile failed (app baked but may need a manual Compile)");
64566
64745
  }
64567
64746
  broadcast({ type: "baked", id });
64568
64747
  return { ok: true, id, agent: id, inputs };
64569
64748
  } finally {
64570
- if (appInstalled2) (0, import_node_fs31.rmSync)(tmpRoot, { recursive: true, force: true });
64749
+ if (appInstalled2) (0, import_node_fs32.rmSync)(tmpRoot, { recursive: true, force: true });
64571
64750
  }
64572
64751
  });
64573
- const graftAgentsDir = () => (0, import_node_path29.join)((0, import_node_os20.homedir)(), ".aware", "agents");
64752
+ const graftAgentsDir = () => (0, import_node_path30.join)((0, import_node_os21.homedir)(), ".aware", "agents");
64574
64753
  app.post("/api/graft/match", async (req, reply) => {
64575
64754
  const { glob } = req.body ?? {};
64576
64755
  if (!glob) return reply.status(400).send({ ok: false, error: "glob required" });
@@ -64587,7 +64766,7 @@ async function startServer() {
64587
64766
  if (!sourceKind || !sourceRef) {
64588
64767
  return reply.status(400).send({ ok: false, error: "sourceKind and sourceRef required" });
64589
64768
  }
64590
- const tempHome = (0, import_node_fs31.mkdtempSync)((0, import_node_path29.join)((0, import_node_os20.tmpdir)(), "floless-graft-"));
64769
+ const tempHome = (0, import_node_fs32.mkdtempSync)((0, import_node_path30.join)((0, import_node_os21.tmpdir)(), "floless-graft-"));
64591
64770
  let result;
64592
64771
  try {
64593
64772
  result = await aware.build({
@@ -64600,19 +64779,19 @@ async function startServer() {
64600
64779
  awareHome: tempHome
64601
64780
  });
64602
64781
  } catch (err2) {
64603
- (0, import_node_fs31.rmSync)(tempHome, { recursive: true, force: true });
64782
+ (0, import_node_fs32.rmSync)(tempHome, { recursive: true, force: true });
64604
64783
  const msg = err2 instanceof AwareError ? err2.message : String(err2?.message ?? err2);
64605
64784
  return reply.status(422).send({ ok: false, error: msg });
64606
64785
  }
64607
64786
  const manifest = readStagedManifest(result.agentDir);
64608
64787
  if (!manifest) {
64609
- (0, import_node_fs31.rmSync)(tempHome, { recursive: true, force: true });
64788
+ (0, import_node_fs32.rmSync)(tempHome, { recursive: true, force: true });
64610
64789
  return reply.status(502).send({ ok: false, error: `build produced output at ${result.agentDir} but no manifest.yaml` });
64611
64790
  }
64612
- const token = (0, import_node_crypto7.randomUUID)();
64791
+ const token = (0, import_node_crypto8.randomUUID)();
64613
64792
  registerStage(token, tempHome, result.agentId);
64614
64793
  const preview = buildPreview(manifest, sourceKind, sourceRef, token);
64615
- if ((0, import_node_fs31.existsSync)((0, import_node_path29.join)(graftAgentsDir(), result.agentId))) {
64794
+ if ((0, import_node_fs32.existsSync)((0, import_node_path30.join)(graftAgentsDir(), result.agentId))) {
64616
64795
  preview.warnings.unshift(`An agent named "${result.agentId}" is already installed \u2014 creating it will overwrite it.`);
64617
64796
  }
64618
64797
  return { ok: true, preview };
@@ -64631,7 +64810,7 @@ async function startServer() {
64631
64810
  registerStage(stagedRef, stage.tempDir, stage.agentId);
64632
64811
  return reply.status(409).send({ ok: false, error: err2.message, agentId: stage.agentId, collision: true });
64633
64812
  }
64634
- (0, import_node_fs31.rmSync)(stage.tempDir, { recursive: true, force: true });
64813
+ (0, import_node_fs32.rmSync)(stage.tempDir, { recursive: true, force: true });
64635
64814
  throw err2;
64636
64815
  }
64637
64816
  broadcast({ type: "grafted", id: stage.agentId });
@@ -64902,11 +65081,11 @@ async function startServer() {
64902
65081
  app.get("/api/requests/:id/snapshot/:n", async (req, reply) => {
64903
65082
  const n = Number.parseInt(req.params.n, 10);
64904
65083
  const p = Number.isInteger(n) ? snapshotPathFor(req.params.id, n) : null;
64905
- if (!p || !(0, import_node_fs31.existsSync)(p)) return reply.status(404).send({ ok: false, error: "snapshot not found" });
65084
+ if (!p || !(0, import_node_fs32.existsSync)(p)) return reply.status(404).send({ ok: false, error: "snapshot not found" });
64906
65085
  const ext = p.split(".").pop().toLowerCase();
64907
65086
  reply.header("Content-Type", ext === "png" ? "image/png" : ext === "webp" ? "image/webp" : ext === "pdf" ? "application/pdf" : "image/jpeg");
64908
65087
  reply.header("Cache-Control", "no-store");
64909
- return (0, import_node_fs31.readFileSync)(p);
65088
+ return (0, import_node_fs32.readFileSync)(p);
64910
65089
  });
64911
65090
  app.post(
64912
65091
  "/api/tweak",
@@ -64931,7 +65110,7 @@ async function startServer() {
64931
65110
  "/api/contract-request",
64932
65111
  { bodyLimit: 25 * 1024 * 1024 },
64933
65112
  async (req, reply) => {
64934
- const { appId, instruction, intent, target, snapshots } = req.body ?? {};
65113
+ const { appId, project, instruction, intent, target, snapshots } = req.body ?? {};
64935
65114
  if (!appId || !instruction) {
64936
65115
  return reply.status(400).send({ ok: false, error: "appId, instruction required" });
64937
65116
  }
@@ -64942,7 +65121,7 @@ async function startServer() {
64942
65121
  return reply.status(400).send({ ok: false, error: e instanceof Error ? e.message : "bad snapshot" });
64943
65122
  }
64944
65123
  const request = addRequest(
64945
- { type: "tweak-contract", appId, instruction, ...intent ? { intent } : {}, ...target ? { target } : {} },
65124
+ { type: "tweak-contract", appId, ...project ? { project } : {}, instruction, ...intent ? { intent } : {}, ...target ? { target } : {} },
64946
65125
  decoded
64947
65126
  );
64948
65127
  broadcast({ type: "request-added", request });
@@ -65075,7 +65254,7 @@ async function startServer() {
65075
65254
  warn(`last-run-status:${ref} \u2014 trace exists but couldn't be parsed (corrupt/truncated)`);
65076
65255
  let finishedAt2 = null;
65077
65256
  try {
65078
- finishedAt2 = (0, import_node_fs31.statSync)(latest.path).mtime.toISOString();
65257
+ finishedAt2 = (0, import_node_fs32.statSync)(latest.path).mtime.toISOString();
65079
65258
  } catch {
65080
65259
  finishedAt2 = null;
65081
65260
  }
@@ -65085,7 +65264,7 @@ async function startServer() {
65085
65264
  let finishedAt = typeof runEnd?.ts === "string" ? runEnd.ts : null;
65086
65265
  if (!finishedAt) {
65087
65266
  try {
65088
- finishedAt = (0, import_node_fs31.statSync)(latest.path).mtime.toISOString();
65267
+ finishedAt = (0, import_node_fs32.statSync)(latest.path).mtime.toISOString();
65089
65268
  } catch {
65090
65269
  finishedAt = null;
65091
65270
  }