@vm0/cli 9.103.3 → 9.104.1
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-LQW4RGRH.js → chunk-FYV4IKTF.js} +3 -3
- package/index.js +10 -10
- package/package.json +1 -1
- package/zero.js +146 -74
- package/zero.js.map +1 -1
- /package/{chunk-LQW4RGRH.js.map → chunk-FYV4IKTF.js.map} +0 -0
|
@@ -49,7 +49,7 @@ if (DSN) {
|
|
|
49
49
|
Sentry.init({
|
|
50
50
|
dsn: DSN,
|
|
51
51
|
environment: process.env.SENTRY_ENVIRONMENT ?? "production",
|
|
52
|
-
release: "9.
|
|
52
|
+
release: "9.104.1",
|
|
53
53
|
sendDefaultPii: false,
|
|
54
54
|
tracesSampleRate: 0,
|
|
55
55
|
shutdownTimeout: 500,
|
|
@@ -68,7 +68,7 @@ if (DSN) {
|
|
|
68
68
|
}
|
|
69
69
|
});
|
|
70
70
|
Sentry.setContext("cli", {
|
|
71
|
-
version: "9.
|
|
71
|
+
version: "9.104.1",
|
|
72
72
|
command: process.argv.slice(2).join(" ")
|
|
73
73
|
});
|
|
74
74
|
Sentry.setContext("runtime", {
|
|
@@ -32244,4 +32244,4 @@ export {
|
|
|
32244
32244
|
parseTime,
|
|
32245
32245
|
paginate
|
|
32246
32246
|
};
|
|
32247
|
-
//# sourceMappingURL=chunk-
|
|
32247
|
+
//# sourceMappingURL=chunk-FYV4IKTF.js.map
|
package/index.js
CHANGED
|
@@ -61,7 +61,7 @@ import {
|
|
|
61
61
|
showNextSteps,
|
|
62
62
|
volumeConfigSchema,
|
|
63
63
|
withErrorHandler
|
|
64
|
-
} from "./chunk-
|
|
64
|
+
} from "./chunk-FYV4IKTF.js";
|
|
65
65
|
|
|
66
66
|
// src/index.ts
|
|
67
67
|
import { Command as Command44 } from "commander";
|
|
@@ -454,7 +454,7 @@ function getConfigPath() {
|
|
|
454
454
|
return join(homedir(), ".vm0", "config.json");
|
|
455
455
|
}
|
|
456
456
|
var infoCommand = new Command6().name("info").description("Display environment and debug information").action(async () => {
|
|
457
|
-
console.log(chalk3.bold(`VM0 CLI v${"9.
|
|
457
|
+
console.log(chalk3.bold(`VM0 CLI v${"9.104.1"}`));
|
|
458
458
|
console.log();
|
|
459
459
|
const config = await loadConfig();
|
|
460
460
|
const hasEnvToken = !!process.env.VM0_TOKEN;
|
|
@@ -1581,7 +1581,7 @@ var composeCommand = new Command7().name("compose").description("Create or updat
|
|
|
1581
1581
|
options.autoUpdate = false;
|
|
1582
1582
|
}
|
|
1583
1583
|
if (options.autoUpdate !== false) {
|
|
1584
|
-
await startSilentUpgrade("9.
|
|
1584
|
+
await startSilentUpgrade("9.104.1");
|
|
1585
1585
|
}
|
|
1586
1586
|
try {
|
|
1587
1587
|
let result;
|
|
@@ -1655,7 +1655,7 @@ var mainRunCommand = new Command8().name("run").description("Run an agent").argu
|
|
|
1655
1655
|
withErrorHandler(
|
|
1656
1656
|
async (identifier, prompt, options) => {
|
|
1657
1657
|
if (options.autoUpdate !== false) {
|
|
1658
|
-
await startSilentUpgrade("9.
|
|
1658
|
+
await startSilentUpgrade("9.104.1");
|
|
1659
1659
|
}
|
|
1660
1660
|
const { name, version } = parseIdentifier(identifier);
|
|
1661
1661
|
let composeId;
|
|
@@ -3413,7 +3413,7 @@ var cookAction = new Command35().name("cook").description("Quick start: prepare,
|
|
|
3413
3413
|
withErrorHandler(
|
|
3414
3414
|
async (prompt, options) => {
|
|
3415
3415
|
if (options.autoUpdate !== false) {
|
|
3416
|
-
const shouldExit = await checkAndUpgrade("9.
|
|
3416
|
+
const shouldExit = await checkAndUpgrade("9.104.1", prompt);
|
|
3417
3417
|
if (shouldExit) {
|
|
3418
3418
|
process.exit(0);
|
|
3419
3419
|
}
|
|
@@ -4156,13 +4156,13 @@ var upgradeCommand = new Command42().name("upgrade").description("Upgrade vm0 CL
|
|
|
4156
4156
|
if (latestVersion === null) {
|
|
4157
4157
|
throw new Error("Could not check for updates. Please try again later.");
|
|
4158
4158
|
}
|
|
4159
|
-
if (latestVersion === "9.
|
|
4160
|
-
console.log(chalk33.green(`\u2713 Already up to date (${"9.
|
|
4159
|
+
if (latestVersion === "9.104.1") {
|
|
4160
|
+
console.log(chalk33.green(`\u2713 Already up to date (${"9.104.1"})`));
|
|
4161
4161
|
return;
|
|
4162
4162
|
}
|
|
4163
4163
|
console.log(
|
|
4164
4164
|
chalk33.yellow(
|
|
4165
|
-
`Current version: ${"9.
|
|
4165
|
+
`Current version: ${"9.104.1"} -> Latest version: ${latestVersion}`
|
|
4166
4166
|
)
|
|
4167
4167
|
);
|
|
4168
4168
|
console.log();
|
|
@@ -4189,7 +4189,7 @@ var upgradeCommand = new Command42().name("upgrade").description("Upgrade vm0 CL
|
|
|
4189
4189
|
const success = await performUpgrade(packageManager);
|
|
4190
4190
|
if (success) {
|
|
4191
4191
|
console.log(
|
|
4192
|
-
chalk33.green(`\u2713 Upgraded from ${"9.
|
|
4192
|
+
chalk33.green(`\u2713 Upgraded from ${"9.104.1"} to ${latestVersion}`)
|
|
4193
4193
|
);
|
|
4194
4194
|
return;
|
|
4195
4195
|
}
|
|
@@ -4257,7 +4257,7 @@ var whoamiCommand = new Command43().name("whoami").description("Show current ide
|
|
|
4257
4257
|
|
|
4258
4258
|
// src/index.ts
|
|
4259
4259
|
var program = new Command44();
|
|
4260
|
-
program.name("vm0").description("VM0 CLI - Build and run agents with natural language").version("9.
|
|
4260
|
+
program.name("vm0").description("VM0 CLI - Build and run agents with natural language").version("9.104.1");
|
|
4261
4261
|
program.addCommand(authCommand);
|
|
4262
4262
|
program.addCommand(infoCommand);
|
|
4263
4263
|
program.addCommand(composeCommand);
|
package/package.json
CHANGED
package/zero.js
CHANGED
|
@@ -115,7 +115,7 @@ import {
|
|
|
115
115
|
upsertZeroOrgModelProvider,
|
|
116
116
|
withErrorHandler,
|
|
117
117
|
zeroAgentCustomSkillNameSchema
|
|
118
|
-
} from "./chunk-
|
|
118
|
+
} from "./chunk-FYV4IKTF.js";
|
|
119
119
|
|
|
120
120
|
// src/zero.ts
|
|
121
121
|
import { Command as Command77 } from "commander";
|
|
@@ -2265,10 +2265,57 @@ Notes:
|
|
|
2265
2265
|
);
|
|
2266
2266
|
|
|
2267
2267
|
// src/commands/zero/doctor/firewall-deny.ts
|
|
2268
|
-
import { Command as
|
|
2268
|
+
import { Command as Command36, Option } from "commander";
|
|
2269
|
+
var firewallDenyCommand = new Command36().name("firewall-deny").description(
|
|
2270
|
+
"Diagnose a firewall denial and find the permission that covers it"
|
|
2271
|
+
).argument("<firewall-ref>", "The firewall connector type (e.g. github)").addOption(
|
|
2272
|
+
new Option(
|
|
2273
|
+
"--method <method>",
|
|
2274
|
+
"The denied HTTP method"
|
|
2275
|
+
).makeOptionMandatory()
|
|
2276
|
+
).addOption(
|
|
2277
|
+
new Option("--path <path>", "The denied path").makeOptionMandatory()
|
|
2278
|
+
).addHelpText(
|
|
2279
|
+
"after",
|
|
2280
|
+
`
|
|
2281
|
+
Examples:
|
|
2282
|
+
zero doctor firewall-deny github --method GET --path /repos/owner/repo/pulls
|
|
2283
|
+
zero doctor firewall-deny slack --method POST --path /chat.postMessage
|
|
2284
|
+
|
|
2285
|
+
Notes:
|
|
2286
|
+
- Identifies which named permission covers a denied request
|
|
2287
|
+
- Use firewall-permissions-change to request or enable the permission`
|
|
2288
|
+
).action(
|
|
2289
|
+
withErrorHandler(
|
|
2290
|
+
async (firewallRef, opts) => {
|
|
2291
|
+
if (!isFirewallConnectorType(firewallRef)) {
|
|
2292
|
+
throw new Error(`Unknown firewall connector type: ${firewallRef}`);
|
|
2293
|
+
}
|
|
2294
|
+
const { label } = CONNECTOR_TYPES[firewallRef];
|
|
2295
|
+
const config = getConnectorFirewall(firewallRef);
|
|
2296
|
+
const permissions = findMatchingPermissions(
|
|
2297
|
+
opts.method,
|
|
2298
|
+
opts.path,
|
|
2299
|
+
config
|
|
2300
|
+
);
|
|
2301
|
+
console.log(
|
|
2302
|
+
`The ${label} firewall blocked ${opts.method} ${opts.path}.`
|
|
2303
|
+
);
|
|
2304
|
+
if (permissions.length === 0) {
|
|
2305
|
+
console.log("No named permission was found covering this request.");
|
|
2306
|
+
return;
|
|
2307
|
+
}
|
|
2308
|
+
const permission = permissions[0];
|
|
2309
|
+
console.log(`This is covered by the "${permission}" permission.`);
|
|
2310
|
+
console.log(
|
|
2311
|
+
`To request this permission, run: zero doctor firewall-permissions-change ${firewallRef} --permission ${permission} --enable --reason "why this is needed"`
|
|
2312
|
+
);
|
|
2313
|
+
}
|
|
2314
|
+
)
|
|
2315
|
+
);
|
|
2269
2316
|
|
|
2270
2317
|
// src/commands/zero/doctor/firewall-permissions-change.ts
|
|
2271
|
-
import { Command as
|
|
2318
|
+
import { Command as Command37, Option as Option2 } from "commander";
|
|
2272
2319
|
|
|
2273
2320
|
// src/commands/zero/doctor/resolve-role.ts
|
|
2274
2321
|
async function resolveUserId() {
|
|
@@ -2309,15 +2356,21 @@ function findPermissionInConfig(ref, permissionName) {
|
|
|
2309
2356
|
}
|
|
2310
2357
|
return false;
|
|
2311
2358
|
}
|
|
2312
|
-
|
|
2359
|
+
var REASON_MAX_LENGTH = 500;
|
|
2360
|
+
async function outputPermissionChangeMessage(firewallRef, permission, action, reason) {
|
|
2313
2361
|
const { label } = CONNECTOR_TYPES[firewallRef];
|
|
2314
2362
|
const platformOrigin = await getPlatformOrigin();
|
|
2315
2363
|
const agentId = process.env.ZERO_AGENT_ID;
|
|
2364
|
+
const role = agentId ? await resolveAgentRole(agentId) : "unknown";
|
|
2316
2365
|
const urlParams = new URLSearchParams({
|
|
2317
2366
|
ref: firewallRef,
|
|
2318
2367
|
permission,
|
|
2319
2368
|
action: action === "enable" ? "allow" : "deny"
|
|
2320
2369
|
});
|
|
2370
|
+
if (role === "member" && reason) {
|
|
2371
|
+
const truncated = reason.length > REASON_MAX_LENGTH ? reason.slice(0, REASON_MAX_LENGTH) : reason;
|
|
2372
|
+
urlParams.set("reason", truncated);
|
|
2373
|
+
}
|
|
2321
2374
|
const pagePath = agentId ? `/agents/${agentId}/permissions` : "/agents";
|
|
2322
2375
|
const url = `${platformOrigin}${pagePath}?${urlParams.toString()}`;
|
|
2323
2376
|
if (firewallRef === "slack" && permission === "chat:write" && action === "enable") {
|
|
@@ -2333,13 +2386,16 @@ async function outputPermissionChangeMessage(firewallRef, permission, action) {
|
|
|
2333
2386
|
);
|
|
2334
2387
|
console.log("");
|
|
2335
2388
|
}
|
|
2336
|
-
const role = agentId ? await resolveAgentRole(agentId) : "unknown";
|
|
2337
2389
|
if (role === "admin" || role === "owner") {
|
|
2338
2390
|
console.log(
|
|
2339
2391
|
`You can ${action} the "${permission}" permission directly: [Manage ${label} firewall](${url})`
|
|
2340
2392
|
);
|
|
2341
2393
|
} else if (role === "member") {
|
|
2342
|
-
if (
|
|
2394
|
+
if (!reason) {
|
|
2395
|
+
console.log(
|
|
2396
|
+
`IMPORTANT: Re-run with \`--reason "one sentence why this is needed"\` so the admin can review your request faster.`
|
|
2397
|
+
);
|
|
2398
|
+
} else if (action === "enable") {
|
|
2343
2399
|
console.log(
|
|
2344
2400
|
`Permission changes require admin approval. Request access at: [Request ${label} access](${url})`
|
|
2345
2401
|
);
|
|
@@ -2354,19 +2410,24 @@ async function outputPermissionChangeMessage(firewallRef, permission, action) {
|
|
|
2354
2410
|
);
|
|
2355
2411
|
}
|
|
2356
2412
|
}
|
|
2357
|
-
var firewallPermissionsChangeCommand = new
|
|
2358
|
-
new
|
|
2413
|
+
var firewallPermissionsChangeCommand = new Command37().name("firewall-permissions-change").description("Request a firewall permission change (enable or disable)").argument("<firewall-ref>", "The firewall connector type (e.g. github)").addOption(
|
|
2414
|
+
new Option2(
|
|
2359
2415
|
"--permission <name>",
|
|
2360
2416
|
"The permission name to change"
|
|
2361
2417
|
).makeOptionMandatory()
|
|
2362
2418
|
).addOption(
|
|
2363
|
-
new
|
|
2419
|
+
new Option2("--enable", "Request to enable the permission").conflicts(
|
|
2364
2420
|
"disable"
|
|
2365
2421
|
)
|
|
2366
2422
|
).addOption(
|
|
2367
|
-
new
|
|
2423
|
+
new Option2("--disable", "Request to disable the permission").conflicts(
|
|
2368
2424
|
"enable"
|
|
2369
2425
|
)
|
|
2426
|
+
).addOption(
|
|
2427
|
+
new Option2(
|
|
2428
|
+
"--reason <text>",
|
|
2429
|
+
"Brief reason why the permission is needed (max 500 chars)"
|
|
2430
|
+
)
|
|
2370
2431
|
).addHelpText(
|
|
2371
2432
|
"after",
|
|
2372
2433
|
`
|
|
@@ -2395,55 +2456,9 @@ Notes:
|
|
|
2395
2456
|
await outputPermissionChangeMessage(
|
|
2396
2457
|
firewallRef,
|
|
2397
2458
|
opts.permission,
|
|
2398
|
-
action
|
|
2399
|
-
|
|
2400
|
-
}
|
|
2401
|
-
)
|
|
2402
|
-
);
|
|
2403
|
-
|
|
2404
|
-
// src/commands/zero/doctor/firewall-deny.ts
|
|
2405
|
-
var firewallDenyCommand = new Command37().name("firewall-deny").description(
|
|
2406
|
-
"Diagnose a firewall denial and find the permission that covers it"
|
|
2407
|
-
).argument("<firewall-ref>", "The firewall connector type (e.g. github)").addOption(
|
|
2408
|
-
new Option2(
|
|
2409
|
-
"--method <method>",
|
|
2410
|
-
"The denied HTTP method"
|
|
2411
|
-
).makeOptionMandatory()
|
|
2412
|
-
).addOption(
|
|
2413
|
-
new Option2("--path <path>", "The denied path").makeOptionMandatory()
|
|
2414
|
-
).addHelpText(
|
|
2415
|
-
"after",
|
|
2416
|
-
`
|
|
2417
|
-
Examples:
|
|
2418
|
-
zero doctor firewall-deny github --method GET --path /repos/owner/repo/pulls
|
|
2419
|
-
zero doctor firewall-deny slack --method POST --path /chat.postMessage
|
|
2420
|
-
|
|
2421
|
-
Notes:
|
|
2422
|
-
- Identifies which named permission covers a denied request
|
|
2423
|
-
- Outputs a platform URL for the user to allow the permission`
|
|
2424
|
-
).action(
|
|
2425
|
-
withErrorHandler(
|
|
2426
|
-
async (firewallRef, opts) => {
|
|
2427
|
-
if (!isFirewallConnectorType(firewallRef)) {
|
|
2428
|
-
throw new Error(`Unknown firewall connector type: ${firewallRef}`);
|
|
2429
|
-
}
|
|
2430
|
-
const { label } = CONNECTOR_TYPES[firewallRef];
|
|
2431
|
-
const config = getConnectorFirewall(firewallRef);
|
|
2432
|
-
const permissions = findMatchingPermissions(
|
|
2433
|
-
opts.method,
|
|
2434
|
-
opts.path,
|
|
2435
|
-
config
|
|
2459
|
+
action,
|
|
2460
|
+
opts.reason
|
|
2436
2461
|
);
|
|
2437
|
-
console.log(
|
|
2438
|
-
`The ${label} firewall blocked ${opts.method} ${opts.path}.`
|
|
2439
|
-
);
|
|
2440
|
-
if (permissions.length === 0) {
|
|
2441
|
-
console.log("No named permission was found covering this request.");
|
|
2442
|
-
return;
|
|
2443
|
-
}
|
|
2444
|
-
const permission = permissions[0];
|
|
2445
|
-
console.log(`This is covered by the "${permission}" permission.`);
|
|
2446
|
-
await outputPermissionChangeMessage(firewallRef, permission, "enable");
|
|
2447
2462
|
}
|
|
2448
2463
|
)
|
|
2449
2464
|
);
|
|
@@ -4720,8 +4735,19 @@ async function captureScreenshot() {
|
|
|
4720
4735
|
const tmpPath = join3(tmpdir(), `vm0-screenshot-${randomUUID()}.jpg`);
|
|
4721
4736
|
try {
|
|
4722
4737
|
await execFileAsync("screencapture", ["-x", "-t", "jpg", tmpPath]);
|
|
4723
|
-
const buffer = await readFile(tmpPath);
|
|
4724
4738
|
const info = await getScreenInfo();
|
|
4739
|
+
if (info.scaleFactor > 1) {
|
|
4740
|
+
await execFileAsync("sips", [
|
|
4741
|
+
"-z",
|
|
4742
|
+
String(info.height),
|
|
4743
|
+
String(info.width),
|
|
4744
|
+
"-s",
|
|
4745
|
+
"formatOptions",
|
|
4746
|
+
"80",
|
|
4747
|
+
tmpPath
|
|
4748
|
+
]);
|
|
4749
|
+
}
|
|
4750
|
+
const buffer = await readFile(tmpPath);
|
|
4725
4751
|
return {
|
|
4726
4752
|
image: buffer.toString("base64"),
|
|
4727
4753
|
width: info.width,
|
|
@@ -4746,12 +4772,24 @@ async function captureRegionScreenshot(region) {
|
|
|
4746
4772
|
regionArg,
|
|
4747
4773
|
tmpPath
|
|
4748
4774
|
]);
|
|
4775
|
+
const info = await getScreenInfo();
|
|
4776
|
+
if (info.scaleFactor > 1) {
|
|
4777
|
+
await execFileAsync("sips", [
|
|
4778
|
+
"-z",
|
|
4779
|
+
String(region.height),
|
|
4780
|
+
String(region.width),
|
|
4781
|
+
"-s",
|
|
4782
|
+
"formatOptions",
|
|
4783
|
+
"80",
|
|
4784
|
+
tmpPath
|
|
4785
|
+
]);
|
|
4786
|
+
}
|
|
4749
4787
|
const buffer = await readFile(tmpPath);
|
|
4750
4788
|
return {
|
|
4751
4789
|
image: buffer.toString("base64"),
|
|
4752
4790
|
width: region.width,
|
|
4753
4791
|
height: region.height,
|
|
4754
|
-
scaleFactor:
|
|
4792
|
+
scaleFactor: info.scaleFactor,
|
|
4755
4793
|
format: "jpg"
|
|
4756
4794
|
};
|
|
4757
4795
|
} finally {
|
|
@@ -4771,14 +4809,30 @@ async function getScreenInfo() {
|
|
|
4771
4809
|
for (const screen of screens) {
|
|
4772
4810
|
const pixelStr = screen._spdisplays_pixels;
|
|
4773
4811
|
if (pixelStr) {
|
|
4774
|
-
const
|
|
4775
|
-
if (
|
|
4776
|
-
const
|
|
4777
|
-
const
|
|
4812
|
+
const pixelMatch = pixelStr.match(/(\d+)\s*x\s*(\d+)/);
|
|
4813
|
+
if (pixelMatch?.[1] && pixelMatch[2]) {
|
|
4814
|
+
const physicalWidth = parseInt(pixelMatch[1], 10);
|
|
4815
|
+
const physicalHeight = parseInt(pixelMatch[2], 10);
|
|
4778
4816
|
const resStr = screen._spdisplays_resolution ?? screen.spdisplays_resolution ?? "";
|
|
4779
|
-
const
|
|
4780
|
-
|
|
4781
|
-
|
|
4817
|
+
const resMatch = resStr.match(/(\d+)\s*x\s*(\d+)/);
|
|
4818
|
+
let scaleFactor;
|
|
4819
|
+
let logicalWidth;
|
|
4820
|
+
let logicalHeight;
|
|
4821
|
+
if (resMatch?.[1] && resMatch[2]) {
|
|
4822
|
+
logicalWidth = parseInt(resMatch[1], 10);
|
|
4823
|
+
logicalHeight = parseInt(resMatch[2], 10);
|
|
4824
|
+
scaleFactor = Math.round(physicalWidth / logicalWidth);
|
|
4825
|
+
} else {
|
|
4826
|
+
const isRetina = /retina/i.test(resStr);
|
|
4827
|
+
scaleFactor = isRetina ? 2 : 1;
|
|
4828
|
+
logicalWidth = Math.floor(physicalWidth / scaleFactor);
|
|
4829
|
+
logicalHeight = Math.floor(physicalHeight / scaleFactor);
|
|
4830
|
+
}
|
|
4831
|
+
return {
|
|
4832
|
+
width: logicalWidth,
|
|
4833
|
+
height: logicalHeight,
|
|
4834
|
+
scaleFactor
|
|
4835
|
+
};
|
|
4782
4836
|
}
|
|
4783
4837
|
}
|
|
4784
4838
|
}
|
|
@@ -4893,17 +4947,20 @@ function parseKeyCombo(keys) {
|
|
|
4893
4947
|
}
|
|
4894
4948
|
return { modifiers, mainKey };
|
|
4895
4949
|
}
|
|
4950
|
+
function keyAction(key) {
|
|
4951
|
+
return VALID_SPECIAL_KEYS.has(key) ? `kp:${key}` : `t:${key}`;
|
|
4952
|
+
}
|
|
4896
4953
|
async function pressKey(keys) {
|
|
4897
4954
|
const { modifiers, mainKey } = parseKeyCombo(keys);
|
|
4898
4955
|
if (modifiers.length === 0) {
|
|
4899
|
-
await execFileAsync2("cliclick", [
|
|
4956
|
+
await execFileAsync2("cliclick", [keyAction(mainKey)]);
|
|
4900
4957
|
return;
|
|
4901
4958
|
}
|
|
4902
4959
|
const args = [];
|
|
4903
4960
|
for (const mod of modifiers) {
|
|
4904
4961
|
args.push(`kd:${mod}`);
|
|
4905
4962
|
}
|
|
4906
|
-
args.push(
|
|
4963
|
+
args.push(keyAction(mainKey));
|
|
4907
4964
|
for (let i = modifiers.length - 1; i >= 0; i--) {
|
|
4908
4965
|
args.push(`ku:${modifiers[i]}`);
|
|
4909
4966
|
}
|
|
@@ -5086,12 +5143,10 @@ async function handleMouseRequest(req, res) {
|
|
|
5086
5143
|
return;
|
|
5087
5144
|
}
|
|
5088
5145
|
const info = await getScreenInfo();
|
|
5089
|
-
|
|
5090
|
-
const maxY = Math.floor(info.height / info.scaleFactor);
|
|
5091
|
-
if (x < 0 || x >= maxX || y < 0 || y >= maxY) {
|
|
5146
|
+
if (x < 0 || x >= info.width || y < 0 || y >= info.height) {
|
|
5092
5147
|
res.writeHead(400, { "Content-Type": "text/plain" });
|
|
5093
5148
|
res.end(
|
|
5094
|
-
`Coordinates out of bounds. Screen size: ${
|
|
5149
|
+
`Coordinates out of bounds. Screen size: ${info.width}x${info.height} (points)`
|
|
5095
5150
|
);
|
|
5096
5151
|
return;
|
|
5097
5152
|
}
|
|
@@ -5665,6 +5720,23 @@ var clientCommand = new Command76().name("client").description("Interact with re
|
|
|
5665
5720
|
var zeroComputerUseCommand = new Command76().name("computer-use").description("Remote desktop control for cloud agents").addCommand(hostCommand).addCommand(clientCommand).addHelpText(
|
|
5666
5721
|
"after",
|
|
5667
5722
|
`
|
|
5723
|
+
Coordinate System:
|
|
5724
|
+
All coordinate parameters use macOS logical coordinates (points), not physical
|
|
5725
|
+
pixels. On Retina displays (scaleFactor: 2), a 2880\xD71800 physical screen has
|
|
5726
|
+
logical dimensions of 1440\xD7900. Use the "info" command to check your screen's
|
|
5727
|
+
logical dimensions and scale factor.
|
|
5728
|
+
|
|
5729
|
+
The "screenshot" command returns an image at logical resolution. The "zoom"
|
|
5730
|
+
command accepts a region in logical coordinates but returns an image at physical
|
|
5731
|
+
resolution (logical size \xD7 scaleFactor), providing higher detail for precise
|
|
5732
|
+
element location.
|
|
5733
|
+
|
|
5734
|
+
Recommended AI agent workflow:
|
|
5735
|
+
1. screenshot \u2014 get a screen overview at logical resolution
|
|
5736
|
+
2. zoom --x --y ... \u2014 zoom into a region of interest for pixel-level detail
|
|
5737
|
+
3. Calculate the logical coordinates of the target element
|
|
5738
|
+
4. Execute click/type operations using those logical coordinates
|
|
5739
|
+
|
|
5668
5740
|
Examples:
|
|
5669
5741
|
Start the host daemon (on macOS): zero computer-use host start
|
|
5670
5742
|
Stop the host daemon: zero computer-use host stop
|
|
@@ -5738,7 +5810,7 @@ function registerZeroCommands(prog, commands) {
|
|
|
5738
5810
|
var program = new Command77();
|
|
5739
5811
|
program.name("zero").description(
|
|
5740
5812
|
"Zero CLI \u2014 interact with the zero platform from inside the sandbox"
|
|
5741
|
-
).version("9.
|
|
5813
|
+
).version("9.104.1").addHelpText(
|
|
5742
5814
|
"after",
|
|
5743
5815
|
`
|
|
5744
5816
|
Examples:
|