@lotics/cli 0.64.0 → 0.66.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.
package/dist/src/cli.js CHANGED
@@ -3387,7 +3387,7 @@ var require_jstat = __commonJS({
3387
3387
  }
3388
3388
  })(exports2, function() {
3389
3389
  var jStat = (function(Math2, undefined2) {
3390
- var concat = Array.prototype.concat;
3390
+ var concat2 = Array.prototype.concat;
3391
3391
  var slice = Array.prototype.slice;
3392
3392
  var toString = Object.prototype.toString;
3393
3393
  function calcRdx(n, m) {
@@ -3407,7 +3407,7 @@ var require_jstat = __commonJS({
3407
3407
  return typeof num === "number" ? num - num === 0 : false;
3408
3408
  }
3409
3409
  function toVector(arr) {
3410
- return concat.apply([], arr);
3410
+ return concat2.apply([], arr);
3411
3411
  }
3412
3412
  function jStat2() {
3413
3413
  return new jStat2._init(arguments);
@@ -20136,7 +20136,7 @@ var require_BufferList = __commonJS({
20136
20136
  }
20137
20137
  return ret;
20138
20138
  };
20139
- BufferList.prototype.concat = function concat(n) {
20139
+ BufferList.prototype.concat = function concat2(n) {
20140
20140
  if (this.length === 0) return Buffer2.alloc(0);
20141
20141
  var ret = Buffer2.allocUnsafe(n >>> 0);
20142
20142
  var p = this.head;
@@ -23322,7 +23322,7 @@ var require_StreamHelper = __commonJS({
23322
23322
  return utils.transformTo(type, content);
23323
23323
  }
23324
23324
  }
23325
- function concat(type, dataArray) {
23325
+ function concat2(type, dataArray) {
23326
23326
  var i2, index = 0, res = null, totalLength = 0;
23327
23327
  for (i2 = 0; i2 < dataArray.length; i2++) {
23328
23328
  totalLength += dataArray[i2].length;
@@ -23359,7 +23359,7 @@ var require_StreamHelper = __commonJS({
23359
23359
  reject2(err2);
23360
23360
  }).on("end", function() {
23361
23361
  try {
23362
- var result = transformZipOutput(resultType, concat(chunkType, dataArray), mimeType);
23362
+ var result = transformZipOutput(resultType, concat2(chunkType, dataArray), mimeType);
23363
23363
  resolve(result);
23364
23364
  } catch (e) {
23365
23365
  reject2(e);
@@ -29881,6 +29881,17 @@ var LoticsClient = class {
29881
29881
  ...body.description ? { description: body.description } : {}
29882
29882
  });
29883
29883
  }
29884
+ /**
29885
+ * Bind (create or replace) an app query by alias via the `set_app_query` tool
29886
+ * — the deploy-free authoring path for `apps.queries`, parallel to
29887
+ * `setAppWorkflow`. `declaration` is the `{ ast, params? }` from
29888
+ * `package.json#lotics.queries.<alias>`. The server validates it exactly as a
29889
+ * deploy validates the manifest. Note: `apps.queries` is manifest-authoritative,
29890
+ * so the next `lotics app deploy` overwrites this from the manifest.
29891
+ */
29892
+ async setAppQuery(app_id, alias, declaration) {
29893
+ return this.execute("set_app_query", { app_id, alias, declaration });
29894
+ }
29884
29895
  /**
29885
29896
  * Fetch one app workflow's faithful source + bound input/output schemas via
29886
29897
  * `get_app_workflow`. `source` is the JS-subset body re-rendered from the
@@ -30004,6 +30015,7 @@ var LoticsClient = class {
30004
30015
  if (args.capabilities !== void 0) {
30005
30016
  formData.append("capabilities", JSON.stringify(args.capabilities));
30006
30017
  }
30018
+ formData.append("workflow_aliases", JSON.stringify(args.workflow_aliases ?? []));
30007
30019
  const url = `${this.baseUrl}/v1/apps/${encodeURIComponent(args.app_id)}/versions`;
30008
30020
  const response = await fetch(url, {
30009
30021
  method: "POST",
@@ -31803,7 +31815,7 @@ function inputDeclToTsType(decl) {
31803
31815
  case "date_range":
31804
31816
  return "{ start: string; end: string }";
31805
31817
  case "file":
31806
- return "string";
31818
+ return decl.multi === true ? "ReadonlyArray<string>" : "string";
31807
31819
  case "object": {
31808
31820
  const fields = decl.fields !== null && typeof decl.fields === "object" ? decl.fields : {};
31809
31821
  return inputsToType(fields);
@@ -32219,6 +32231,8 @@ async function fetchLatestNpmVersion(packageName) {
32219
32231
  var WORKFLOWS_DIR = path5.join("src", "workflows");
32220
32232
  var WORKFLOW_GLOBALS_DIR = path5.join(".lotics", "workflows");
32221
32233
  var WORKFLOW_TSCONFIG_EXCLUDES = ["src/workflows", ".lotics/workflows"];
32234
+ var LOTICS_INCLUDE_GLOB = ".lotics/**/*";
32235
+ var STALE_LOTICS_INCLUDES = /* @__PURE__ */ new Set([".lotics", "./.lotics", ".lotics/"]);
32222
32236
  var FALLBACK_ENVELOPE_PREFIX = "async function __workflow(): Promise<__WorkflowReturn | void> {\n";
32223
32237
  var FALLBACK_ENVELOPE_SUFFIX = "\n}";
32224
32238
  function workflowFileHeader(alias) {
@@ -32362,11 +32376,11 @@ function writeAppMeta(projectDir, meta) {
32362
32376
  pkg2.lotics = meta;
32363
32377
  fs4.writeFileSync(pkgPath2, JSON.stringify(pkg2, null, 2) + "\n");
32364
32378
  }
32365
- function ensureWorkflowTsconfigExcludes(projectDir) {
32379
+ function ensureAppTsconfig(projectDir) {
32366
32380
  const tsconfigPath = path5.join(projectDir, "tsconfig.json");
32367
32381
  if (!fs4.existsSync(tsconfigPath)) {
32368
32382
  console.error(
32369
- `\u26A0 No tsconfig.json at ${projectDir} \u2014 could not ensure ${WORKFLOW_TSCONFIG_EXCLUDES.join(", ")} are excluded. Add them to your tsconfig's "exclude" so npm run typecheck skips the workflow bodies.`
32383
+ `\u26A0 No tsconfig.json at ${projectDir} \u2014 could not ensure "include" has "${LOTICS_INCLUDE_GLOB}" (a bare .lotics loads none of the generated types) or "exclude" has ${WORKFLOW_TSCONFIG_EXCLUDES.join(", ")}.`
32370
32384
  );
32371
32385
  return;
32372
32386
  }
@@ -32375,20 +32389,29 @@ function ensureWorkflowTsconfigExcludes(projectDir) {
32375
32389
  parsed = JSON.parse(fs4.readFileSync(tsconfigPath, "utf-8"));
32376
32390
  } catch (err2) {
32377
32391
  console.error(
32378
- `\u26A0 Could not parse tsconfig.json (${err2 instanceof Error ? err2.message : String(err2)}) \u2014 add ${WORKFLOW_TSCONFIG_EXCLUDES.join(", ")} to its "exclude" manually so npm run typecheck skips the workflow bodies.`
32392
+ `\u26A0 Could not parse tsconfig.json (${err2 instanceof Error ? err2.message : String(err2)}) \u2014 ensure "include" has "${LOTICS_INCLUDE_GLOB}" and "exclude" has ${WORKFLOW_TSCONFIG_EXCLUDES.join(", ")} manually.`
32379
32393
  );
32380
32394
  return;
32381
32395
  }
32382
32396
  if (!parsed || typeof parsed !== "object") return;
32383
- const current = Array.isArray(parsed.exclude) ? parsed.exclude : [];
32384
- const currentStrings = current.filter((e) => typeof e === "string");
32385
- const toAdd = WORKFLOW_TSCONFIG_EXCLUDES.filter((g) => !currentStrings.includes(g));
32386
- if (toAdd.length === 0) return;
32387
- parsed.exclude = [...currentStrings, ...toAdd];
32397
+ const changes = [];
32398
+ if (Array.isArray(parsed.include)) {
32399
+ const inc = parsed.include.filter((e) => typeof e === "string");
32400
+ if (inc.some((e) => STALE_LOTICS_INCLUDES.has(e))) {
32401
+ const healed = inc.map((e) => STALE_LOTICS_INCLUDES.has(e) ? LOTICS_INCLUDE_GLOB : e);
32402
+ parsed.include = healed.filter((e, i2) => healed.indexOf(e) === i2);
32403
+ changes.push(`rewrote a bare ".lotics" to "${LOTICS_INCLUDE_GLOB}" in "include" (a dot-dir loads zero generated types)`);
32404
+ }
32405
+ }
32406
+ const currentEx = Array.isArray(parsed.exclude) ? parsed.exclude.filter((e) => typeof e === "string") : [];
32407
+ const toAdd = WORKFLOW_TSCONFIG_EXCLUDES.filter((g) => !currentEx.includes(g));
32408
+ if (toAdd.length > 0) {
32409
+ parsed.exclude = [...currentEx, ...toAdd];
32410
+ changes.push(`added ${toAdd.join(", ")} to "exclude"`);
32411
+ }
32412
+ if (changes.length === 0) return;
32388
32413
  fs4.writeFileSync(tsconfigPath, JSON.stringify(parsed, null, 2) + "\n");
32389
- console.error(
32390
- `Patched tsconfig.json: added ${toAdd.join(", ")} to "exclude" so npm run typecheck skips the workflow bodies (check them with: lotics app workflow check).`
32391
- );
32414
+ console.error(`Patched tsconfig.json: ${changes.join("; ")}.`);
32392
32415
  }
32393
32416
  function writeAppDts(projectDir, manifest) {
32394
32417
  const dotLotics = path5.join(projectDir, ".lotics");
@@ -32399,6 +32422,7 @@ function writeAppDts(projectDir, manifest) {
32399
32422
  [path5.join(dotLotics, "app_agents.d.ts"), generateAppAgentsDts(manifest.agents)]
32400
32423
  ];
32401
32424
  for (const [file, content] of written) fs4.writeFileSync(file, content);
32425
+ ensureAppTsconfig(projectDir);
32402
32426
  return written.map(([file]) => file);
32403
32427
  }
32404
32428
  function readCodegenTablesAllowlist(projectDir) {
@@ -32447,7 +32471,6 @@ async function appCodegen(args) {
32447
32471
  );
32448
32472
  }
32449
32473
  await refreshWorkflowGlobals(args.client, projectDir, meta.app_id, Object.keys(meta.workflows ?? {}));
32450
- if (Object.keys(meta.workflows ?? {}).length > 0) ensureWorkflowTsconfigExcludes(projectDir);
32451
32474
  }
32452
32475
  async function refreshWorkflowGlobals(client, projectDir, app_id, aliases) {
32453
32476
  for (const alias of aliases) {
@@ -32630,7 +32653,6 @@ async function appPull(client, args) {
32630
32653
  `Wrote ${written.length} workflow ${written.length === 1 ? "body" : "bodies"} to ${WORKFLOWS_DIR}/ (${written.join(", ")})`
32631
32654
  );
32632
32655
  }
32633
- ensureWorkflowTsconfigExcludes(targetPath);
32634
32656
  }
32635
32657
  console.error(`Installing npm dependencies...`);
32636
32658
  await runNpm(["install"], targetPath);
@@ -32720,10 +32742,14 @@ async function appDeploy(client, args) {
32720
32742
  // defaulting to `{}` when the manifest declares none — so deleting the
32721
32743
  // `capabilities` block turns every capability OFF on the next deploy
32722
32744
  // (fail-safe; the declaration is the grant).
32723
- capabilities: meta.capabilities ?? {}
32724
- // Workflow bindings are NOT a deploy concern — set_app_workflow /
32725
- // remove_app_workflow own apps.workflows. The manifest's `workflows`
32726
- // map is a pulled reflection used only for the .d.ts codegen above.
32745
+ capabilities: meta.capabilities ?? {},
32746
+ // Workflow BINDINGS are NOT a deploy concern — set_app_workflow /
32747
+ // remove_app_workflow own apps.workflows. But the alias KEYS of the
32748
+ // manifest's `workflows` map ARE sent (never the bindings): they record
32749
+ // which aliases this bundle declares, so remove_app_workflow can refuse
32750
+ // to unbind an alias the served version still calls. Drop an alias from
32751
+ // the manifest + redeploy to lift that guard before removing its binding.
32752
+ workflow_aliases: Object.keys(meta.workflows ?? {})
32727
32753
  });
32728
32754
  writeAppMeta(projectDir, {
32729
32755
  ...meta,
@@ -32932,6 +32958,25 @@ async function appWorkflowSet(client, args) {
32932
32958
  console.error(` result.data schema: ${JSON.stringify(result.outputs)}`);
32933
32959
  }
32934
32960
  }
32961
+ async function appQuerySet(client, args) {
32962
+ const projectDir = process.cwd();
32963
+ const meta = readAppMeta(projectDir);
32964
+ const declaration = meta.queries?.[args.alias];
32965
+ if (!declaration) {
32966
+ console.error(
32967
+ `No query "${args.alias}" in package.json#lotics.queries. Declare it there (alias \u2192 { ast, params? }) first.`
32968
+ );
32969
+ process.exit(1);
32970
+ }
32971
+ const res = await client.setAppQuery(meta.app_id, args.alias, declaration);
32972
+ if (res.error) {
32973
+ console.error(`Failed to set query "${args.alias}": ${res.error}`);
32974
+ process.exit(1);
32975
+ }
32976
+ console.error(
32977
+ `Set query "${args.alias}" on ${meta.app_id}. (apps.queries is manifest-authoritative \u2014 the next 'lotics app deploy' re-syncs it.)`
32978
+ );
32979
+ }
32935
32980
  async function appWorkflowPull(client) {
32936
32981
  const projectDir = process.cwd();
32937
32982
  const meta = readAppMeta(projectDir);
@@ -32945,7 +32990,7 @@ async function appWorkflowPull(client) {
32945
32990
  console.error(
32946
32991
  `Wrote ${written.length} workflow ${written.length === 1 ? "body" : "bodies"} to ${WORKFLOWS_DIR}/` + (written.length > 0 ? ` (${written.join(", ")})` : "")
32947
32992
  );
32948
- ensureWorkflowTsconfigExcludes(projectDir);
32993
+ ensureAppTsconfig(projectDir);
32949
32994
  }
32950
32995
  async function appWorkflowCheck(args) {
32951
32996
  const projectDir = process.cwd();
@@ -33040,10 +33085,11 @@ function appUiLink(args) {
33040
33085
  `No vite.config.ts at ${projectDir}. Run inside a 'lotics app' project directory.`
33041
33086
  );
33042
33087
  }
33043
- const uiSrc = findUiSrcDir(projectDir);
33044
- if (!uiSrc) {
33088
+ const explicit = args.uiSrc ?? process.env.LOTICS_UI_SRC;
33089
+ const uiSrc = explicit ? path5.resolve(explicit) : findUiSrcDir(projectDir);
33090
+ if (!uiSrc || !fs4.existsSync(uiSrc) || !fs4.statSync(uiSrc).isDirectory()) {
33045
33091
  throw new Error(
33046
- "Cannot find packages/ui/src by walking up from this directory \u2014 `lotics ui link` requires a monorepo checkout. External apps consume @lotics/ui from npm; bump the package version and widen the app's dependency range instead."
33092
+ explicit ? `--ui-src / LOTICS_UI_SRC points at '${explicit}', which is not a directory. Pass the absolute path to the monorepo's packages/ui/src.` : "Cannot find packages/ui/src by walking up from this directory. For an EXTERNAL app (consuming @lotics/ui from npm), pass --ui-src=<abs path to packages/ui/src> or set LOTICS_UI_SRC; inside a monorepo checkout it is found automatically."
33047
33093
  );
33048
33094
  }
33049
33095
  const hasComponent = fs4.existsSync(path5.join(uiSrc, `${args.component}.tsx`)) || fs4.existsSync(path5.join(uiSrc, `${args.component}.ts`)) || fs4.existsSync(path5.join(uiSrc, args.component));
@@ -33098,6 +33144,7 @@ function parseArgs(argv) {
33098
33144
  apiKey: void 0,
33099
33145
  workspace: void 0,
33100
33146
  viewAs: void 0,
33147
+ uiSrc: void 0,
33101
33148
  name: void 0,
33102
33149
  timezone: void 0,
33103
33150
  message: void 0,
@@ -33139,6 +33186,9 @@ function parseArgs(argv) {
33139
33186
  case "--view-as":
33140
33187
  flags.viewAs = argv[++i2];
33141
33188
  break;
33189
+ case "--ui-src":
33190
+ flags.uiSrc = argv[++i2];
33191
+ break;
33142
33192
  case "--name":
33143
33193
  flags.name = argv[++i2];
33144
33194
  break;
@@ -42644,8 +42694,426 @@ function ensureVmlArray(val) {
42644
42694
  return Array.isArray(val) ? val : [val];
42645
42695
  }
42646
42696
 
42697
+ // ../xlsx/src/biff8_reader.ts
42698
+ var OLE2_MAGIC2 = [208, 207, 17, 224, 161, 177, 26, 225];
42699
+ var ENDOFCHAIN = 4294967294;
42700
+ var FREESECT = 4294967295;
42701
+ var DEFAULT_MAX_ROWS = 1e4;
42702
+ function isOle2(bytes) {
42703
+ return bytes.length >= 8 && OLE2_MAGIC2.every((b, i2) => bytes[i2] === b);
42704
+ }
42705
+ function readCfbStreams(bytes) {
42706
+ const dv = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
42707
+ const u162 = (o) => dv.getUint16(o, true);
42708
+ const u32 = (o) => dv.getUint32(o, true);
42709
+ const sectorSize = 1 << u162(30);
42710
+ const miniSectorSize = 1 << u162(32);
42711
+ const firstDirSector = u32(48);
42712
+ const miniCutoff = u32(56);
42713
+ const firstMiniFatSector = u32(60);
42714
+ const firstDifatSector = u32(68);
42715
+ if (sectorSize < 512 || sectorSize > 1 << 20) {
42716
+ throw new Error("Unsupported .xls: invalid OLE2 sector size");
42717
+ }
42718
+ const sectorOffset = (n) => sectorSize * (n + 1);
42719
+ const difat = [];
42720
+ for (let i2 = 0; i2 < 109; i2++) {
42721
+ const v = u32(76 + i2 * 4);
42722
+ if (v !== FREESECT) difat.push(v);
42723
+ }
42724
+ let ds = firstDifatSector;
42725
+ const entriesPerSector = sectorSize / 4;
42726
+ for (let guard = 0; ds !== ENDOFCHAIN && ds !== FREESECT && guard < 1 << 20; guard++) {
42727
+ const base = sectorOffset(ds);
42728
+ for (let i2 = 0; i2 < entriesPerSector - 1; i2++) {
42729
+ const v = u32(base + i2 * 4);
42730
+ if (v !== FREESECT) difat.push(v);
42731
+ }
42732
+ ds = u32(base + (entriesPerSector - 1) * 4);
42733
+ }
42734
+ const fat = [];
42735
+ for (const fatSector of difat) {
42736
+ const base = sectorOffset(fatSector);
42737
+ for (let i2 = 0; i2 < entriesPerSector; i2++) fat.push(u32(base + i2 * 4));
42738
+ }
42739
+ const readChain = (src, start, size, ss, offOf, chain) => {
42740
+ const maxSectors = Math.floor(src.length / ss) + 2;
42741
+ const parts = [];
42742
+ let s = start;
42743
+ for (let guard = 0; s !== ENDOFCHAIN && s !== FREESECT && s < chain.length && guard < maxSectors; guard++) {
42744
+ const o = offOf(s);
42745
+ parts.push(src.subarray(o, o + ss));
42746
+ s = chain[s];
42747
+ }
42748
+ const merged = concat(parts);
42749
+ return size != null ? merged.subarray(0, size) : merged;
42750
+ };
42751
+ const readBig = (start, size) => readChain(bytes, start, size, sectorSize, sectorOffset, fat);
42752
+ const dirBytes = readBig(firstDirSector, null);
42753
+ const ddv = new DataView(dirBytes.buffer, dirBytes.byteOffset, dirBytes.byteLength);
42754
+ const dir = [];
42755
+ for (let off = 0; off + 128 <= dirBytes.length; off += 128) {
42756
+ const nameLen = ddv.getUint16(off + 64, true);
42757
+ const type = ddv.getUint8(off + 66);
42758
+ if (nameLen < 2 || type === 0) continue;
42759
+ const name = utf16le(dirBytes.subarray(off, off + nameLen - 2));
42760
+ dir.push({ name, type, start: ddv.getUint32(off + 116, true), size: Number(ddv.getBigUint64(off + 120, true)) });
42761
+ }
42762
+ const root = dir.find((e) => e.type === 5);
42763
+ const miniStream = root ? readBig(root.start, root.size) : new Uint8Array(0);
42764
+ const miniFatBytes = readBig(firstMiniFatSector, null);
42765
+ const miniFat = [];
42766
+ for (let i2 = 0; i2 + 4 <= miniFatBytes.length; i2 += 4) miniFat.push(miniFatBytes[i2] | miniFatBytes[i2 + 1] << 8 | miniFatBytes[i2 + 2] << 16 | miniFatBytes[i2 + 3] << 24);
42767
+ const readMini = (start, size) => readChain(miniStream, start, size, miniSectorSize, (n) => n * miniSectorSize, miniFat);
42768
+ const readStream = (e) => e.size >= miniCutoff ? readBig(e.start, e.size) : readMini(e.start, e.size);
42769
+ return dir.filter((e) => e.type === 2).map((e) => ({ name: e.name, bytes: readStream(e) }));
42770
+ }
42771
+ var REC = {
42772
+ FORMULA: 6,
42773
+ EOF: 10,
42774
+ CONTINUE: 60,
42775
+ DATEMODE: 34,
42776
+ FILEPASS: 47,
42777
+ BLANK: 513,
42778
+ NUMBER: 515,
42779
+ LABEL: 516,
42780
+ STRING: 519,
42781
+ BOOLERR: 517,
42782
+ BOUNDSHEET: 133,
42783
+ FORMAT: 1054,
42784
+ XF: 224,
42785
+ RK: 638,
42786
+ MULRK: 189,
42787
+ MULBLANK: 190,
42788
+ LABELSST: 253,
42789
+ SST: 252,
42790
+ BOF: 2057
42791
+ };
42792
+ function* iterRecords(stream, from, to) {
42793
+ const dv = new DataView(stream.buffer, stream.byteOffset, stream.byteLength);
42794
+ let p = from;
42795
+ while (p + 4 <= to) {
42796
+ const type = dv.getUint16(p, true);
42797
+ const len = dv.getUint16(p + 2, true);
42798
+ const bodyStart = p + 4;
42799
+ if (bodyStart + len > stream.length) break;
42800
+ yield { type, body: stream.subarray(bodyStart, bodyStart + len), offset: p };
42801
+ p = bodyStart + len;
42802
+ }
42803
+ }
42804
+ function parseGlobals(stream) {
42805
+ const sstChunks = [];
42806
+ const formats = /* @__PURE__ */ new Map();
42807
+ const xfFormatIds = [];
42808
+ const boundsheets = [];
42809
+ let date1904 = false;
42810
+ let sawSst = false;
42811
+ let sstUnique = 0;
42812
+ let end = stream.length;
42813
+ let started = false;
42814
+ const dv = new DataView(stream.buffer, stream.byteOffset, stream.byteLength);
42815
+ for (const r of iterRecords(stream, 0, stream.length)) {
42816
+ if (r.type === REC.BOF) {
42817
+ if (started) {
42818
+ end = r.offset;
42819
+ break;
42820
+ }
42821
+ started = true;
42822
+ continue;
42823
+ }
42824
+ if (r.type === REC.EOF) {
42825
+ end = r.offset;
42826
+ break;
42827
+ }
42828
+ }
42829
+ for (const r of iterRecords(stream, 0, end)) {
42830
+ switch (r.type) {
42831
+ case REC.FILEPASS:
42832
+ throw new PasswordProtectedError();
42833
+ case REC.DATEMODE:
42834
+ date1904 = readU16(r.body, 0) === 1;
42835
+ break;
42836
+ case REC.SST:
42837
+ sawSst = true;
42838
+ sstUnique = readU32(r.body, 4);
42839
+ sstChunks.push(r.body.subarray(8));
42840
+ break;
42841
+ case REC.CONTINUE:
42842
+ if (sawSst) sstChunks.push(r.body);
42843
+ break;
42844
+ case REC.FORMAT: {
42845
+ const id = readU16(r.body, 0);
42846
+ formats.set(id, readUnicodeShort(r.body, 2, 2));
42847
+ break;
42848
+ }
42849
+ case REC.XF: {
42850
+ xfFormatIds.push(readU16(r.body, 2));
42851
+ break;
42852
+ }
42853
+ case REC.BOUNDSHEET: {
42854
+ const pos = dv.getUint32(r.offset + 4, true);
42855
+ boundsheets.push({ name: readUnicodeShort(r.body, 6, 1), pos });
42856
+ break;
42857
+ }
42858
+ default:
42859
+ break;
42860
+ }
42861
+ }
42862
+ const sst = parseSst(sstChunks, sstUnique);
42863
+ const xfFormats = xfFormatIds.map((id) => formats.get(id) ?? builtinFormat(id));
42864
+ return { sst, date1904, xfFormats, boundsheets };
42865
+ }
42866
+ function parseSst(chunks, count) {
42867
+ const out = [];
42868
+ if (chunks.length === 0) return out;
42869
+ let ci = 0;
42870
+ let off = 0;
42871
+ const atEnd = () => ci >= chunks.length;
42872
+ const cur = () => chunks[ci];
42873
+ const advanceChunk = () => {
42874
+ ci++;
42875
+ off = 0;
42876
+ };
42877
+ const rawU8 = () => {
42878
+ while (!atEnd() && off >= cur().length) advanceChunk();
42879
+ if (atEnd()) return 0;
42880
+ return cur()[off++];
42881
+ };
42882
+ const rawU16 = () => rawU8() | rawU8() << 8;
42883
+ const rawU32 = () => rawU8() | rawU8() << 8 | rawU8() << 16 | rawU8() << 24;
42884
+ const skip = (n) => {
42885
+ for (let i2 = 0; i2 < n; i2++) rawU8();
42886
+ };
42887
+ for (let s = 0; s < count && !atEnd(); s++) {
42888
+ const cch = rawU16();
42889
+ const grbit = rawU8();
42890
+ let high = (grbit & 1) !== 0;
42891
+ const rich = (grbit & 8) !== 0 ? rawU16() : 0;
42892
+ const ext = (grbit & 4) !== 0 ? rawU32() : 0;
42893
+ let str = "";
42894
+ let read = 0;
42895
+ while (read < cch) {
42896
+ if (off >= cur().length) {
42897
+ advanceChunk();
42898
+ if (atEnd()) break;
42899
+ high = (cur()[off++] & 1) !== 0;
42900
+ }
42901
+ if (high) {
42902
+ const code = cur()[off] | cur()[off + 1] << 8;
42903
+ off += 2;
42904
+ str += String.fromCharCode(code);
42905
+ } else {
42906
+ str += String.fromCharCode(cur()[off++]);
42907
+ }
42908
+ read++;
42909
+ }
42910
+ skip(rich * 4 + ext);
42911
+ out.push(str);
42912
+ }
42913
+ return out;
42914
+ }
42915
+ function parseSheet2(stream, start, name, g, maxRows) {
42916
+ const sheet = emptySheet(name);
42917
+ const grid = /* @__PURE__ */ new Map();
42918
+ let maxRow = -1;
42919
+ let truncated = false;
42920
+ const put = (row, col, cell) => {
42921
+ if (row >= maxRows) {
42922
+ truncated = true;
42923
+ return;
42924
+ }
42925
+ let r = grid.get(row);
42926
+ if (!r) {
42927
+ r = /* @__PURE__ */ new Map();
42928
+ grid.set(row, r);
42929
+ }
42930
+ r.set(col, cell);
42931
+ if (row > maxRow) maxRow = row;
42932
+ };
42933
+ let end = stream.length;
42934
+ let seenBof = false;
42935
+ for (const r of iterRecords(stream, start, stream.length)) {
42936
+ if (r.type === REC.BOF) {
42937
+ if (seenBof) {
42938
+ end = r.offset;
42939
+ break;
42940
+ }
42941
+ seenBof = true;
42942
+ continue;
42943
+ }
42944
+ if (r.type === REC.EOF) {
42945
+ end = r.offset;
42946
+ break;
42947
+ }
42948
+ }
42949
+ for (const r of iterRecords(stream, start, end)) {
42950
+ switch (r.type) {
42951
+ case REC.LABELSST: {
42952
+ const row = readU16(r.body, 0), col = readU16(r.body, 2), isst = readU32(r.body, 6);
42953
+ put(row, col, textCell(col, g.sst[isst] ?? ""));
42954
+ break;
42955
+ }
42956
+ case REC.LABEL: {
42957
+ const row = readU16(r.body, 0), col = readU16(r.body, 2);
42958
+ put(row, col, textCell(col, readUnicodeShort(r.body, 6, 2)));
42959
+ break;
42960
+ }
42961
+ case REC.NUMBER: {
42962
+ const row = readU16(r.body, 0), col = readU16(r.body, 2), xf = readU16(r.body, 4);
42963
+ put(row, col, numberCell(col, readF64(r.body, 6), g.xfFormats[xf]));
42964
+ break;
42965
+ }
42966
+ case REC.RK: {
42967
+ const row = readU16(r.body, 0), col = readU16(r.body, 2), xf = readU16(r.body, 4);
42968
+ put(row, col, numberCell(col, decodeRk(readU32(r.body, 6)), g.xfFormats[xf]));
42969
+ break;
42970
+ }
42971
+ case REC.MULRK: {
42972
+ const row = readU16(r.body, 0), first2 = readU16(r.body, 2);
42973
+ const n = (r.body.length - 6) / 6;
42974
+ for (let i2 = 0; i2 < n; i2++) {
42975
+ const xf = readU16(r.body, 4 + i2 * 6);
42976
+ const rk = readU32(r.body, 6 + i2 * 6);
42977
+ put(row, first2 + i2, numberCell(first2 + i2, decodeRk(rk), g.xfFormats[xf]));
42978
+ }
42979
+ break;
42980
+ }
42981
+ case REC.FORMULA: {
42982
+ const row = readU16(r.body, 0), col = readU16(r.body, 2), xf = readU16(r.body, 4);
42983
+ const cell = formulaCell(col, r.body, g.xfFormats[xf]);
42984
+ if (cell) put(row, col, cell);
42985
+ break;
42986
+ }
42987
+ // BLANK / MULBLANK / BOOLERR carry no data value we surface — skipped.
42988
+ default:
42989
+ break;
42990
+ }
42991
+ }
42992
+ const rows = [];
42993
+ for (let ri = 0; ri <= maxRow; ri++) {
42994
+ const r = grid.get(ri);
42995
+ if (!r) continue;
42996
+ const cells = [...r.values()].sort((a, b) => a.column - b.column);
42997
+ rows.push({ index: ri, height: sheet.defaultRowHeight, cells, hidden: false });
42998
+ }
42999
+ sheet.rows = rows;
43000
+ sheet.totalRowCount = maxRow + 1;
43001
+ sheet.truncated = truncated;
43002
+ return sheet;
43003
+ }
43004
+ function textCell(column, text) {
43005
+ return { column, value: text, typedValue: text, content: { type: "plain", text }, style: {} };
43006
+ }
43007
+ function numberCell(column, num, numFmt) {
43008
+ const value = Number.isFinite(num) ? String(num) : "";
43009
+ return {
43010
+ column,
43011
+ value,
43012
+ rawValue: num,
43013
+ typedValue: num,
43014
+ numFmtCode: numFmt && numFmt !== "General" ? numFmt : void 0,
43015
+ content: { type: "plain", text: value },
43016
+ style: {}
43017
+ };
43018
+ }
43019
+ function formulaCell(column, body, numFmt) {
43020
+ if (readU16(body, 12) === 65535) {
43021
+ const kind = body[6];
43022
+ if (kind === 1) {
43023
+ const b = body[8] !== 0;
43024
+ return { column, value: b ? "TRUE" : "FALSE", typedValue: b, content: { type: "plain", text: b ? "TRUE" : "FALSE" }, style: {} };
43025
+ }
43026
+ return null;
43027
+ }
43028
+ return numberCell(column, readF64(body, 6), numFmt);
43029
+ }
43030
+ function decodeRk(rk) {
43031
+ const div100 = (rk & 1) !== 0;
43032
+ const isInt = (rk & 2) !== 0;
43033
+ let n;
43034
+ if (isInt) {
43035
+ n = rk >> 2;
43036
+ } else {
43037
+ const buf = new ArrayBuffer(8);
43038
+ new DataView(buf).setUint32(4, rk & 4294967292, true);
43039
+ n = new DataView(buf).getFloat64(0, true);
43040
+ }
43041
+ return div100 ? n / 100 : n;
43042
+ }
43043
+ function readU16(b, o) {
43044
+ return b[o] | b[o + 1] << 8;
43045
+ }
43046
+ function readU32(b, o) {
43047
+ return (b[o] | b[o + 1] << 8 | b[o + 2] << 16 | b[o + 3] << 24) >>> 0;
43048
+ }
43049
+ function readF64(b, o) {
43050
+ return new DataView(b.buffer, b.byteOffset + o, 8).getFloat64(0, true);
43051
+ }
43052
+ function readUnicodeShort(b, offset, lenBytes) {
43053
+ const cch = lenBytes === 1 ? b[offset] : readU16(b, offset);
43054
+ const grbit = b[offset + lenBytes];
43055
+ const high = (grbit & 1) !== 0;
43056
+ let p = offset + lenBytes + 1;
43057
+ let s = "";
43058
+ for (let i2 = 0; i2 < cch; i2++) {
43059
+ if (high) {
43060
+ s += String.fromCharCode(b[p] | b[p + 1] << 8);
43061
+ p += 2;
43062
+ } else {
43063
+ s += String.fromCharCode(b[p]);
43064
+ p += 1;
43065
+ }
43066
+ }
43067
+ return s;
43068
+ }
43069
+ function utf16le(b) {
43070
+ let s = "";
43071
+ for (let i2 = 0; i2 + 1 < b.length; i2 += 2) s += String.fromCharCode(b[i2] | b[i2 + 1] << 8);
43072
+ return s;
43073
+ }
43074
+ function concat(parts) {
43075
+ let total = 0;
43076
+ for (const p of parts) total += p.length;
43077
+ const out = new Uint8Array(total);
43078
+ let o = 0;
43079
+ for (const p of parts) {
43080
+ out.set(p, o);
43081
+ o += p.length;
43082
+ }
43083
+ return out;
43084
+ }
43085
+ function builtinFormat(id) {
43086
+ const DATES = {
43087
+ 14: "m/d/yyyy",
43088
+ 15: "d-mmm-yy",
43089
+ 16: "d-mmm",
43090
+ 17: "mmm-yy",
43091
+ 18: "h:mm AM/PM",
43092
+ 19: "h:mm:ss AM/PM",
43093
+ 20: "h:mm",
43094
+ 21: "h:mm:ss",
43095
+ 22: "m/d/yyyy h:mm",
43096
+ 45: "mm:ss",
43097
+ 46: "[h]:mm:ss",
43098
+ 47: "mm:ss.0"
43099
+ };
43100
+ return DATES[id] ?? "General";
43101
+ }
43102
+ function parseBiff8(bytes, options) {
43103
+ const streams = readCfbStreams(bytes);
43104
+ if (streams.some((s) => /^EncryptedPackage$/i.test(s.name))) throw new PasswordProtectedError();
43105
+ const wb = streams.find((s) => /^workbook$/i.test(s.name)) ?? streams.find((s) => /^book$/i.test(s.name));
43106
+ if (!wb) throw new Error("Not a valid .xls: no Workbook stream in the OLE2 container");
43107
+ const g = parseGlobals(wb.bytes);
43108
+ const maxRows = options?.maxRowsPerSheet ?? DEFAULT_MAX_ROWS;
43109
+ const sheets = g.boundsheets.length > 0 ? g.boundsheets.map((bs) => parseSheet2(wb.bytes, bs.pos, bs.name, g, maxRows)) : [emptySheet("Sheet1")];
43110
+ return { sheets, activeSheetIndex: 0 };
43111
+ }
43112
+
42647
43113
  // ../xlsx/src/excel_parser.ts
42648
43114
  function parseExcelBuffer(arrayBuffer, options) {
43115
+ const bytes = new Uint8Array(arrayBuffer);
43116
+ if (isOle2(bytes)) return parseBiff8(bytes, options);
42649
43117
  const zip = unzipXlsx(arrayBuffer);
42650
43118
  return parseExcelFromZip(zip, options);
42651
43119
  }
@@ -49222,11 +49690,16 @@ COMMANDS
49222
49690
  lotics app workflow pull Rewrite src/workflows/*.ts from the server
49223
49691
  lotics app workflow check [alias] Typecheck src/workflows bodies locally (one
49224
49692
  isolated program per alias; the app's own tsc)
49693
+ lotics app query set <alias> Push package.json#lotics.queries.<alias> to
49694
+ apps.queries via set_app_query (no deploy;
49695
+ re-synced by the next deploy from the manifest)
49225
49696
  lotics app subdomain <new-subdomain> Rename the app's public <slug>.lotics.app address
49226
49697
  lotics app rename "<new name>" Rename the app's display name (launcher title)
49227
49698
  lotics app dev [path] Run the app locally with HMR (RPC forwarded to prod)
49228
- lotics ui link <component> [--remove] Dev-link @lotics/ui to the monorepo's
49229
- packages/ui/src for live HMR (monorepo only)
49699
+ lotics ui link <component> [--ui-src <path>] [--remove]
49700
+ Dev-link @lotics/ui to packages/ui/src (Vite alias
49701
+ + tsc paths) for live HMR + typecheck. Monorepo apps
49702
+ auto-find it; external apps pass --ui-src / LOTICS_UI_SRC
49230
49703
  lotics xlsx <subcommand> ... Read/write/edit .xlsx files on your local filesystem
49231
49704
  (uses the bundled Lotics xlsx engine; prefer over
49232
49705
  npm xlsx/exceljs for round-trip fidelity)
@@ -49590,15 +50063,16 @@ async function main() {
49590
50063
  if (subcommand === "link") {
49591
50064
  const component = toolArgs;
49592
50065
  if (!component) {
49593
- console.error("Usage: lotics ui link <component> [--remove]");
49594
- console.error("Dev-links @lotics/ui to the monorepo's packages/ui/src for live HMR.");
50066
+ console.error("Usage: lotics ui link <component> [--ui-src <abs path>] [--remove]");
50067
+ console.error("Dev-links @lotics/ui to packages/ui/src (Vite + tsc) for live HMR + typecheck.");
50068
+ console.error("Monorepo apps find packages/ui/src automatically; external apps pass --ui-src / LOTICS_UI_SRC.");
49595
50069
  process.exit(1);
49596
50070
  }
49597
- appUiLink({ component, remove: restArgs.includes("--remove") });
50071
+ appUiLink({ component, uiSrc: flags.uiSrc, remove: restArgs.includes("--remove") });
49598
50072
  return;
49599
50073
  }
49600
50074
  console.error(`Unknown ui subcommand: ${subcommand ?? "(none)"}`);
49601
- console.error("Usage: lotics ui link <component> [--remove]");
50075
+ console.error("Usage: lotics ui link <component> [--ui-src <abs path>] [--remove]");
49602
50076
  process.exit(1);
49603
50077
  }
49604
50078
  if (command === "app" && subcommand === "workflow" && toolArgs === "check") {
@@ -49691,6 +50165,7 @@ async function main() {
49691
50165
  console.error(" lotics app workflow set <alias> Push the edited src/workflows/<alias>.ts body");
49692
50166
  console.error(" lotics app workflow pull Rewrite src/workflows/*.ts from the server");
49693
50167
  console.error(" lotics app workflow check [alias] Typecheck src/workflows bodies locally");
50168
+ console.error(" lotics app query set <alias> Push lotics.queries.<alias> to apps.queries (no deploy)");
49694
50169
  console.error(" lotics app subdomain <new-subdomain> Rename the app's public <slug>.lotics.app address");
49695
50170
  console.error(` lotics app rename "<new name>" Rename the app's display name (launcher title)`);
49696
50171
  console.error(" lotics app dev [path] Run the app locally with HMR + RPC forwarding");
@@ -49896,6 +50371,26 @@ Available workspaces:`);
49896
50371
  }
49897
50372
  workflowUsage();
49898
50373
  }
50374
+ if (subcommand === "query") {
50375
+ const action = toolArgs;
50376
+ if (action === "set") {
50377
+ const alias = restArgs[0];
50378
+ if (!alias) {
50379
+ console.error("Usage: lotics app query set <alias>");
50380
+ console.error(
50381
+ "Pushes package.json#lotics.queries.<alias> to apps.queries via set_app_query (no deploy)."
50382
+ );
50383
+ process.exit(1);
50384
+ }
50385
+ await appQuerySet(client, { alias });
50386
+ return;
50387
+ }
50388
+ console.error("Usage:");
50389
+ console.error(
50390
+ " lotics app query set <alias> Push package.json#lotics.queries.<alias> to apps.queries (no deploy)"
50391
+ );
50392
+ process.exit(1);
50393
+ }
49899
50394
  if (subcommand === "dev") {
49900
50395
  const projectDir = toolArgs;
49901
50396
  let port;