@vm0/cli 9.150.11 → 9.151.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/{chunk-2ZSJAVJT.js → chunk-VUZYX6DE.js} +1144 -592
- package/{chunk-2ZSJAVJT.js.map → chunk-VUZYX6DE.js.map} +1 -1
- package/index.js +9 -9
- package/index.js.map +1 -1
- package/package.json +1 -1
- package/zero.js +444 -50
- package/zero.js.map +1 -1
package/package.json
CHANGED
package/zero.js
CHANGED
|
@@ -10,11 +10,13 @@ import {
|
|
|
10
10
|
InvalidArgumentError,
|
|
11
11
|
MODEL_PROVIDER_TYPES,
|
|
12
12
|
Option,
|
|
13
|
+
completeHostedSite,
|
|
13
14
|
completePhoneFileUpload,
|
|
14
15
|
completeSlackFileUpload,
|
|
15
16
|
completeTelegramFileUpload,
|
|
16
17
|
configureGlobalProxyFromEnv,
|
|
17
18
|
connectorTypeSchema,
|
|
19
|
+
createLocalBrowserReadCommand,
|
|
18
20
|
createSkill,
|
|
19
21
|
createZeroAgent,
|
|
20
22
|
createZeroRun,
|
|
@@ -51,6 +53,7 @@ import {
|
|
|
51
53
|
getConnectorFirewall,
|
|
52
54
|
getConnectorTypeForSecretName,
|
|
53
55
|
getDefaultAuthMethod,
|
|
56
|
+
getLocalBrowserReadCommand,
|
|
54
57
|
getScopeDiff,
|
|
55
58
|
getSecretsForAuthMethod,
|
|
56
59
|
getSelectableProviderTypes,
|
|
@@ -91,6 +94,7 @@ import {
|
|
|
91
94
|
paginate,
|
|
92
95
|
parseEvent,
|
|
93
96
|
parseTime,
|
|
97
|
+
prepareHostedSite,
|
|
94
98
|
promptConfirm,
|
|
95
99
|
promptPassword,
|
|
96
100
|
promptSelect,
|
|
@@ -130,7 +134,7 @@ import {
|
|
|
130
134
|
withErrorHandler,
|
|
131
135
|
zeroAgentCustomSkillNameSchema,
|
|
132
136
|
zeroRemoteAgentCommand
|
|
133
|
-
} from "./chunk-
|
|
137
|
+
} from "./chunk-VUZYX6DE.js";
|
|
134
138
|
import {
|
|
135
139
|
__toESM,
|
|
136
140
|
init_esm_shims
|
|
@@ -1885,8 +1889,8 @@ function formatDateTime(dateStr) {
|
|
|
1885
1889
|
const hours = String(date.getHours()).padStart(2, "0");
|
|
1886
1890
|
const minutes = String(date.getMinutes()).padStart(2, "0");
|
|
1887
1891
|
const formatted = `${year}-${month}-${day} ${hours}:${minutes}`;
|
|
1888
|
-
const
|
|
1889
|
-
return `${formatted} (${
|
|
1892
|
+
const relative2 = formatRelativeTime(dateStr);
|
|
1893
|
+
return `${formatted} (${relative2})`;
|
|
1890
1894
|
}
|
|
1891
1895
|
function generateCronExpression(frequency, time, day) {
|
|
1892
1896
|
const [hourStr, minuteStr] = time.split(":");
|
|
@@ -3281,8 +3285,8 @@ function renderTerminalRunResult(runId, runResponse) {
|
|
|
3281
3285
|
return { succeeded: false, runId };
|
|
3282
3286
|
}
|
|
3283
3287
|
function sleep(ms) {
|
|
3284
|
-
return new Promise((
|
|
3285
|
-
return setTimeout(
|
|
3288
|
+
return new Promise((resolve2) => {
|
|
3289
|
+
return setTimeout(resolve2, ms);
|
|
3286
3290
|
});
|
|
3287
3291
|
}
|
|
3288
3292
|
async function pollZeroEvents(runId, options) {
|
|
@@ -4559,8 +4563,8 @@ Notes:
|
|
|
4559
4563
|
async (options) => {
|
|
4560
4564
|
let fileSize;
|
|
4561
4565
|
try {
|
|
4562
|
-
const
|
|
4563
|
-
fileSize =
|
|
4566
|
+
const stat2 = statSync(options.file);
|
|
4567
|
+
fileSize = stat2.size;
|
|
4564
4568
|
} catch {
|
|
4565
4569
|
throw new Error(`File not found: ${options.file}`);
|
|
4566
4570
|
}
|
|
@@ -4894,11 +4898,11 @@ Notes:
|
|
|
4894
4898
|
async (options) => {
|
|
4895
4899
|
let fileSize;
|
|
4896
4900
|
try {
|
|
4897
|
-
const
|
|
4898
|
-
if (!
|
|
4901
|
+
const stat2 = statSync2(options.file);
|
|
4902
|
+
if (!stat2.isFile()) {
|
|
4899
4903
|
throw new Error(`Not a regular file: ${options.file}`);
|
|
4900
4904
|
}
|
|
4901
|
-
fileSize =
|
|
4905
|
+
fileSize = stat2.size;
|
|
4902
4906
|
} catch (error) {
|
|
4903
4907
|
if (error instanceof Error && error.message.startsWith("Not ")) {
|
|
4904
4908
|
throw error;
|
|
@@ -5072,11 +5076,11 @@ Output:
|
|
|
5072
5076
|
async (options) => {
|
|
5073
5077
|
let fileSize;
|
|
5074
5078
|
try {
|
|
5075
|
-
const
|
|
5076
|
-
if (!
|
|
5079
|
+
const stat2 = statSync3(options.file);
|
|
5080
|
+
if (!stat2.isFile()) {
|
|
5077
5081
|
throw new Error(`Not a regular file: ${options.file}`);
|
|
5078
5082
|
}
|
|
5079
|
-
fileSize =
|
|
5083
|
+
fileSize = stat2.size;
|
|
5080
5084
|
} catch (error) {
|
|
5081
5085
|
if (error instanceof Error && error.message.startsWith("Not ")) {
|
|
5082
5086
|
throw error;
|
|
@@ -5378,13 +5382,13 @@ import { join as join4 } from "path";
|
|
|
5378
5382
|
var IGNORED_NAMES = /* @__PURE__ */ new Set(["node_modules", ".git", ".DS_Store"]);
|
|
5379
5383
|
function readSkillDirectory(dirPath) {
|
|
5380
5384
|
const files = [];
|
|
5381
|
-
function
|
|
5385
|
+
function walk2(dir, prefix) {
|
|
5382
5386
|
const entries = readdirSync(dir, { withFileTypes: true });
|
|
5383
5387
|
for (const entry of entries) {
|
|
5384
5388
|
if (entry.name.startsWith(".") || IGNORED_NAMES.has(entry.name)) continue;
|
|
5385
5389
|
const relPath = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
5386
5390
|
if (entry.isDirectory()) {
|
|
5387
|
-
|
|
5391
|
+
walk2(join4(dir, entry.name), relPath);
|
|
5388
5392
|
} else {
|
|
5389
5393
|
files.push({
|
|
5390
5394
|
path: relPath,
|
|
@@ -5393,7 +5397,7 @@ function readSkillDirectory(dirPath) {
|
|
|
5393
5397
|
}
|
|
5394
5398
|
}
|
|
5395
5399
|
}
|
|
5396
|
-
|
|
5400
|
+
walk2(dirPath, "");
|
|
5397
5401
|
if (!files.some((f) => {
|
|
5398
5402
|
return f.path === "SKILL.md";
|
|
5399
5403
|
})) {
|
|
@@ -6459,12 +6463,12 @@ async function readClipboard() {
|
|
|
6459
6463
|
return stdout;
|
|
6460
6464
|
}
|
|
6461
6465
|
async function writeClipboard(text) {
|
|
6462
|
-
return new Promise((
|
|
6466
|
+
return new Promise((resolve2, reject) => {
|
|
6463
6467
|
const proc = spawn("pbcopy", { stdio: ["pipe", "ignore", "ignore"] });
|
|
6464
6468
|
proc.on("error", reject);
|
|
6465
6469
|
proc.on("close", (code) => {
|
|
6466
6470
|
if (code === 0) {
|
|
6467
|
-
|
|
6471
|
+
resolve2();
|
|
6468
6472
|
} else {
|
|
6469
6473
|
reject(new Error(`pbcopy exited with code ${code}`));
|
|
6470
6474
|
}
|
|
@@ -6486,13 +6490,13 @@ async function openApplication(nameOrBundleId) {
|
|
|
6486
6490
|
|
|
6487
6491
|
// src/lib/computer-use/desktop-server.ts
|
|
6488
6492
|
function readBody(req) {
|
|
6489
|
-
return new Promise((
|
|
6493
|
+
return new Promise((resolve2, reject) => {
|
|
6490
6494
|
const chunks = [];
|
|
6491
6495
|
req.on("data", (chunk) => {
|
|
6492
6496
|
chunks.push(chunk);
|
|
6493
6497
|
});
|
|
6494
6498
|
req.on("end", () => {
|
|
6495
|
-
|
|
6499
|
+
resolve2(Buffer.concat(chunks).toString());
|
|
6496
6500
|
});
|
|
6497
6501
|
req.on("error", reject);
|
|
6498
6502
|
});
|
|
@@ -6532,7 +6536,7 @@ async function handleZoom(searchParams, res) {
|
|
|
6532
6536
|
res.end(JSON.stringify(result));
|
|
6533
6537
|
}
|
|
6534
6538
|
function parseJsonBody(req) {
|
|
6535
|
-
return new Promise((
|
|
6539
|
+
return new Promise((resolve2, reject) => {
|
|
6536
6540
|
const chunks = [];
|
|
6537
6541
|
let size = 0;
|
|
6538
6542
|
req.on("data", (chunk) => {
|
|
@@ -6546,7 +6550,7 @@ function parseJsonBody(req) {
|
|
|
6546
6550
|
});
|
|
6547
6551
|
req.on("end", () => {
|
|
6548
6552
|
try {
|
|
6549
|
-
|
|
6553
|
+
resolve2(JSON.parse(Buffer.concat(chunks).toString()));
|
|
6550
6554
|
} catch {
|
|
6551
6555
|
reject(new Error("Invalid JSON body"));
|
|
6552
6556
|
}
|
|
@@ -6688,12 +6692,12 @@ async function handleOpenApplication(req, res) {
|
|
|
6688
6692
|
res.end(JSON.stringify({ ok: true }));
|
|
6689
6693
|
}
|
|
6690
6694
|
async function getRandomPort() {
|
|
6691
|
-
return new Promise((
|
|
6695
|
+
return new Promise((resolve2, reject) => {
|
|
6692
6696
|
const server = createNetServer();
|
|
6693
6697
|
server.listen(0, "127.0.0.1", () => {
|
|
6694
6698
|
const { port } = server.address();
|
|
6695
6699
|
server.close(() => {
|
|
6696
|
-
|
|
6700
|
+
resolve2(port);
|
|
6697
6701
|
});
|
|
6698
6702
|
});
|
|
6699
6703
|
server.on("error", reject);
|
|
@@ -6760,7 +6764,7 @@ async function handleRequest(token, req, res) {
|
|
|
6760
6764
|
}
|
|
6761
6765
|
}
|
|
6762
6766
|
function startDesktopServer(token, port) {
|
|
6763
|
-
return new Promise((
|
|
6767
|
+
return new Promise((resolve2, reject) => {
|
|
6764
6768
|
const server = createServer((req, res) => {
|
|
6765
6769
|
handleRequest(token, req, res).catch(() => {
|
|
6766
6770
|
if (!res.headersSent) {
|
|
@@ -6771,7 +6775,7 @@ function startDesktopServer(token, port) {
|
|
|
6771
6775
|
});
|
|
6772
6776
|
server.on("error", reject);
|
|
6773
6777
|
server.listen(port, "127.0.0.1", () => {
|
|
6774
|
-
|
|
6778
|
+
resolve2(server);
|
|
6775
6779
|
});
|
|
6776
6780
|
});
|
|
6777
6781
|
}
|
|
@@ -6835,13 +6839,13 @@ var hostStartCommand = new Command().name("start").description("Start the comput
|
|
|
6835
6839
|
console.log(source_default.dim("Press ^C twice to disconnect"));
|
|
6836
6840
|
console.log();
|
|
6837
6841
|
let sigintCount = 0;
|
|
6838
|
-
await new Promise((
|
|
6842
|
+
await new Promise((resolve2) => {
|
|
6839
6843
|
const keepAlive = setInterval(() => {
|
|
6840
6844
|
}, 6e4);
|
|
6841
6845
|
const done = () => {
|
|
6842
6846
|
clearInterval(keepAlive);
|
|
6843
6847
|
process.removeListener("SIGINT", onSigint);
|
|
6844
|
-
|
|
6848
|
+
resolve2();
|
|
6845
6849
|
};
|
|
6846
6850
|
const onSigint = () => {
|
|
6847
6851
|
sigintCount++;
|
|
@@ -7681,6 +7685,384 @@ Examples:
|
|
|
7681
7685
|
Download a file: zero web download-file <file-id> -o /tmp/out.pdf`
|
|
7682
7686
|
);
|
|
7683
7687
|
|
|
7688
|
+
// src/commands/zero/local-browser/index.ts
|
|
7689
|
+
init_esm_shims();
|
|
7690
|
+
function sleep3(ms) {
|
|
7691
|
+
return new Promise((resolve2) => {
|
|
7692
|
+
setTimeout(resolve2, ms);
|
|
7693
|
+
});
|
|
7694
|
+
}
|
|
7695
|
+
function parseTimeoutSeconds(value) {
|
|
7696
|
+
if (!value) return 30;
|
|
7697
|
+
const seconds = Number.parseInt(value, 10);
|
|
7698
|
+
if (!Number.isFinite(seconds) || seconds <= 0) {
|
|
7699
|
+
throw new Error("Timeout must be a positive number of seconds");
|
|
7700
|
+
}
|
|
7701
|
+
return seconds;
|
|
7702
|
+
}
|
|
7703
|
+
function resultText(command) {
|
|
7704
|
+
if (!command.result) {
|
|
7705
|
+
return "";
|
|
7706
|
+
}
|
|
7707
|
+
return JSON.stringify(command.result, null, 2);
|
|
7708
|
+
}
|
|
7709
|
+
async function runReadCommand(kind, options) {
|
|
7710
|
+
const timeoutSeconds = parseTimeoutSeconds(options.timeout);
|
|
7711
|
+
const created = await createLocalBrowserReadCommand({
|
|
7712
|
+
kind,
|
|
7713
|
+
timeoutMs: timeoutSeconds * 1e3,
|
|
7714
|
+
...options.tabId ? { tabId: options.tabId } : {},
|
|
7715
|
+
...options.host ? { hostName: options.host } : {},
|
|
7716
|
+
...options.hostId ? { hostId: options.hostId } : {}
|
|
7717
|
+
});
|
|
7718
|
+
const deadline = Date.now() + timeoutSeconds * 1e3;
|
|
7719
|
+
while (Date.now() <= deadline) {
|
|
7720
|
+
const command = await getLocalBrowserReadCommand(created.commandId);
|
|
7721
|
+
if (command.status === "queued" || command.status === "running") {
|
|
7722
|
+
if (process.stdout.isTTY) {
|
|
7723
|
+
process.stdout.write(".");
|
|
7724
|
+
}
|
|
7725
|
+
await sleep3(1e3);
|
|
7726
|
+
continue;
|
|
7727
|
+
}
|
|
7728
|
+
if (process.stdout.isTTY) {
|
|
7729
|
+
process.stdout.write("\n");
|
|
7730
|
+
}
|
|
7731
|
+
if (command.status === "failed") {
|
|
7732
|
+
throw new Error(
|
|
7733
|
+
command.error ? `${command.error.code}: ${command.error.message}` : "Local-browser command failed"
|
|
7734
|
+
);
|
|
7735
|
+
}
|
|
7736
|
+
const text = resultText(command);
|
|
7737
|
+
if (text) {
|
|
7738
|
+
console.log(text);
|
|
7739
|
+
}
|
|
7740
|
+
return;
|
|
7741
|
+
}
|
|
7742
|
+
throw new Error(`Local-browser command timed out: ${created.commandId}`);
|
|
7743
|
+
}
|
|
7744
|
+
function addReadOptions(command) {
|
|
7745
|
+
return command.option("--host <name>", "Run on a named local-browser host").option("--host-id <id>", "Run on a specific local-browser host id").option("--tab-id <id>", "Target a specific browser tab").option("--timeout <seconds>", "Maximum time to wait", "30");
|
|
7746
|
+
}
|
|
7747
|
+
function readCommand(name, kind) {
|
|
7748
|
+
return addReadOptions(
|
|
7749
|
+
new Command().name(name).description(`Run ${kind}`).action(
|
|
7750
|
+
withErrorHandler(async (options) => {
|
|
7751
|
+
await runReadCommand(kind, options);
|
|
7752
|
+
})
|
|
7753
|
+
)
|
|
7754
|
+
);
|
|
7755
|
+
}
|
|
7756
|
+
var tabsCommand = new Command().name("tabs").description("Read browser tabs").addCommand(readCommand("list", "tabs.list")).addCommand(readCommand("current", "tabs.current"));
|
|
7757
|
+
var pageCommand = new Command().name("page").description("Read the active browser page").addCommand(readCommand("snapshot", "page.snapshot")).addCommand(readCommand("screenshot", "page.screenshot")).addCommand(readCommand("selection", "page.selection")).addCommand(readCommand("metadata", "page.metadata"));
|
|
7758
|
+
var zeroLocalBrowserCommand = new Command().name("local-browser").description("Read authorized browser context").addHelpText(
|
|
7759
|
+
"after",
|
|
7760
|
+
`
|
|
7761
|
+
Examples:
|
|
7762
|
+
List tabs? zero local-browser tabs list
|
|
7763
|
+
Current tab? zero local-browser tabs current
|
|
7764
|
+
Page metadata? zero local-browser page metadata
|
|
7765
|
+
Page selection? zero local-browser page selection`
|
|
7766
|
+
).addCommand(tabsCommand).addCommand(pageCommand);
|
|
7767
|
+
|
|
7768
|
+
// src/commands/zero/host/index.ts
|
|
7769
|
+
init_esm_shims();
|
|
7770
|
+
import { readFile as readFile3 } from "fs/promises";
|
|
7771
|
+
|
|
7772
|
+
// src/lib/host/static-site.ts
|
|
7773
|
+
init_esm_shims();
|
|
7774
|
+
import { createHash } from "crypto";
|
|
7775
|
+
import { readdir, readFile as readFile2, stat } from "fs/promises";
|
|
7776
|
+
import { extname as extname3, relative, resolve, sep, dirname, posix } from "path";
|
|
7777
|
+
var MIME_BY_EXTENSION3 = {
|
|
7778
|
+
".html": "text/html; charset=utf-8",
|
|
7779
|
+
".htm": "text/html; charset=utf-8",
|
|
7780
|
+
".css": "text/css; charset=utf-8",
|
|
7781
|
+
".js": "application/javascript; charset=utf-8",
|
|
7782
|
+
".mjs": "application/javascript; charset=utf-8",
|
|
7783
|
+
".json": "application/json; charset=utf-8",
|
|
7784
|
+
".map": "application/json; charset=utf-8",
|
|
7785
|
+
".txt": "text/plain; charset=utf-8",
|
|
7786
|
+
".xml": "application/xml; charset=utf-8",
|
|
7787
|
+
".svg": "image/svg+xml; charset=utf-8",
|
|
7788
|
+
".png": "image/png",
|
|
7789
|
+
".jpg": "image/jpeg",
|
|
7790
|
+
".jpeg": "image/jpeg",
|
|
7791
|
+
".gif": "image/gif",
|
|
7792
|
+
".webp": "image/webp",
|
|
7793
|
+
".avif": "image/avif",
|
|
7794
|
+
".ico": "image/x-icon",
|
|
7795
|
+
".wasm": "application/wasm",
|
|
7796
|
+
".woff": "font/woff",
|
|
7797
|
+
".woff2": "font/woff2",
|
|
7798
|
+
".ttf": "font/ttf",
|
|
7799
|
+
".otf": "font/otf",
|
|
7800
|
+
".eot": "application/vnd.ms-fontobject",
|
|
7801
|
+
".mp4": "video/mp4",
|
|
7802
|
+
".webm": "video/webm",
|
|
7803
|
+
".mp3": "audio/mpeg",
|
|
7804
|
+
".wav": "audio/wav"
|
|
7805
|
+
};
|
|
7806
|
+
var HTML_REFERENCE_RE = /<(?:script|link|img|source|video|audio|embed|object)\b[^>]*\s(?:src|href|poster|data)=["']([^"']+)["'][^>]*>/giu;
|
|
7807
|
+
var SRCSET_RE = /\s(?:srcset)=["']([^"']+)["']/giu;
|
|
7808
|
+
var CSS_URL_RE = /url\(\s*["']?([^"')]+)["']?\s*\)/giu;
|
|
7809
|
+
var CSS_IMPORT_RE = /@import\s+(?:url\()?["']([^"']+)["']\)?/giu;
|
|
7810
|
+
function inferContentType3(path) {
|
|
7811
|
+
return MIME_BY_EXTENSION3[extname3(path).toLowerCase()] ?? "application/octet-stream";
|
|
7812
|
+
}
|
|
7813
|
+
function looksImmutable(path) {
|
|
7814
|
+
if (path.startsWith("/assets/")) {
|
|
7815
|
+
return true;
|
|
7816
|
+
}
|
|
7817
|
+
return /(?:[-.])[A-Za-z0-9_-]{8,}\.[A-Za-z0-9]+$/u.test(path);
|
|
7818
|
+
}
|
|
7819
|
+
function toSitePath(root, absolutePath) {
|
|
7820
|
+
const rel = relative(root, absolutePath).split(sep).join("/");
|
|
7821
|
+
return `/${rel}`;
|
|
7822
|
+
}
|
|
7823
|
+
function isSafeSitePath(path) {
|
|
7824
|
+
if (!path.startsWith("/") || path.startsWith("//")) {
|
|
7825
|
+
return false;
|
|
7826
|
+
}
|
|
7827
|
+
if (path.includes("\\") || path.includes("\0")) {
|
|
7828
|
+
return false;
|
|
7829
|
+
}
|
|
7830
|
+
const segments = path.split("/").filter(Boolean);
|
|
7831
|
+
return !segments.some((segment) => {
|
|
7832
|
+
return segment === "." || segment === "..";
|
|
7833
|
+
});
|
|
7834
|
+
}
|
|
7835
|
+
function isExternalReference(value) {
|
|
7836
|
+
return /^(?:[a-z][a-z0-9+.-]*:|\/\/|#)/iu.test(value);
|
|
7837
|
+
}
|
|
7838
|
+
function stripQueryAndHash(value) {
|
|
7839
|
+
const hashIndex = value.indexOf("#");
|
|
7840
|
+
const withoutHash = hashIndex >= 0 ? value.slice(0, hashIndex) : value;
|
|
7841
|
+
const queryIndex = withoutHash.indexOf("?");
|
|
7842
|
+
return queryIndex >= 0 ? withoutHash.slice(0, queryIndex) : withoutHash;
|
|
7843
|
+
}
|
|
7844
|
+
function normalizeReference(fromPath, raw) {
|
|
7845
|
+
const trimmed = raw.trim();
|
|
7846
|
+
if (!trimmed || isExternalReference(trimmed)) {
|
|
7847
|
+
return null;
|
|
7848
|
+
}
|
|
7849
|
+
const stripped = stripQueryAndHash(trimmed);
|
|
7850
|
+
if (!stripped || stripped.endsWith("/")) {
|
|
7851
|
+
return null;
|
|
7852
|
+
}
|
|
7853
|
+
const resolved = stripped.startsWith("/") ? posix.normalize(stripped) : posix.normalize(posix.join(dirname(fromPath), stripped));
|
|
7854
|
+
const path = resolved.startsWith("/") ? resolved : `/${resolved}`;
|
|
7855
|
+
if (!isSafeSitePath(path)) {
|
|
7856
|
+
throw new Error(`Invalid asset reference in ${fromPath}: ${raw}`);
|
|
7857
|
+
}
|
|
7858
|
+
return path;
|
|
7859
|
+
}
|
|
7860
|
+
function shouldRequireHtmlReference(path) {
|
|
7861
|
+
return extname3(path).length > 0 || path.startsWith("/assets/");
|
|
7862
|
+
}
|
|
7863
|
+
function isHtmlExtension(ext) {
|
|
7864
|
+
return ext === ".html" || ext === ".htm";
|
|
7865
|
+
}
|
|
7866
|
+
function shouldValidateReferences(ext) {
|
|
7867
|
+
return isHtmlExtension(ext) || ext === ".css";
|
|
7868
|
+
}
|
|
7869
|
+
function collectSrcsetReferences(value) {
|
|
7870
|
+
return value.split(",").map((entry) => {
|
|
7871
|
+
return entry.trim().split(/\s+/u)[0] ?? "";
|
|
7872
|
+
}).filter(Boolean);
|
|
7873
|
+
}
|
|
7874
|
+
function collectHtmlReferences(text) {
|
|
7875
|
+
const references = [];
|
|
7876
|
+
for (const match of text.matchAll(HTML_REFERENCE_RE)) {
|
|
7877
|
+
if (match[1]) references.push(match[1]);
|
|
7878
|
+
}
|
|
7879
|
+
for (const match of text.matchAll(SRCSET_RE)) {
|
|
7880
|
+
if (!match[1]) continue;
|
|
7881
|
+
references.push(...collectSrcsetReferences(match[1]));
|
|
7882
|
+
}
|
|
7883
|
+
return references;
|
|
7884
|
+
}
|
|
7885
|
+
function collectCssReferences(text) {
|
|
7886
|
+
const references = [];
|
|
7887
|
+
for (const match of text.matchAll(CSS_URL_RE)) {
|
|
7888
|
+
if (match[1]) references.push(match[1]);
|
|
7889
|
+
}
|
|
7890
|
+
for (const match of text.matchAll(CSS_IMPORT_RE)) {
|
|
7891
|
+
if (match[1]) references.push(match[1]);
|
|
7892
|
+
}
|
|
7893
|
+
return references;
|
|
7894
|
+
}
|
|
7895
|
+
function collectReferences(ext, text) {
|
|
7896
|
+
return isHtmlExtension(ext) ? collectHtmlReferences(text) : collectCssReferences(text);
|
|
7897
|
+
}
|
|
7898
|
+
async function hashFile(path) {
|
|
7899
|
+
const bytes = await readFile2(path);
|
|
7900
|
+
return createHash("sha256").update(bytes).digest("hex");
|
|
7901
|
+
}
|
|
7902
|
+
async function walk(root, dir, files) {
|
|
7903
|
+
const entries = await readdir(dir, { withFileTypes: true });
|
|
7904
|
+
for (const entry of entries) {
|
|
7905
|
+
const fullPath = resolve(dir, entry.name);
|
|
7906
|
+
if (entry.isDirectory()) {
|
|
7907
|
+
await walk(root, fullPath, files);
|
|
7908
|
+
continue;
|
|
7909
|
+
}
|
|
7910
|
+
if (!entry.isFile()) {
|
|
7911
|
+
throw new Error(`Unsupported file type in hosted site: ${fullPath}`);
|
|
7912
|
+
}
|
|
7913
|
+
const fileStat = await stat(fullPath);
|
|
7914
|
+
const path = toSitePath(root, fullPath);
|
|
7915
|
+
if (!isSafeSitePath(path)) {
|
|
7916
|
+
throw new Error(`Invalid hosted-site path: ${path}`);
|
|
7917
|
+
}
|
|
7918
|
+
files.push({
|
|
7919
|
+
absolutePath: fullPath,
|
|
7920
|
+
path,
|
|
7921
|
+
size: fileStat.size,
|
|
7922
|
+
sha256: await hashFile(fullPath),
|
|
7923
|
+
contentType: inferContentType3(path),
|
|
7924
|
+
immutable: looksImmutable(path) || void 0
|
|
7925
|
+
});
|
|
7926
|
+
}
|
|
7927
|
+
}
|
|
7928
|
+
async function assertReferencesExist(files) {
|
|
7929
|
+
const byPath = new Map(
|
|
7930
|
+
files.map((file) => {
|
|
7931
|
+
return [file.path, file];
|
|
7932
|
+
})
|
|
7933
|
+
);
|
|
7934
|
+
for (const file of files) {
|
|
7935
|
+
const ext = extname3(file.path).toLowerCase();
|
|
7936
|
+
if (!shouldValidateReferences(ext)) {
|
|
7937
|
+
continue;
|
|
7938
|
+
}
|
|
7939
|
+
const text = await readFile2(file.absolutePath, "utf8");
|
|
7940
|
+
const references = collectReferences(ext, text);
|
|
7941
|
+
for (const reference of references) {
|
|
7942
|
+
const normalized = normalizeReference(file.path, reference);
|
|
7943
|
+
if (!normalized) {
|
|
7944
|
+
continue;
|
|
7945
|
+
}
|
|
7946
|
+
if (isHtmlExtension(ext) && !shouldRequireHtmlReference(normalized)) {
|
|
7947
|
+
continue;
|
|
7948
|
+
}
|
|
7949
|
+
if (!byPath.has(normalized)) {
|
|
7950
|
+
throw new Error(
|
|
7951
|
+
`Missing asset referenced by ${file.path}: ${reference}`
|
|
7952
|
+
);
|
|
7953
|
+
}
|
|
7954
|
+
}
|
|
7955
|
+
}
|
|
7956
|
+
}
|
|
7957
|
+
async function scanStaticSite(rootPath) {
|
|
7958
|
+
const root = resolve(rootPath);
|
|
7959
|
+
const rootStat = await stat(root);
|
|
7960
|
+
if (!rootStat.isDirectory()) {
|
|
7961
|
+
throw new Error(`Hosted site path must be a directory: ${rootPath}`);
|
|
7962
|
+
}
|
|
7963
|
+
const files = [];
|
|
7964
|
+
await walk(root, root, files);
|
|
7965
|
+
if (!files.some((file) => {
|
|
7966
|
+
return file.path === "/index.html";
|
|
7967
|
+
})) {
|
|
7968
|
+
throw new Error("Hosted site directory must include index.html");
|
|
7969
|
+
}
|
|
7970
|
+
await assertReferencesExist(files);
|
|
7971
|
+
return {
|
|
7972
|
+
root,
|
|
7973
|
+
files: files.sort((a, b) => {
|
|
7974
|
+
return a.path.localeCompare(b.path);
|
|
7975
|
+
})
|
|
7976
|
+
};
|
|
7977
|
+
}
|
|
7978
|
+
|
|
7979
|
+
// src/commands/zero/host/index.ts
|
|
7980
|
+
function formatBytes(bytes) {
|
|
7981
|
+
if (bytes < 1024) return `${bytes} B`;
|
|
7982
|
+
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
7983
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
7984
|
+
}
|
|
7985
|
+
var zeroHostCommand = new Command().name("host").description("Publish a built static site and print its public URL").argument("<dir>", "Static build directory, for example ./dist").requiredOption("--site <slug>", "Public site slug, e.g. my-product-demo").option("--spa", "Serve unknown HTML navigation paths from index.html").option("--json", "Output only the final result as JSON").addHelpText(
|
|
7986
|
+
"after",
|
|
7987
|
+
`
|
|
7988
|
+
Examples:
|
|
7989
|
+
Publish a Vite build: zero host ./dist --site my-product-demo --spa
|
|
7990
|
+
Machine readable: zero host ./dist --site my-product-demo --spa --json
|
|
7991
|
+
|
|
7992
|
+
Notes:
|
|
7993
|
+
- Authenticates via ZERO_TOKEN (requires host:write capability)
|
|
7994
|
+
- The directory must include index.html
|
|
7995
|
+
- Local HTML/CSS asset references must point at files inside the directory`
|
|
7996
|
+
).action(
|
|
7997
|
+
withErrorHandler(async (dir, options) => {
|
|
7998
|
+
const scan = await scanStaticSite(dir);
|
|
7999
|
+
const totalSize = scan.files.reduce((sum, file) => {
|
|
8000
|
+
return sum + file.size;
|
|
8001
|
+
}, 0);
|
|
8002
|
+
if (!options.json) {
|
|
8003
|
+
console.log(source_default.dim(`Preparing ${scan.files.length} files...`));
|
|
8004
|
+
}
|
|
8005
|
+
const prepared = await prepareHostedSite({
|
|
8006
|
+
site: options.site,
|
|
8007
|
+
spaFallback: Boolean(options.spa),
|
|
8008
|
+
files: scan.files.map((file) => {
|
|
8009
|
+
return {
|
|
8010
|
+
path: file.path,
|
|
8011
|
+
size: file.size,
|
|
8012
|
+
sha256: file.sha256,
|
|
8013
|
+
contentType: file.contentType,
|
|
8014
|
+
immutable: file.immutable
|
|
8015
|
+
};
|
|
8016
|
+
})
|
|
8017
|
+
});
|
|
8018
|
+
const uploadByPath = new Map(
|
|
8019
|
+
prepared.uploads.map((upload) => {
|
|
8020
|
+
return [upload.path, upload.uploadUrl];
|
|
8021
|
+
})
|
|
8022
|
+
);
|
|
8023
|
+
for (const file of scan.files) {
|
|
8024
|
+
const uploadUrl = uploadByPath.get(file.path);
|
|
8025
|
+
if (!uploadUrl) {
|
|
8026
|
+
throw new Error(`Missing upload URL for ${file.path}`);
|
|
8027
|
+
}
|
|
8028
|
+
if (!options.json) {
|
|
8029
|
+
console.log(source_default.dim(`Uploading ${file.path}`));
|
|
8030
|
+
}
|
|
8031
|
+
const bytes = await readFile3(file.absolutePath);
|
|
8032
|
+
const response = await fetch(uploadUrl, {
|
|
8033
|
+
method: "PUT",
|
|
8034
|
+
headers: { "Content-Type": file.contentType },
|
|
8035
|
+
body: new Uint8Array(bytes)
|
|
8036
|
+
});
|
|
8037
|
+
if (!response.ok) {
|
|
8038
|
+
throw new Error(
|
|
8039
|
+
`Failed to upload ${file.path} (HTTP ${response.status})`
|
|
8040
|
+
);
|
|
8041
|
+
}
|
|
8042
|
+
}
|
|
8043
|
+
const completed = await completeHostedSite(prepared.deploymentId);
|
|
8044
|
+
if (options.json) {
|
|
8045
|
+
console.log(
|
|
8046
|
+
JSON.stringify({
|
|
8047
|
+
siteId: completed.siteId,
|
|
8048
|
+
deploymentId: completed.deploymentId,
|
|
8049
|
+
publicSlug: completed.publicSlug,
|
|
8050
|
+
url: completed.url,
|
|
8051
|
+
fileCount: scan.files.length,
|
|
8052
|
+
size: totalSize
|
|
8053
|
+
})
|
|
8054
|
+
);
|
|
8055
|
+
return;
|
|
8056
|
+
}
|
|
8057
|
+
console.log(source_default.green("\u2713 Hosted site ready"));
|
|
8058
|
+
console.log(source_default.dim(` Site: ${completed.publicSlug}`));
|
|
8059
|
+
console.log(source_default.dim(` Deployment: ${completed.deploymentId}`));
|
|
8060
|
+
console.log(source_default.dim(` Files: ${scan.files.length.toLocaleString()}`));
|
|
8061
|
+
console.log(source_default.dim(` Size: ${formatBytes(totalSize)}`));
|
|
8062
|
+
console.log(` URL: ${completed.url}`);
|
|
8063
|
+
})
|
|
8064
|
+
);
|
|
8065
|
+
|
|
7684
8066
|
// src/zero.ts
|
|
7685
8067
|
var COMMAND_CAPABILITY_MAP = {
|
|
7686
8068
|
agent: "agent:read",
|
|
@@ -7700,7 +8082,9 @@ var COMMAND_CAPABILITY_MAP = {
|
|
|
7700
8082
|
"computer-use": "computer-use:write",
|
|
7701
8083
|
"built-in": "file:write",
|
|
7702
8084
|
web: null,
|
|
7703
|
-
|
|
8085
|
+
host: "host:write",
|
|
8086
|
+
"remote-agent": ["remote-agent:read", "remote-agent:write"],
|
|
8087
|
+
"local-browser": "local-browser:read"
|
|
7704
8088
|
};
|
|
7705
8089
|
var DEFAULT_COMMANDS = [
|
|
7706
8090
|
zeroOrgCommand,
|
|
@@ -7724,7 +8108,9 @@ var DEFAULT_COMMANDS = [
|
|
|
7724
8108
|
zeroComputerUseCommand,
|
|
7725
8109
|
zeroBuiltInCommand,
|
|
7726
8110
|
zeroWebCommand,
|
|
7727
|
-
|
|
8111
|
+
zeroHostCommand,
|
|
8112
|
+
zeroRemoteAgentCommand,
|
|
8113
|
+
zeroLocalBrowserCommand
|
|
7728
8114
|
];
|
|
7729
8115
|
function shouldHideCommand(name, payload) {
|
|
7730
8116
|
if (!payload) return false;
|
|
@@ -7738,6 +8124,30 @@ function shouldHideCommand(name, payload) {
|
|
|
7738
8124
|
}
|
|
7739
8125
|
return !payload.capabilities.includes(requiredCap);
|
|
7740
8126
|
}
|
|
8127
|
+
function buildZeroHelpText(payload = decodeZeroTokenPayload()) {
|
|
8128
|
+
const examples = [
|
|
8129
|
+
" Check a connector? zero doctor check-connector --env-name <ENV_NAME>",
|
|
8130
|
+
" Send a Slack message? zero slack message send --help",
|
|
8131
|
+
" List Telegram bots? zero telegram bot list",
|
|
8132
|
+
" Send Telegram? zero telegram message send --help",
|
|
8133
|
+
" Upload Telegram? zero telegram upload-file --help",
|
|
8134
|
+
" Download Telegram? zero telegram download-file --help",
|
|
8135
|
+
" Send AgentPhone? zero phone message --help",
|
|
8136
|
+
" Upload AgentPhone? zero phone upload-file --help",
|
|
8137
|
+
" Download AgentPhone? zero phone download-file --help",
|
|
8138
|
+
" Set up a schedule? zero schedule setup --help",
|
|
8139
|
+
" Update yourself? zero agent --help",
|
|
8140
|
+
" Manage custom skills? zero skill --help",
|
|
8141
|
+
" Generate image? zero built-in generate image --help",
|
|
8142
|
+
" Generate voice? zero built-in generate voice --help",
|
|
8143
|
+
...shouldHideCommand("local-browser", payload) ? [] : [" Read browser context? zero local-browser --help"],
|
|
8144
|
+
...shouldHideCommand("host", payload) ? [] : [" Host a static site? zero host ./dist --site my-site --spa"],
|
|
8145
|
+
" Check your identity? zero whoami"
|
|
8146
|
+
];
|
|
8147
|
+
return `
|
|
8148
|
+
Examples:
|
|
8149
|
+
${examples.join("\n")}`;
|
|
8150
|
+
}
|
|
7741
8151
|
function registerZeroCommands(prog, commands) {
|
|
7742
8152
|
const token = process.env.ZERO_TOKEN;
|
|
7743
8153
|
const payload = token ? decodeZeroTokenPayload(token) : void 0;
|
|
@@ -7749,32 +8159,16 @@ function registerZeroCommands(prog, commands) {
|
|
|
7749
8159
|
var program = new Command();
|
|
7750
8160
|
program.name("zero").description(
|
|
7751
8161
|
"Zero CLI \u2014 interact with the zero platform from inside the sandbox"
|
|
7752
|
-
).version("9.
|
|
7753
|
-
|
|
7754
|
-
|
|
7755
|
-
Examples:
|
|
7756
|
-
Check a connector? zero doctor check-connector --env-name <ENV_NAME>
|
|
7757
|
-
Send a Slack message? zero slack message send --help
|
|
7758
|
-
List Telegram bots? zero telegram bot list
|
|
7759
|
-
Send Telegram? zero telegram message send --help
|
|
7760
|
-
Upload Telegram? zero telegram upload-file --help
|
|
7761
|
-
Download Telegram? zero telegram download-file --help
|
|
7762
|
-
Send AgentPhone? zero phone message --help
|
|
7763
|
-
Upload AgentPhone? zero phone upload-file --help
|
|
7764
|
-
Download AgentPhone? zero phone download-file --help
|
|
7765
|
-
Set up a schedule? zero schedule setup --help
|
|
7766
|
-
Update yourself? zero agent --help
|
|
7767
|
-
Manage custom skills? zero skill --help
|
|
7768
|
-
Generate image? zero built-in generate image --help
|
|
7769
|
-
Generate voice? zero built-in generate voice --help
|
|
7770
|
-
Check your identity? zero whoami`
|
|
7771
|
-
);
|
|
8162
|
+
).version("9.151.0").addHelpText("after", () => {
|
|
8163
|
+
return buildZeroHelpText();
|
|
8164
|
+
});
|
|
7772
8165
|
if (process.argv[1]?.endsWith("zero.js") || process.argv[1]?.endsWith("zero.ts") || process.argv[1]?.endsWith("zero")) {
|
|
7773
8166
|
configureGlobalProxyFromEnv();
|
|
7774
8167
|
registerZeroCommands(program);
|
|
7775
8168
|
program.parse();
|
|
7776
8169
|
}
|
|
7777
8170
|
export {
|
|
8171
|
+
buildZeroHelpText,
|
|
7778
8172
|
program,
|
|
7779
8173
|
registerZeroCommands
|
|
7780
8174
|
};
|