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