@lotics/cli 0.69.0 → 0.71.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.
@@ -0,0 +1,14 @@
1
+ Bundled license information:
2
+
3
+ jszip/dist/jszip.min.js:
4
+ /*!
5
+
6
+ JSZip v3.10.1 - A JavaScript class for generating and reading zip files
7
+ <http://stuartk.com/jszip>
8
+
9
+ (c) 2009-2016 Stuart Knightley <stuart [at] stuartk.com>
10
+ Dual licenced under the MIT license or GPLv3. See https://raw.github.com/Stuk/jszip/main/LICENSE.markdown.
11
+
12
+ JSZip uses the library pako released under the MIT license :
13
+ https://github.com/nodeca/pako/blob/main/LICENSE
14
+ */
package/dist/src/cli.js CHANGED
@@ -20127,7 +20127,7 @@ var require_BufferList = __commonJS({
20127
20127
  this.head = this.tail = null;
20128
20128
  this.length = 0;
20129
20129
  };
20130
- BufferList.prototype.join = function join(s) {
20130
+ BufferList.prototype.join = function join2(s) {
20131
20131
  if (this.length === 0) return "";
20132
20132
  var p = this.head;
20133
20133
  var ret = "" + p.data;
@@ -22102,8 +22102,8 @@ var require_lib2 = __commonJS({
22102
22102
  return this;
22103
22103
  }
22104
22104
  var p = this.constructor;
22105
- return this.then(resolve2, reject3);
22106
- function resolve2(value) {
22105
+ return this.then(resolve3, reject3);
22106
+ function resolve3(value) {
22107
22107
  function yes() {
22108
22108
  return value;
22109
22109
  }
@@ -22256,8 +22256,8 @@ var require_lib2 = __commonJS({
22256
22256
  }
22257
22257
  return out;
22258
22258
  }
22259
- Promise2.resolve = resolve;
22260
- function resolve(value) {
22259
+ Promise2.resolve = resolve2;
22260
+ function resolve2(value) {
22261
22261
  if (value instanceof this) {
22262
22262
  return value;
22263
22263
  }
@@ -22788,10 +22788,10 @@ var require_utils4 = __commonJS({
22788
22788
  var promise = external.Promise.resolve(inputData).then(function(data) {
22789
22789
  var isBlob = support.blob && (data instanceof Blob || ["[object File]", "[object Blob]"].indexOf(Object.prototype.toString.call(data)) !== -1);
22790
22790
  if (isBlob && typeof FileReader !== "undefined") {
22791
- return new external.Promise(function(resolve, reject2) {
22791
+ return new external.Promise(function(resolve2, reject2) {
22792
22792
  var reader = new FileReader();
22793
22793
  reader.onload = function(e) {
22794
- resolve(e.target.result);
22794
+ resolve2(e.target.result);
22795
22795
  };
22796
22796
  reader.onerror = function(e) {
22797
22797
  reject2(e.target.error);
@@ -23346,7 +23346,7 @@ var require_StreamHelper = __commonJS({
23346
23346
  }
23347
23347
  }
23348
23348
  function accumulate(helper, updateCallback) {
23349
- return new external.Promise(function(resolve, reject2) {
23349
+ return new external.Promise(function(resolve2, reject2) {
23350
23350
  var dataArray = [];
23351
23351
  var chunkType = helper._internalType, resultType = helper._outputType, mimeType = helper._mimeType;
23352
23352
  helper.on("data", function(data, meta) {
@@ -23360,7 +23360,7 @@ var require_StreamHelper = __commonJS({
23360
23360
  }).on("end", function() {
23361
23361
  try {
23362
23362
  var result = transformZipOutput(resultType, concat2(chunkType, dataArray), mimeType);
23363
- resolve(result);
23363
+ resolve2(result);
23364
23364
  } catch (e) {
23365
23365
  reject2(e);
23366
23366
  }
@@ -29473,7 +29473,7 @@ var require_load = __commonJS({
29473
29473
  var Crc32Probe = require_Crc32Probe();
29474
29474
  var nodejsUtils = require_nodejsUtils();
29475
29475
  function checkEntryCRC32(zipEntry) {
29476
- return new external.Promise(function(resolve, reject2) {
29476
+ return new external.Promise(function(resolve2, reject2) {
29477
29477
  var worker = zipEntry.decompressed.getContentWorker().pipe(new Crc32Probe());
29478
29478
  worker.on("error", function(e) {
29479
29479
  reject2(e);
@@ -29481,7 +29481,7 @@ var require_load = __commonJS({
29481
29481
  if (worker.streamInfo.crc32 !== zipEntry.decompressed.crc32) {
29482
29482
  reject2(new Error("Corrupted zip : CRC32 mismatch"));
29483
29483
  } else {
29484
- resolve();
29484
+ resolve2();
29485
29485
  }
29486
29486
  }).resume();
29487
29487
  });
@@ -31553,8 +31553,8 @@ async function startDevServer(args) {
31553
31553
  );
31554
31554
  let stopped = false;
31555
31555
  let stoppingResolve = null;
31556
- const stoppingPromise = new Promise((resolve) => {
31557
- stoppingResolve = resolve;
31556
+ const stoppingPromise = new Promise((resolve2) => {
31557
+ stoppingResolve = resolve2;
31558
31558
  });
31559
31559
  viteChild.on("exit", (code, signal) => {
31560
31560
  if (!stopped) {
@@ -31655,11 +31655,11 @@ async function startDevServer(args) {
31655
31655
  res.writeHead(404, { "Content-Type": "text/plain" });
31656
31656
  res.end("Not Found");
31657
31657
  });
31658
- await new Promise((resolve, reject2) => {
31658
+ await new Promise((resolve2, reject2) => {
31659
31659
  server.once("error", reject2);
31660
31660
  server.listen(wrapperPort, () => {
31661
31661
  server.off("error", reject2);
31662
- resolve();
31662
+ resolve2();
31663
31663
  });
31664
31664
  });
31665
31665
  async function stopAll() {
@@ -31668,11 +31668,11 @@ async function startDevServer(args) {
31668
31668
  if (!viteChild.killed) {
31669
31669
  viteChild.kill("SIGINT");
31670
31670
  }
31671
- await new Promise((resolve) => server.close(() => resolve()));
31671
+ await new Promise((resolve2) => server.close(() => resolve2()));
31672
31672
  stoppingResolve?.();
31673
31673
  }
31674
- const ready = new Promise((resolve) => {
31675
- setTimeout(resolve, 800);
31674
+ const ready = new Promise((resolve2) => {
31675
+ setTimeout(resolve2, 800);
31676
31676
  });
31677
31677
  return {
31678
31678
  port: wrapperPort,
@@ -31688,22 +31688,22 @@ async function pickPort(preferred, ...avoid) {
31688
31688
  if (!avoid.includes(preferred) && await isPortFree(preferred)) {
31689
31689
  return preferred;
31690
31690
  }
31691
- return new Promise((resolve, reject2) => {
31691
+ return new Promise((resolve2, reject2) => {
31692
31692
  const srv = net.createServer();
31693
31693
  srv.once("error", reject2);
31694
31694
  srv.listen(0, () => {
31695
31695
  const addr = srv.address();
31696
31696
  const port = typeof addr === "object" && addr ? addr.port : 0;
31697
- srv.close(() => port ? resolve(port) : reject2(new Error("Failed to pick port")));
31697
+ srv.close(() => port ? resolve2(port) : reject2(new Error("Failed to pick port")));
31698
31698
  });
31699
31699
  });
31700
31700
  }
31701
31701
  function isPortFree(port) {
31702
- return new Promise((resolve) => {
31702
+ return new Promise((resolve2) => {
31703
31703
  const srv = net.createServer();
31704
- srv.once("error", () => resolve(false));
31704
+ srv.once("error", () => resolve2(false));
31705
31705
  srv.listen(port, () => {
31706
- srv.close(() => resolve(true));
31706
+ srv.close(() => resolve2(true));
31707
31707
  });
31708
31708
  });
31709
31709
  }
@@ -31759,7 +31759,7 @@ declare module "@lotics/app-sdk" {
31759
31759
  const inputLines = [];
31760
31760
  const resultLines = [];
31761
31761
  for (const [alias, declaration] of entries) {
31762
- const valueType = declaration.inputs ? inputsToType(declaration.inputs) : "Record<string, unknown>";
31762
+ const valueType = declaration.inputs ? inputsToType(declaration.inputs, { nullableOptional: true }) : "Record<string, unknown>";
31763
31763
  const aliasKey = isValidIdentifier(alias) ? alias : JSON.stringify(alias);
31764
31764
  inputLines.push(` ${aliasKey}: ${valueType};`);
31765
31765
  if (declaration.outputs) {
@@ -31778,15 +31778,18 @@ ${inputLines.join("\n")}
31778
31778
  }
31779
31779
  `;
31780
31780
  }
31781
- function inputsToType(inputs) {
31781
+ function inputsToType(inputs, opts) {
31782
+ const nullableOptional = opts?.nullableOptional === true;
31782
31783
  const fields = [];
31783
31784
  for (const [key, decl] of Object.entries(inputs)) {
31784
31785
  if (decl === null || typeof decl !== "object") continue;
31785
31786
  const d = decl;
31786
31787
  const tsType = inputDeclToTsType(d);
31787
- const optional = d.required === false ? "?" : "";
31788
+ const isOptional = d.required === false;
31789
+ const fieldType = isOptional && nullableOptional ? `${tsType} | null` : tsType;
31790
+ const optional = isOptional ? "?" : "";
31788
31791
  const fieldKey = isValidIdentifier(key) ? key : JSON.stringify(key);
31789
- fields.push(` ${fieldKey}${optional}: ${tsType};`);
31792
+ fields.push(` ${fieldKey}${optional}: ${fieldType};`);
31790
31793
  }
31791
31794
  if (fields.length === 0) return "Record<string, never>";
31792
31795
  return `{
@@ -32334,7 +32337,7 @@ async function fetchWorkflowGlobals(client, projectDir, app_id, alias) {
32334
32337
  }
32335
32338
  }
32336
32339
  function runTar(args, cwd) {
32337
- return new Promise((resolve, reject2) => {
32340
+ return new Promise((resolve2, reject2) => {
32338
32341
  const proc = spawn2("tar", args, { cwd, stdio: ["ignore", "ignore", "pipe"] });
32339
32342
  let stderr = "";
32340
32343
  proc.stderr.on("data", (chunk) => {
@@ -32342,17 +32345,17 @@ function runTar(args, cwd) {
32342
32345
  });
32343
32346
  proc.on("error", reject2);
32344
32347
  proc.on("exit", (code) => {
32345
- if (code === 0) resolve();
32348
+ if (code === 0) resolve2();
32346
32349
  else reject2(new Error(`tar ${args.join(" ")} failed with exit ${code}: ${stderr}`));
32347
32350
  });
32348
32351
  });
32349
32352
  }
32350
32353
  function runNpm(args, cwd) {
32351
- return new Promise((resolve, reject2) => {
32354
+ return new Promise((resolve2, reject2) => {
32352
32355
  const proc = spawn2("npm", args, { cwd, stdio: "inherit", env: ipv4ChildEnv(process.env) });
32353
32356
  proc.on("error", reject2);
32354
32357
  proc.on("exit", (code) => {
32355
- if (code === 0) resolve();
32358
+ if (code === 0) resolve2();
32356
32359
  else reject2(new Error(`npm ${args.join(" ")} exited with code ${code}`));
32357
32360
  });
32358
32361
  });
@@ -32848,11 +32851,11 @@ async function appDev(client, args) {
32848
32851
  console.error(` Ctrl-C to stop.
32849
32852
  `);
32850
32853
  openBrowser(url);
32851
- await new Promise((resolve) => {
32854
+ await new Promise((resolve2) => {
32852
32855
  const onSig = () => {
32853
32856
  process.off("SIGINT", onSig);
32854
32857
  process.off("SIGTERM", onSig);
32855
- resolve();
32858
+ resolve2();
32856
32859
  };
32857
32860
  process.on("SIGINT", onSig);
32858
32861
  process.on("SIGTERM", onSig);
@@ -49652,6 +49655,198 @@ async function runDocxCommand(subcommand, toolArgs, restArgs) {
49652
49655
  }
49653
49656
  }
49654
49657
 
49658
+ // src/preview.ts
49659
+ import { spawn as spawn3 } from "node:child_process";
49660
+ import { createServer } from "node:http";
49661
+ import { readFileSync as readFileSync2, writeFileSync, existsSync, mkdtempSync, rmSync, readdirSync } from "node:fs";
49662
+ import { tmpdir as tmpdir2 } from "node:os";
49663
+ import { join, dirname, resolve, extname, basename } from "node:path";
49664
+ import { fileURLToPath as fileURLToPath2 } from "node:url";
49665
+ import { setTimeout as sleep } from "node:timers/promises";
49666
+ var HERE = dirname(fileURLToPath2(import.meta.url));
49667
+ function fail2(msg) {
49668
+ console.error(msg);
49669
+ process.exit(1);
49670
+ }
49671
+ function findChrome() {
49672
+ const env = process.env.LOTICS_CHROME || process.env.CHROME_PATH;
49673
+ if (env && existsSync(env)) return env;
49674
+ const home = process.env.HOME || "";
49675
+ const pwDir = process.platform === "darwin" ? `${home}/Library/Caches/ms-playwright` : `${home}/.cache/ms-playwright`;
49676
+ if (existsSync(pwDir)) {
49677
+ const rel = process.platform === "darwin" ? ["chrome-mac/Chromium.app/Contents/MacOS/Chromium"] : ["chrome-linux/chrome", "chrome-linux/headless_shell"];
49678
+ const revs = readdirSync(pwDir).filter((n) => n.startsWith("chromium-") || n.startsWith("chromium_headless_shell-")).sort().reverse();
49679
+ for (const rev2 of revs) {
49680
+ for (const r of rel) {
49681
+ const bin = join(pwDir, rev2, r);
49682
+ if (existsSync(bin)) return bin;
49683
+ }
49684
+ }
49685
+ }
49686
+ const systemPaths = [
49687
+ "/usr/bin/google-chrome",
49688
+ "/usr/bin/google-chrome-stable",
49689
+ "/usr/bin/chromium",
49690
+ "/usr/bin/chromium-browser",
49691
+ "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
49692
+ "/Applications/Chromium.app/Contents/MacOS/Chromium"
49693
+ ];
49694
+ return systemPaths.find((p) => existsSync(p)) ?? null;
49695
+ }
49696
+ async function cdpConnect(wsUrl) {
49697
+ const ws = new WebSocket(wsUrl);
49698
+ await new Promise((res, rej) => {
49699
+ ws.onopen = () => res();
49700
+ ws.onerror = () => rej(new Error("CDP websocket failed to open"));
49701
+ });
49702
+ let id = 0;
49703
+ const pending = /* @__PURE__ */ new Map();
49704
+ ws.onclose = () => {
49705
+ for (const done of pending.values()) done(Promise.reject(new Error("CDP connection closed (Chrome exited?)")));
49706
+ pending.clear();
49707
+ };
49708
+ ws.onmessage = (e) => {
49709
+ const m = JSON.parse(String(e.data));
49710
+ if (m.id != null && pending.has(m.id)) {
49711
+ const done = pending.get(m.id);
49712
+ pending.delete(m.id);
49713
+ done(m.error ? Promise.reject(new Error(m.error.message)) : m.result);
49714
+ }
49715
+ };
49716
+ const send = (method, params = {}) => new Promise((res) => {
49717
+ const i2 = ++id;
49718
+ pending.set(i2, (r) => res(r));
49719
+ ws.send(JSON.stringify({ id: i2, method, params }));
49720
+ });
49721
+ return { send, close: () => ws.close() };
49722
+ }
49723
+ async function runPreviewCommand(filePath, flags) {
49724
+ if (!filePath) fail2("Usage: lotics preview <file.docx|.xlsx> [--out <file.png>]");
49725
+ const abs = resolve(filePath);
49726
+ if (!existsSync(abs)) fail2(`File not found: ${abs}`);
49727
+ const ext = extname(abs).toLowerCase();
49728
+ const type = ext === ".docx" ? "docx" : ext === ".xlsx" || ext === ".xls" || ext === ".csv" ? "xlsx" : null;
49729
+ if (!type) fail2(`Unsupported file type "${ext}" \u2014 preview supports .docx and .xlsx/.csv. (PDFs open directly \u2014 no preview needed.)`);
49730
+ if (typeof WebSocket === "undefined") {
49731
+ fail2("lotics preview needs Node 22+ (it drives Chrome over CDP via the built-in WebSocket). Upgrade Node and retry.");
49732
+ }
49733
+ const bundlePath = join(HERE, "..", "render_page.js");
49734
+ if (!existsSync(bundlePath)) fail2(`Render bundle missing at ${bundlePath} \u2014 reinstall @lotics/cli (build step failed).`);
49735
+ const chrome = findChrome();
49736
+ if (!chrome) {
49737
+ fail2(
49738
+ "No Chrome/Chromium found. Set CHROME_PATH to a Chrome binary, or install one:\n npx playwright install chromium (then it's auto-detected)\n or install Google Chrome / Chromium via your package manager."
49739
+ );
49740
+ }
49741
+ const b64 = readFileSync2(abs).toString("base64");
49742
+ const bundle = readFileSync2(bundlePath, "utf8");
49743
+ const html = `<!doctype html><html><head><meta charset="utf-8"><style>body{margin:0;background:#fff;font-family:sans-serif}#root{padding:20px;max-width:1240px;margin:0 auto}</style></head><body><div id="root"></div><script>window.__LOTICS_RENDER=${JSON.stringify({ type, b64 })}</script><script src="/render_page.js"></script></body></html>`;
49744
+ const server = createServer((req, res) => {
49745
+ if (req.url === "/render_page.js") {
49746
+ res.writeHead(200, { "content-type": "application/javascript" });
49747
+ res.end(bundle);
49748
+ } else {
49749
+ res.writeHead(200, { "content-type": "text/html" });
49750
+ res.end(html);
49751
+ }
49752
+ });
49753
+ await new Promise((r) => server.listen(0, "127.0.0.1", () => r()));
49754
+ const httpPort = server.address().port;
49755
+ const udd = mkdtempSync(join(tmpdir2(), "lotics-render-"));
49756
+ const child = spawn3(chrome, [
49757
+ "--headless=new",
49758
+ "--disable-gpu",
49759
+ "--no-sandbox",
49760
+ "--hide-scrollbars",
49761
+ // Large multi-sheet renders exhaust the (often tiny) /dev/shm in containers/WSL2 and
49762
+ // crash the tab; back shared memory with /tmp instead.
49763
+ "--disable-dev-shm-usage",
49764
+ "--force-device-scale-factor=2",
49765
+ "--remote-debugging-port=0",
49766
+ `--user-data-dir=${udd}`,
49767
+ "about:blank"
49768
+ ], { stdio: "ignore" });
49769
+ const cleanup = () => {
49770
+ try {
49771
+ child.kill();
49772
+ } catch {
49773
+ }
49774
+ try {
49775
+ server.close();
49776
+ } catch {
49777
+ }
49778
+ try {
49779
+ rmSync(udd, { recursive: true, force: true });
49780
+ } catch {
49781
+ }
49782
+ };
49783
+ try {
49784
+ let cdpPort = 0;
49785
+ const portFile = join(udd, "DevToolsActivePort");
49786
+ for (let i2 = 0; i2 < 100 && !cdpPort; i2++) {
49787
+ if (existsSync(portFile)) {
49788
+ const p = parseInt(readFileSync2(portFile, "utf8").split("\n")[0], 10);
49789
+ if (p) cdpPort = p;
49790
+ }
49791
+ if (!cdpPort) await sleep(100);
49792
+ }
49793
+ if (!cdpPort) throw new Error("Chrome did not expose a debugging port (launch failed?).");
49794
+ let target;
49795
+ for (let i2 = 0; i2 < 60 && !target?.webSocketDebuggerUrl; i2++) {
49796
+ try {
49797
+ const list = await (await fetch(`http://127.0.0.1:${cdpPort}/json/list`)).json();
49798
+ target = list.find((t) => t.type === "page");
49799
+ } catch {
49800
+ }
49801
+ if (!target?.webSocketDebuggerUrl) await sleep(100);
49802
+ }
49803
+ if (!target?.webSocketDebuggerUrl) throw new Error("No Chrome page target available.");
49804
+ const cdp = await cdpConnect(target.webSocketDebuggerUrl);
49805
+ await cdp.send("Page.enable");
49806
+ await cdp.send("Runtime.enable");
49807
+ await cdp.send("Page.navigate", { url: `http://127.0.0.1:${httpPort}/` });
49808
+ let err2;
49809
+ let done = false;
49810
+ const warnings = [];
49811
+ for (let i2 = 0; i2 < 200; i2++) {
49812
+ const r = await cdp.send("Runtime.evaluate", {
49813
+ expression: "({done: !!window.__loticsDone, err: window.__loticsError || '', warnings: window.__loticsWarnings || []})",
49814
+ returnByValue: true
49815
+ });
49816
+ const v = r.result?.value;
49817
+ if (v?.done) {
49818
+ done = true;
49819
+ err2 = v.err || void 0;
49820
+ if (v.warnings?.length) warnings.push(...v.warnings);
49821
+ break;
49822
+ }
49823
+ await sleep(75);
49824
+ }
49825
+ if (!done) throw new Error("Render timed out (page never signaled completion).");
49826
+ if (err2) throw new Error(`Render engine error: ${err2}`);
49827
+ const metrics = await cdp.send("Page.getLayoutMetrics");
49828
+ const size = metrics.cssContentSize ?? metrics.contentSize ?? { width: 1240, height: 1600 };
49829
+ const MAX_CAPTURE = 15e3;
49830
+ const w = Math.ceil(size.width);
49831
+ const h = Math.ceil(size.height);
49832
+ if (w > MAX_CAPTURE || h > MAX_CAPTURE) {
49833
+ warnings.push(`content ${w}\xD7${h}px clipped to ${Math.min(w, MAX_CAPTURE)}\xD7${Math.min(h, MAX_CAPTURE)}px (exceeds the ${MAX_CAPTURE}px capture limit)`);
49834
+ }
49835
+ const shot = await cdp.send("Page.captureScreenshot", {
49836
+ format: "png",
49837
+ captureBeyondViewport: true,
49838
+ clip: { x: 0, y: 0, width: Math.min(w, MAX_CAPTURE), height: Math.min(h, MAX_CAPTURE), scale: 1 }
49839
+ });
49840
+ cdp.close();
49841
+ const outPath = flags.output ? resolve(flags.output) : join(dirname(abs), basename(abs, ext) + ".png");
49842
+ writeFileSync(outPath, Buffer.from(shot.data, "base64"));
49843
+ console.log(`Rendered ${basename(abs)} \u2192 ${outPath} (${Math.min(w, MAX_CAPTURE)}\xD7${Math.min(h, MAX_CAPTURE)}, via ${basename(chrome)})`);
49844
+ for (const warn of warnings) console.error(` \u26A0 ${warn}`);
49845
+ } finally {
49846
+ cleanup();
49847
+ }
49848
+ }
49849
+
49655
49850
  // src/cli.ts
49656
49851
  dns.setDefaultResultOrder("ipv4first");
49657
49852
  net2.setDefaultAutoSelectFamilyAttemptTimeout(2e3);
@@ -49703,10 +49898,6 @@ COMMANDS
49703
49898
  lotics run <tool> '<json>' Execute a tool
49704
49899
  lotics run <tool> @args.json Read JSON args from a file (large payloads)
49705
49900
  cat args.json | lotics run <tool> Read JSON args from stdin (large payloads)
49706
- lotics upload <file|dir...> Upload files (directories expand to their immediate files)
49707
- lotics download <file_id> Download a file by ID
49708
- lotics download record <record_id> <field_key>
49709
- Download all files on a record file field
49710
49901
  lotics app create <name> [path] Create a new custom-code app + scaffold locally
49711
49902
  lotics app pull <app_id> [path] Bootstrap full local env (source + npm install + types)
49712
49903
  lotics app deploy -m <message> Build + upload current dir as a new version
@@ -49744,6 +49935,12 @@ COMMANDS
49744
49935
  lotics docx <subcommand> ... Read/write/edit .docx files on your local filesystem
49745
49936
  (uses the bundled Lotics OOXML engine; preserves
49746
49937
  tables, images, and unknown markup verbatim)
49938
+ lotics file upload <file|dir...> Upload files (alias: lotics upload)
49939
+ lotics file download <file_id> Download a file by ID (alias: lotics download)
49940
+ lotics file download record <record_id> <field_key>
49941
+ Download all files on a record file field
49942
+ lotics file preview <file> [-o png] Render a .docx/.xlsx to a PNG (frontend engines;
49943
+ needs a Chrome/Chromium on the machine)
49747
49944
 
49748
49945
  FLAGS
49749
49946
  --json Full JSON output (default is human-readable text)
@@ -49821,10 +50018,10 @@ Resolution precedence (highest first):
49821
50018
  > global active profile. LOTICS_WORKSPACE / --workspace override the workspace.`);
49822
50019
  }
49823
50020
  function readStdin() {
49824
- return new Promise((resolve, reject2) => {
50021
+ return new Promise((resolve2, reject2) => {
49825
50022
  const chunks = [];
49826
50023
  process.stdin.on("data", (chunk) => chunks.push(chunk));
49827
- process.stdin.on("end", () => resolve(Buffer.concat(chunks).toString("utf-8").trim()));
50024
+ process.stdin.on("end", () => resolve2(Buffer.concat(chunks).toString("utf-8").trim()));
49828
50025
  process.stdin.on("error", reject2);
49829
50026
  });
49830
50027
  }
@@ -49833,10 +50030,10 @@ function prompt(question) {
49833
50030
  input: process.stdin,
49834
50031
  output: process.stderr
49835
50032
  });
49836
- return new Promise((resolve) => {
50033
+ return new Promise((resolve2) => {
49837
50034
  rl.question(question, (answer) => {
49838
50035
  rl.close();
49839
- resolve(answer.trim());
50036
+ resolve2(answer.trim());
49840
50037
  });
49841
50038
  });
49842
50039
  }
@@ -50003,7 +50200,18 @@ function resolveUploadPaths(rawPaths) {
50003
50200
  return result;
50004
50201
  }
50005
50202
  async function main() {
50006
- const { command, subcommand, toolArgs, restArgs, flags } = parseArgs(process.argv.slice(2));
50203
+ const parsed = parseArgs(process.argv.slice(2));
50204
+ const { restArgs, flags } = parsed;
50205
+ let { command, subcommand, toolArgs } = parsed;
50206
+ if (command === "file") {
50207
+ if (!subcommand) {
50208
+ printHelp();
50209
+ return;
50210
+ }
50211
+ command = subcommand;
50212
+ subcommand = toolArgs;
50213
+ toolArgs = restArgs.shift();
50214
+ }
50007
50215
  if (flags.help || !command && !flags.version) {
50008
50216
  printHelp();
50009
50217
  return;
@@ -50097,6 +50305,10 @@ async function main() {
50097
50305
  await runDocxCommand(subcommand, toolArgs, restArgs);
50098
50306
  return;
50099
50307
  }
50308
+ if (command === "preview") {
50309
+ await runPreviewCommand(subcommand, flags);
50310
+ return;
50311
+ }
50100
50312
  if (command === "ui") {
50101
50313
  if (subcommand === "link") {
50102
50314
  const component = toolArgs;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lotics/cli",
3
- "version": "0.69.0",
3
+ "version": "0.71.0",
4
4
  "description": "Lotics SDK and CLI for AI agents",
5
5
  "type": "module",
6
6
  "bin": {