@lotics/cli 0.70.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.
- package/dist/cli.js +27 -5
- package/dist/preview.d.ts +3 -0
- package/dist/preview.js +233 -0
- package/dist/render_page.js +59068 -0
- package/dist/render_page.js.LEGAL.txt +14 -0
- package/dist/src/cli.js +247 -38
- package/package.json +1 -1
|
@@ -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
|
|
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(
|
|
22106
|
-
function
|
|
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 =
|
|
22260
|
-
function
|
|
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(
|
|
22791
|
+
return new external.Promise(function(resolve2, reject2) {
|
|
22792
22792
|
var reader = new FileReader();
|
|
22793
22793
|
reader.onload = function(e) {
|
|
22794
|
-
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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((
|
|
31557
|
-
stoppingResolve =
|
|
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((
|
|
31658
|
+
await new Promise((resolve2, reject2) => {
|
|
31659
31659
|
server.once("error", reject2);
|
|
31660
31660
|
server.listen(wrapperPort, () => {
|
|
31661
31661
|
server.off("error", reject2);
|
|
31662
|
-
|
|
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((
|
|
31671
|
+
await new Promise((resolve2) => server.close(() => resolve2()));
|
|
31672
31672
|
stoppingResolve?.();
|
|
31673
31673
|
}
|
|
31674
|
-
const ready = new Promise((
|
|
31675
|
-
setTimeout(
|
|
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((
|
|
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 ?
|
|
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((
|
|
31702
|
+
return new Promise((resolve2) => {
|
|
31703
31703
|
const srv = net.createServer();
|
|
31704
|
-
srv.once("error", () =>
|
|
31704
|
+
srv.once("error", () => resolve2(false));
|
|
31705
31705
|
srv.listen(port, () => {
|
|
31706
|
-
srv.close(() =>
|
|
31706
|
+
srv.close(() => resolve2(true));
|
|
31707
31707
|
});
|
|
31708
31708
|
});
|
|
31709
31709
|
}
|
|
@@ -32337,7 +32337,7 @@ async function fetchWorkflowGlobals(client, projectDir, app_id, alias) {
|
|
|
32337
32337
|
}
|
|
32338
32338
|
}
|
|
32339
32339
|
function runTar(args, cwd) {
|
|
32340
|
-
return new Promise((
|
|
32340
|
+
return new Promise((resolve2, reject2) => {
|
|
32341
32341
|
const proc = spawn2("tar", args, { cwd, stdio: ["ignore", "ignore", "pipe"] });
|
|
32342
32342
|
let stderr = "";
|
|
32343
32343
|
proc.stderr.on("data", (chunk) => {
|
|
@@ -32345,17 +32345,17 @@ function runTar(args, cwd) {
|
|
|
32345
32345
|
});
|
|
32346
32346
|
proc.on("error", reject2);
|
|
32347
32347
|
proc.on("exit", (code) => {
|
|
32348
|
-
if (code === 0)
|
|
32348
|
+
if (code === 0) resolve2();
|
|
32349
32349
|
else reject2(new Error(`tar ${args.join(" ")} failed with exit ${code}: ${stderr}`));
|
|
32350
32350
|
});
|
|
32351
32351
|
});
|
|
32352
32352
|
}
|
|
32353
32353
|
function runNpm(args, cwd) {
|
|
32354
|
-
return new Promise((
|
|
32354
|
+
return new Promise((resolve2, reject2) => {
|
|
32355
32355
|
const proc = spawn2("npm", args, { cwd, stdio: "inherit", env: ipv4ChildEnv(process.env) });
|
|
32356
32356
|
proc.on("error", reject2);
|
|
32357
32357
|
proc.on("exit", (code) => {
|
|
32358
|
-
if (code === 0)
|
|
32358
|
+
if (code === 0) resolve2();
|
|
32359
32359
|
else reject2(new Error(`npm ${args.join(" ")} exited with code ${code}`));
|
|
32360
32360
|
});
|
|
32361
32361
|
});
|
|
@@ -32851,11 +32851,11 @@ async function appDev(client, args) {
|
|
|
32851
32851
|
console.error(` Ctrl-C to stop.
|
|
32852
32852
|
`);
|
|
32853
32853
|
openBrowser(url);
|
|
32854
|
-
await new Promise((
|
|
32854
|
+
await new Promise((resolve2) => {
|
|
32855
32855
|
const onSig = () => {
|
|
32856
32856
|
process.off("SIGINT", onSig);
|
|
32857
32857
|
process.off("SIGTERM", onSig);
|
|
32858
|
-
|
|
32858
|
+
resolve2();
|
|
32859
32859
|
};
|
|
32860
32860
|
process.on("SIGINT", onSig);
|
|
32861
32861
|
process.on("SIGTERM", onSig);
|
|
@@ -49655,6 +49655,198 @@ async function runDocxCommand(subcommand, toolArgs, restArgs) {
|
|
|
49655
49655
|
}
|
|
49656
49656
|
}
|
|
49657
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
|
+
|
|
49658
49850
|
// src/cli.ts
|
|
49659
49851
|
dns.setDefaultResultOrder("ipv4first");
|
|
49660
49852
|
net2.setDefaultAutoSelectFamilyAttemptTimeout(2e3);
|
|
@@ -49706,10 +49898,6 @@ COMMANDS
|
|
|
49706
49898
|
lotics run <tool> '<json>' Execute a tool
|
|
49707
49899
|
lotics run <tool> @args.json Read JSON args from a file (large payloads)
|
|
49708
49900
|
cat args.json | lotics run <tool> Read JSON args from stdin (large payloads)
|
|
49709
|
-
lotics upload <file|dir...> Upload files (directories expand to their immediate files)
|
|
49710
|
-
lotics download <file_id> Download a file by ID
|
|
49711
|
-
lotics download record <record_id> <field_key>
|
|
49712
|
-
Download all files on a record file field
|
|
49713
49901
|
lotics app create <name> [path] Create a new custom-code app + scaffold locally
|
|
49714
49902
|
lotics app pull <app_id> [path] Bootstrap full local env (source + npm install + types)
|
|
49715
49903
|
lotics app deploy -m <message> Build + upload current dir as a new version
|
|
@@ -49747,6 +49935,12 @@ COMMANDS
|
|
|
49747
49935
|
lotics docx <subcommand> ... Read/write/edit .docx files on your local filesystem
|
|
49748
49936
|
(uses the bundled Lotics OOXML engine; preserves
|
|
49749
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)
|
|
49750
49944
|
|
|
49751
49945
|
FLAGS
|
|
49752
49946
|
--json Full JSON output (default is human-readable text)
|
|
@@ -49824,10 +50018,10 @@ Resolution precedence (highest first):
|
|
|
49824
50018
|
> global active profile. LOTICS_WORKSPACE / --workspace override the workspace.`);
|
|
49825
50019
|
}
|
|
49826
50020
|
function readStdin() {
|
|
49827
|
-
return new Promise((
|
|
50021
|
+
return new Promise((resolve2, reject2) => {
|
|
49828
50022
|
const chunks = [];
|
|
49829
50023
|
process.stdin.on("data", (chunk) => chunks.push(chunk));
|
|
49830
|
-
process.stdin.on("end", () =>
|
|
50024
|
+
process.stdin.on("end", () => resolve2(Buffer.concat(chunks).toString("utf-8").trim()));
|
|
49831
50025
|
process.stdin.on("error", reject2);
|
|
49832
50026
|
});
|
|
49833
50027
|
}
|
|
@@ -49836,10 +50030,10 @@ function prompt(question) {
|
|
|
49836
50030
|
input: process.stdin,
|
|
49837
50031
|
output: process.stderr
|
|
49838
50032
|
});
|
|
49839
|
-
return new Promise((
|
|
50033
|
+
return new Promise((resolve2) => {
|
|
49840
50034
|
rl.question(question, (answer) => {
|
|
49841
50035
|
rl.close();
|
|
49842
|
-
|
|
50036
|
+
resolve2(answer.trim());
|
|
49843
50037
|
});
|
|
49844
50038
|
});
|
|
49845
50039
|
}
|
|
@@ -50006,7 +50200,18 @@ function resolveUploadPaths(rawPaths) {
|
|
|
50006
50200
|
return result;
|
|
50007
50201
|
}
|
|
50008
50202
|
async function main() {
|
|
50009
|
-
const
|
|
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
|
+
}
|
|
50010
50215
|
if (flags.help || !command && !flags.version) {
|
|
50011
50216
|
printHelp();
|
|
50012
50217
|
return;
|
|
@@ -50100,6 +50305,10 @@ async function main() {
|
|
|
50100
50305
|
await runDocxCommand(subcommand, toolArgs, restArgs);
|
|
50101
50306
|
return;
|
|
50102
50307
|
}
|
|
50308
|
+
if (command === "preview") {
|
|
50309
|
+
await runPreviewCommand(subcommand, flags);
|
|
50310
|
+
return;
|
|
50311
|
+
}
|
|
50103
50312
|
if (command === "ui") {
|
|
50104
50313
|
if (subcommand === "link") {
|
|
50105
50314
|
const component = toolArgs;
|