@vm0/cli 9.119.2 → 9.120.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-PS4P6JB6.js → chunk-CVXG5BRK.js} +420 -361
- package/{chunk-PS4P6JB6.js.map → chunk-CVXG5BRK.js.map} +1 -1
- package/index.js +153 -292
- package/index.js.map +1 -1
- package/package.json +1 -1
- package/zero.js +236 -468
- package/zero.js.map +1 -1
package/zero.js
CHANGED
|
@@ -18,15 +18,11 @@ import {
|
|
|
18
18
|
createPhoneCall,
|
|
19
19
|
createSkill,
|
|
20
20
|
createZeroAgent,
|
|
21
|
-
createZeroComputerConnector,
|
|
22
|
-
createZeroConnectorSession,
|
|
23
21
|
createZeroRun,
|
|
24
22
|
decodeCliTokenPayload,
|
|
25
23
|
decodeZeroTokenPayload,
|
|
26
24
|
deleteSkill,
|
|
27
25
|
deleteZeroAgent,
|
|
28
|
-
deleteZeroComputerConnector,
|
|
29
|
-
deleteZeroConnector,
|
|
30
26
|
deleteZeroOrg,
|
|
31
27
|
deleteZeroOrgModelProvider,
|
|
32
28
|
deleteZeroOrgSecret,
|
|
@@ -44,7 +40,6 @@ import {
|
|
|
44
40
|
getActiveOrg,
|
|
45
41
|
getApiUrl,
|
|
46
42
|
getAuthMethodsForType,
|
|
47
|
-
getBaseUrl,
|
|
48
43
|
getComputerUseHost,
|
|
49
44
|
getConnectorDerivedNames,
|
|
50
45
|
getConnectorEnvironmentMapping,
|
|
@@ -65,7 +60,6 @@ import {
|
|
|
65
60
|
getZeroAgentInstructions,
|
|
66
61
|
getZeroAgentUserConnectors,
|
|
67
62
|
getZeroConnector,
|
|
68
|
-
getZeroConnectorSession,
|
|
69
63
|
getZeroOrg,
|
|
70
64
|
getZeroOrgMembers,
|
|
71
65
|
getZeroRun,
|
|
@@ -110,6 +104,7 @@ import {
|
|
|
110
104
|
resolveFirewallPolicies,
|
|
111
105
|
resolveZeroScheduleByAgent,
|
|
112
106
|
saveConfig,
|
|
107
|
+
searchConnectors,
|
|
113
108
|
searchZeroLogs,
|
|
114
109
|
sendChatMessage,
|
|
115
110
|
sendSlackMessage,
|
|
@@ -131,7 +126,7 @@ import {
|
|
|
131
126
|
upsertZeroOrgModelProvider,
|
|
132
127
|
withErrorHandler,
|
|
133
128
|
zeroAgentCustomSkillNameSchema
|
|
134
|
-
} from "./chunk-
|
|
129
|
+
} from "./chunk-CVXG5BRK.js";
|
|
135
130
|
import {
|
|
136
131
|
__toESM,
|
|
137
132
|
init_esm_shims
|
|
@@ -1564,388 +1559,63 @@ Notes:
|
|
|
1564
1559
|
// src/commands/zero/connector/index.ts
|
|
1565
1560
|
init_esm_shims();
|
|
1566
1561
|
|
|
1567
|
-
// src/commands/zero/connector/
|
|
1562
|
+
// src/commands/zero/connector/list.ts
|
|
1568
1563
|
init_esm_shims();
|
|
1569
1564
|
|
|
1570
|
-
// src/
|
|
1565
|
+
// src/commands/zero/connector/agent-context.ts
|
|
1571
1566
|
init_esm_shims();
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
} catch (cause) {
|
|
1585
|
-
throw new Error(
|
|
1586
|
-
"Failed to load ngrok tunnel module. This may be caused by a system library (GLIBC) incompatibility. See: https://github.com/vm0-ai/vm0/issues/6825",
|
|
1587
|
-
{ cause }
|
|
1588
|
-
);
|
|
1589
|
-
}
|
|
1590
|
-
}
|
|
1591
|
-
async function startNgrokTunnels(ngrokToken, endpointPrefix, webdavPort, cdpPort) {
|
|
1592
|
-
const ngrok = await loadNgrok();
|
|
1593
|
-
await ngrok.forward({
|
|
1594
|
-
addr: `localhost:${webdavPort}`,
|
|
1595
|
-
authtoken: ngrokToken,
|
|
1596
|
-
domain: `webdav.${endpointPrefix}.internal`
|
|
1597
|
-
});
|
|
1598
|
-
await ngrok.forward({
|
|
1599
|
-
addr: `localhost:${cdpPort}`,
|
|
1600
|
-
authtoken: ngrokToken,
|
|
1601
|
-
domain: `chrome.${endpointPrefix}.internal`
|
|
1602
|
-
});
|
|
1603
|
-
}
|
|
1604
|
-
async function stopNgrokTunnels() {
|
|
1605
|
-
const ngrok = await loadNgrok();
|
|
1606
|
-
await ngrok.kill();
|
|
1567
|
+
async function resolveAgentContext(flagAgentId) {
|
|
1568
|
+
const agentId = flagAgentId ?? process.env.ZERO_AGENT_ID;
|
|
1569
|
+
if (!agentId) return null;
|
|
1570
|
+
const [agent, enabledTypes] = await Promise.all([
|
|
1571
|
+
getZeroAgent(agentId),
|
|
1572
|
+
getZeroAgentUserConnectors(agentId)
|
|
1573
|
+
]);
|
|
1574
|
+
return {
|
|
1575
|
+
agentId: agent.agentId,
|
|
1576
|
+
displayName: agent.displayName ?? agent.agentId,
|
|
1577
|
+
authorizedTypes: new Set(enabledTypes)
|
|
1578
|
+
};
|
|
1607
1579
|
}
|
|
1608
1580
|
|
|
1609
|
-
// src/
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
"/Applications/Chromium.app/Contents/MacOS/Chromium",
|
|
1615
|
-
// Linux / PATH-based
|
|
1616
|
-
"google-chrome",
|
|
1617
|
-
"google-chrome-stable",
|
|
1618
|
-
"chromium-browser",
|
|
1619
|
-
"chromium",
|
|
1620
|
-
"chrome"
|
|
1621
|
-
];
|
|
1622
|
-
async function getRandomPort() {
|
|
1623
|
-
return new Promise((resolve, reject) => {
|
|
1624
|
-
const server = createServer();
|
|
1625
|
-
server.listen(0, "127.0.0.1", () => {
|
|
1626
|
-
const { port } = server.address();
|
|
1627
|
-
server.close(() => {
|
|
1628
|
-
return resolve(port);
|
|
1629
|
-
});
|
|
1630
|
-
});
|
|
1631
|
-
server.on("error", reject);
|
|
1632
|
-
});
|
|
1633
|
-
}
|
|
1634
|
-
async function findBinary(...candidates) {
|
|
1635
|
-
for (const candidate of candidates) {
|
|
1636
|
-
if (candidate.startsWith("/")) {
|
|
1637
|
-
try {
|
|
1638
|
-
await access(candidate, constants.X_OK);
|
|
1639
|
-
return candidate;
|
|
1640
|
-
} catch {
|
|
1641
|
-
}
|
|
1642
|
-
} else {
|
|
1643
|
-
const found = await new Promise((resolve) => {
|
|
1644
|
-
const child = spawn("which", [candidate]);
|
|
1645
|
-
child.on("close", (code) => {
|
|
1646
|
-
return resolve(code === 0);
|
|
1647
|
-
});
|
|
1648
|
-
});
|
|
1649
|
-
if (found) return candidate;
|
|
1650
|
-
}
|
|
1651
|
-
}
|
|
1652
|
-
return null;
|
|
1653
|
-
}
|
|
1654
|
-
async function checkComputerDependencies() {
|
|
1655
|
-
const wsgidavBinary = await findBinary("wsgidav");
|
|
1656
|
-
if (!wsgidavBinary) {
|
|
1657
|
-
throw new Error(
|
|
1658
|
-
"wsgidav not found\n\nInstall with: pip install wsgidav[cheroot]"
|
|
1659
|
-
);
|
|
1660
|
-
}
|
|
1661
|
-
const chromeBinary = await findBinary(...CHROME_CANDIDATES);
|
|
1662
|
-
if (!chromeBinary) {
|
|
1663
|
-
throw new Error("Chrome not found\n\nInstall Google Chrome or Chromium");
|
|
1664
|
-
}
|
|
1581
|
+
// src/commands/zero/connector/list.ts
|
|
1582
|
+
function renderIdentity(connector) {
|
|
1583
|
+
if (connector.externalUsername) return `@${connector.externalUsername}`;
|
|
1584
|
+
if (connector.externalEmail) return connector.externalEmail;
|
|
1585
|
+
return "-";
|
|
1665
1586
|
}
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
const
|
|
1669
|
-
if (
|
|
1670
|
-
|
|
1671
|
-
"wsgidav not found\n\nInstall with: pip install wsgidav[cheroot]"
|
|
1672
|
-
);
|
|
1587
|
+
function renderConnectedAsCell(connector) {
|
|
1588
|
+
if (!connector) return source_default.dim("(not connected)");
|
|
1589
|
+
const identity = renderIdentity(connector);
|
|
1590
|
+
if (connector.needsReconnect) {
|
|
1591
|
+
return source_default.yellow(`${identity} (reconnect needed)`);
|
|
1673
1592
|
}
|
|
1674
|
-
const
|
|
1675
|
-
if (
|
|
1676
|
-
|
|
1677
|
-
}
|
|
1678
|
-
const webdavPort = await getRandomPort();
|
|
1679
|
-
const cdpPort = await getRandomPort();
|
|
1680
|
-
const downloadsPath = join(homedir(), "Downloads");
|
|
1681
|
-
const wsgidav = spawn(
|
|
1682
|
-
wsgidavBinary,
|
|
1683
|
-
[
|
|
1684
|
-
"--host=127.0.0.1",
|
|
1685
|
-
`--port=${webdavPort}`,
|
|
1686
|
-
`--root=${downloadsPath}`,
|
|
1687
|
-
"--auth=anonymous",
|
|
1688
|
-
"--no-config"
|
|
1689
|
-
],
|
|
1690
|
-
{ stdio: ["ignore", "pipe", "pipe"] }
|
|
1691
|
-
);
|
|
1692
|
-
wsgidav.stdout?.on("data", (data) => {
|
|
1693
|
-
return process.stdout.write(data);
|
|
1694
|
-
});
|
|
1695
|
-
wsgidav.stderr?.on("data", (data) => {
|
|
1696
|
-
return process.stderr.write(data);
|
|
1697
|
-
});
|
|
1698
|
-
console.log(source_default.green("\u2713 WebDAV server started"));
|
|
1699
|
-
const chrome = spawn(
|
|
1700
|
-
chromeBinary,
|
|
1701
|
-
[
|
|
1702
|
-
`--remote-debugging-port=${cdpPort}`,
|
|
1703
|
-
"--remote-debugging-address=127.0.0.1",
|
|
1704
|
-
"--headless=new",
|
|
1705
|
-
"--no-sandbox",
|
|
1706
|
-
"--disable-gpu"
|
|
1707
|
-
],
|
|
1708
|
-
{ stdio: ["ignore", "pipe", "pipe"] }
|
|
1709
|
-
);
|
|
1710
|
-
chrome.stdout?.on("data", (data) => {
|
|
1711
|
-
return process.stdout.write(data);
|
|
1712
|
-
});
|
|
1713
|
-
chrome.stderr?.on("data", (data) => {
|
|
1714
|
-
return process.stderr.write(data);
|
|
1715
|
-
});
|
|
1716
|
-
console.log(source_default.green("\u2713 Chrome started"));
|
|
1717
|
-
try {
|
|
1718
|
-
await startNgrokTunnels(
|
|
1719
|
-
credentials.ngrokToken,
|
|
1720
|
-
credentials.endpointPrefix,
|
|
1721
|
-
webdavPort,
|
|
1722
|
-
cdpPort
|
|
1723
|
-
);
|
|
1724
|
-
console.log(
|
|
1725
|
-
source_default.green(
|
|
1726
|
-
`\u2713 ngrok tunnels: webdav.${credentials.domain}, chrome.${credentials.domain}`
|
|
1727
|
-
)
|
|
1728
|
-
);
|
|
1729
|
-
console.log();
|
|
1730
|
-
console.log(source_default.green("\u2713 Computer connector active"));
|
|
1731
|
-
console.log(` WebDAV: ~/Downloads \u2192 webdav.${credentials.domain}`);
|
|
1732
|
-
console.log(
|
|
1733
|
-
` Chrome CDP: port ${cdpPort} \u2192 chrome.${credentials.domain}`
|
|
1734
|
-
);
|
|
1735
|
-
console.log();
|
|
1736
|
-
console.log(source_default.dim("Press ^C twice to disconnect"));
|
|
1737
|
-
console.log();
|
|
1738
|
-
let sigintCount = 0;
|
|
1739
|
-
await new Promise((resolve) => {
|
|
1740
|
-
const keepAlive = setInterval(() => {
|
|
1741
|
-
}, 6e4);
|
|
1742
|
-
const done = () => {
|
|
1743
|
-
clearInterval(keepAlive);
|
|
1744
|
-
process.removeListener("SIGINT", onSigint);
|
|
1745
|
-
resolve();
|
|
1746
|
-
};
|
|
1747
|
-
const onSigint = () => {
|
|
1748
|
-
sigintCount++;
|
|
1749
|
-
if (sigintCount === 1) {
|
|
1750
|
-
console.log(source_default.dim("\nPress ^C again to disconnect and exit..."));
|
|
1751
|
-
} else {
|
|
1752
|
-
done();
|
|
1753
|
-
}
|
|
1754
|
-
};
|
|
1755
|
-
process.on("SIGINT", onSigint);
|
|
1756
|
-
process.once("SIGTERM", done);
|
|
1757
|
-
});
|
|
1758
|
-
} finally {
|
|
1759
|
-
console.log();
|
|
1760
|
-
console.log(source_default.cyan("Stopping services..."));
|
|
1761
|
-
wsgidav.kill("SIGTERM");
|
|
1762
|
-
chrome.kill("SIGTERM");
|
|
1763
|
-
await stopNgrokTunnels();
|
|
1764
|
-
console.log(source_default.green("\u2713 Services stopped"));
|
|
1593
|
+
const scopeMismatch = connector.authMethod === "oauth" && !hasRequiredScopes(connector.type, connector.oauthScopes);
|
|
1594
|
+
if (scopeMismatch) {
|
|
1595
|
+
return source_default.yellow(`${identity} (permissions update available)`);
|
|
1765
1596
|
}
|
|
1597
|
+
return identity;
|
|
1766
1598
|
}
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
return new Promise((resolve) => {
|
|
1771
|
-
return setTimeout(resolve, ms);
|
|
1772
|
-
});
|
|
1599
|
+
var ANSI_PATTERN = /\u001b\[[0-9;]*m/g;
|
|
1600
|
+
function stripAnsi(s) {
|
|
1601
|
+
return s.replace(ANSI_PATTERN, "");
|
|
1773
1602
|
}
|
|
1774
|
-
function
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
}).replace(/\*\*([^*]+)\*\*/g, (_m, content) => {
|
|
1778
|
-
return source_default.bold(content);
|
|
1779
|
-
}).replace(/^> (.+)$/gm, (_m, content) => {
|
|
1780
|
-
return source_default.yellow(` ${content}`);
|
|
1781
|
-
});
|
|
1603
|
+
function padEndAnsi(s, width) {
|
|
1604
|
+
const visible = stripAnsi(s).length;
|
|
1605
|
+
return s + " ".repeat(Math.max(0, width - visible));
|
|
1782
1606
|
}
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
);
|
|
1790
|
-
}
|
|
1791
|
-
const secretEntries = Object.entries(apiTokenConfig.secrets);
|
|
1792
|
-
const inputSecrets = {};
|
|
1793
|
-
if (tokenValue && secretEntries.length === 1) {
|
|
1794
|
-
const [secretName] = secretEntries[0];
|
|
1795
|
-
inputSecrets[secretName] = tokenValue;
|
|
1796
|
-
} else {
|
|
1797
|
-
if (apiTokenConfig.helpText) {
|
|
1798
|
-
console.log();
|
|
1799
|
-
console.log(renderHelpText(apiTokenConfig.helpText));
|
|
1800
|
-
console.log();
|
|
1801
|
-
}
|
|
1802
|
-
for (const [secretName, secretConfig] of secretEntries) {
|
|
1803
|
-
if (!secretConfig.required) continue;
|
|
1804
|
-
const value = await promptPassword(
|
|
1805
|
-
`${secretConfig.label}${secretConfig.placeholder ? source_default.dim(` (${secretConfig.placeholder})`) : ""}:`
|
|
1806
|
-
);
|
|
1807
|
-
if (!value) {
|
|
1808
|
-
console.log(source_default.dim("Cancelled"));
|
|
1809
|
-
return;
|
|
1810
|
-
}
|
|
1811
|
-
inputSecrets[secretName] = value;
|
|
1812
|
-
}
|
|
1813
|
-
}
|
|
1814
|
-
for (const [name, value] of Object.entries(inputSecrets)) {
|
|
1815
|
-
await setZeroSecret({
|
|
1816
|
-
name,
|
|
1817
|
-
value,
|
|
1818
|
-
description: `API token for ${config.label} connector`
|
|
1819
|
-
});
|
|
1820
|
-
}
|
|
1821
|
-
console.log(source_default.green(`
|
|
1822
|
-
\u2713 Connector "${connectorType}" connected`));
|
|
1823
|
-
}
|
|
1824
|
-
async function connectComputer() {
|
|
1825
|
-
await checkComputerDependencies();
|
|
1826
|
-
console.log(source_default.cyan("Setting up computer connector..."));
|
|
1827
|
-
const credentials = await createZeroComputerConnector();
|
|
1828
|
-
await startComputerServices(credentials);
|
|
1829
|
-
console.log(source_default.cyan("Disconnecting computer connector..."));
|
|
1830
|
-
await deleteZeroComputerConnector();
|
|
1831
|
-
console.log(source_default.green("\u2713 Disconnected computer"));
|
|
1832
|
-
}
|
|
1833
|
-
async function resolveAuthMethod(connectorType, tokenFlag) {
|
|
1834
|
-
const config = CONNECTOR_TYPES[connectorType];
|
|
1835
|
-
const oauthFlag = CONNECTOR_TYPES[connectorType].featureFlag;
|
|
1836
|
-
const orgId = await getActiveOrg();
|
|
1837
|
-
const oauthAvailable = "oauth" in config.authMethods && (!oauthFlag || isFeatureEnabled(oauthFlag, { orgId }));
|
|
1838
|
-
const apiTokenAvailable = "api-token" in config.authMethods;
|
|
1839
|
-
if (tokenFlag) {
|
|
1840
|
-
if (!apiTokenAvailable) {
|
|
1841
|
-
throw new Error(
|
|
1842
|
-
`${config.label} does not support API token authentication`
|
|
1843
|
-
);
|
|
1844
|
-
}
|
|
1845
|
-
return "api-token";
|
|
1846
|
-
}
|
|
1847
|
-
if (oauthAvailable && apiTokenAvailable) {
|
|
1848
|
-
const selected = await promptSelect(
|
|
1849
|
-
`How would you like to connect ${config.label}?`,
|
|
1850
|
-
[
|
|
1851
|
-
{ title: "OAuth (Sign in with browser)", value: "oauth" },
|
|
1852
|
-
{
|
|
1853
|
-
title: `API Token (${config.authMethods["api-token"].label})`,
|
|
1854
|
-
value: "api-token"
|
|
1855
|
-
}
|
|
1856
|
-
]
|
|
1857
|
-
);
|
|
1858
|
-
if (!selected) {
|
|
1859
|
-
console.log(source_default.dim("Cancelled"));
|
|
1860
|
-
return null;
|
|
1861
|
-
}
|
|
1862
|
-
return selected;
|
|
1863
|
-
}
|
|
1864
|
-
if (apiTokenAvailable) return "api-token";
|
|
1865
|
-
if (oauthAvailable) return "oauth";
|
|
1866
|
-
throw new Error(
|
|
1867
|
-
`${config.label} has no available auth methods. OAuth may not be enabled yet.`
|
|
1868
|
-
);
|
|
1869
|
-
}
|
|
1870
|
-
async function connectViaOAuth(connectorType) {
|
|
1871
|
-
console.log(`Connecting ${source_default.cyan(connectorType)}...`);
|
|
1872
|
-
const session = await createZeroConnectorSession(connectorType);
|
|
1873
|
-
const apiUrl = await getBaseUrl();
|
|
1874
|
-
const verificationUrl = `${apiUrl}${session.verificationUrl}`;
|
|
1875
|
-
console.log(source_default.green("\nSession created"));
|
|
1876
|
-
console.log(source_default.cyan(`
|
|
1877
|
-
To connect, visit: ${verificationUrl}`));
|
|
1878
|
-
console.log(
|
|
1879
|
-
`
|
|
1880
|
-
The session expires in ${Math.floor(session.expiresIn / 60)} minutes.`
|
|
1881
|
-
);
|
|
1882
|
-
console.log("\nWaiting for authorization...");
|
|
1883
|
-
const startTime = Date.now();
|
|
1884
|
-
const maxWaitTime = session.expiresIn * 1e3;
|
|
1885
|
-
const pollInterval = (session.interval || 5) * 1e3;
|
|
1886
|
-
let isFirstPoll = true;
|
|
1887
|
-
while (Date.now() - startTime < maxWaitTime) {
|
|
1888
|
-
if (!isFirstPoll) {
|
|
1889
|
-
await delay(pollInterval);
|
|
1890
|
-
}
|
|
1891
|
-
isFirstPoll = false;
|
|
1892
|
-
const status = await getZeroConnectorSession(connectorType, session.id);
|
|
1893
|
-
switch (status.status) {
|
|
1894
|
-
case "complete":
|
|
1895
|
-
console.log(
|
|
1896
|
-
source_default.green(`
|
|
1897
|
-
|
|
1898
|
-
\u2713 Connector "${connectorType}" connected`)
|
|
1899
|
-
);
|
|
1900
|
-
return;
|
|
1901
|
-
case "expired":
|
|
1902
|
-
throw new Error("Session expired, please try again");
|
|
1903
|
-
case "error":
|
|
1904
|
-
throw new Error(
|
|
1905
|
-
`Connection failed: ${status.errorMessage || "Unknown error"}`
|
|
1906
|
-
);
|
|
1907
|
-
case "pending":
|
|
1908
|
-
process.stdout.write(source_default.dim("."));
|
|
1909
|
-
break;
|
|
1910
|
-
}
|
|
1911
|
-
}
|
|
1912
|
-
throw new Error("Session timed out, please try again");
|
|
1913
|
-
}
|
|
1914
|
-
var connectCommand = new Command().name("connect").description("Connect a third-party service (e.g., GitHub)").argument("<type>", "Connector type (e.g., github)").option("--token <value>", "API token value (skip interactive prompt)").action(
|
|
1915
|
-
withErrorHandler(async (type, options) => {
|
|
1916
|
-
const parseResult = connectorTypeSchema.safeParse(type);
|
|
1917
|
-
if (!parseResult.success) {
|
|
1918
|
-
const available = Object.keys(CONNECTOR_TYPES).join(", ");
|
|
1919
|
-
throw new Error(`Unknown connector type: ${type}`, {
|
|
1920
|
-
cause: new Error(`Available connectors: ${available}`)
|
|
1921
|
-
});
|
|
1922
|
-
}
|
|
1923
|
-
const connectorType = parseResult.data;
|
|
1924
|
-
if (connectorType === "computer") {
|
|
1925
|
-
await connectComputer();
|
|
1926
|
-
return;
|
|
1927
|
-
}
|
|
1928
|
-
const authMethod = await resolveAuthMethod(connectorType, options.token);
|
|
1929
|
-
if (!authMethod) return;
|
|
1930
|
-
if (authMethod === "api-token") {
|
|
1931
|
-
await connectViaApiToken(connectorType, options.token);
|
|
1932
|
-
return;
|
|
1933
|
-
}
|
|
1934
|
-
await connectViaOAuth(connectorType);
|
|
1935
|
-
})
|
|
1936
|
-
);
|
|
1937
|
-
|
|
1938
|
-
// src/commands/zero/connector/list.ts
|
|
1939
|
-
init_esm_shims();
|
|
1940
|
-
var listCommand6 = new Command().name("list").alias("ls").description("List all connectors and their status").action(
|
|
1941
|
-
withErrorHandler(async () => {
|
|
1942
|
-
const result = await listZeroConnectors();
|
|
1607
|
+
var listCommand6 = new Command().name("list").alias("ls").description("List all connectors and their status").option("--agent <id>", "Show per-agent authorization column").action(
|
|
1608
|
+
withErrorHandler(async (options) => {
|
|
1609
|
+
const [{ connectors }, orgId, agentCtx] = await Promise.all([
|
|
1610
|
+
listZeroConnectors(),
|
|
1611
|
+
getActiveOrg(),
|
|
1612
|
+
resolveAgentContext(options.agent)
|
|
1613
|
+
]);
|
|
1943
1614
|
const connectedMap = new Map(
|
|
1944
|
-
|
|
1615
|
+
connectors.map((c) => {
|
|
1945
1616
|
return [c.type, c];
|
|
1946
1617
|
})
|
|
1947
1618
|
);
|
|
1948
|
-
const orgId = await getActiveOrg();
|
|
1949
1619
|
const allTypesRaw = Object.keys(CONNECTOR_TYPES);
|
|
1950
1620
|
const allTypes = [];
|
|
1951
1621
|
for (const type of allTypesRaw) {
|
|
@@ -1962,28 +1632,133 @@ var listCommand6 = new Command().name("list").alias("ls").description("List all
|
|
|
1962
1632
|
return t.length;
|
|
1963
1633
|
})
|
|
1964
1634
|
);
|
|
1965
|
-
const
|
|
1966
|
-
const
|
|
1967
|
-
|
|
1635
|
+
const connectedAsHeader = "CONNECTED AS";
|
|
1636
|
+
const connectedCells = allTypes.map((type) => {
|
|
1637
|
+
return renderConnectedAsCell(connectedMap.get(type));
|
|
1638
|
+
});
|
|
1639
|
+
const connectedAsWidth = Math.max(
|
|
1640
|
+
connectedAsHeader.length,
|
|
1641
|
+
...connectedCells.map((c) => {
|
|
1642
|
+
return stripAnsi(c).length;
|
|
1643
|
+
})
|
|
1644
|
+
);
|
|
1645
|
+
const authorizedHeader = agentCtx ? `AUTHORIZED FOR ${agentCtx.displayName}` : null;
|
|
1646
|
+
const headerParts = [
|
|
1968
1647
|
"TYPE".padEnd(typeWidth),
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
console.log(source_default.dim(
|
|
1973
|
-
for (
|
|
1974
|
-
const
|
|
1975
|
-
const
|
|
1976
|
-
const
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1648
|
+
connectedAsHeader.padEnd(connectedAsWidth)
|
|
1649
|
+
];
|
|
1650
|
+
if (authorizedHeader) headerParts.push(authorizedHeader);
|
|
1651
|
+
console.log(source_default.dim(headerParts.join(" ")));
|
|
1652
|
+
for (let i = 0; i < allTypes.length; i++) {
|
|
1653
|
+
const type = allTypes[i];
|
|
1654
|
+
const connectedCell = padEndAnsi(connectedCells[i], connectedAsWidth);
|
|
1655
|
+
const parts = [type.padEnd(typeWidth), connectedCell];
|
|
1656
|
+
if (agentCtx) {
|
|
1657
|
+
parts.push(
|
|
1658
|
+
agentCtx.authorizedTypes.has(type) ? source_default.green("\u2713") : source_default.dim("-")
|
|
1659
|
+
);
|
|
1660
|
+
}
|
|
1661
|
+
console.log(parts.join(" "));
|
|
1980
1662
|
}
|
|
1981
|
-
console.log();
|
|
1982
|
-
console.log(source_default.dim("To connect a service:"));
|
|
1983
|
-
console.log(source_default.dim(" zero connector connect <type>"));
|
|
1984
1663
|
})
|
|
1985
1664
|
);
|
|
1986
1665
|
|
|
1666
|
+
// src/commands/zero/connector/search.ts
|
|
1667
|
+
init_esm_shims();
|
|
1668
|
+
var DEFAULT_LIMIT = 5;
|
|
1669
|
+
var EXACT_MATCH_THRESHOLD = 80;
|
|
1670
|
+
var ANSI_PATTERN2 = /\u001b\[[0-9;]*m/g;
|
|
1671
|
+
function stripAnsi2(s) {
|
|
1672
|
+
return s.replace(ANSI_PATTERN2, "");
|
|
1673
|
+
}
|
|
1674
|
+
function padEndAnsi2(s, width) {
|
|
1675
|
+
const visible = stripAnsi2(s).length;
|
|
1676
|
+
return s + " ".repeat(Math.max(0, width - visible));
|
|
1677
|
+
}
|
|
1678
|
+
function parseLimit(raw) {
|
|
1679
|
+
const n = Number.parseInt(raw, 10);
|
|
1680
|
+
if (!Number.isFinite(n) || n <= 0) {
|
|
1681
|
+
throw new Error(`--limit must be a positive integer, got "${raw}".`);
|
|
1682
|
+
}
|
|
1683
|
+
return n;
|
|
1684
|
+
}
|
|
1685
|
+
var searchCommand = new Command().name("search").description("Search connectors by type, label, env var, secret, or tag").argument("<keyword>", "Search keyword (case-insensitive)").option("--agent <id>", "Show per-agent authorization column").option(
|
|
1686
|
+
"--limit <n>",
|
|
1687
|
+
`Maximum number of results to display (default ${DEFAULT_LIMIT})`,
|
|
1688
|
+
parseLimit,
|
|
1689
|
+
DEFAULT_LIMIT
|
|
1690
|
+
).action(
|
|
1691
|
+
withErrorHandler(
|
|
1692
|
+
async (keyword, options) => {
|
|
1693
|
+
const trimmed = keyword.trim();
|
|
1694
|
+
if (!trimmed) {
|
|
1695
|
+
throw new Error("Keyword cannot be empty.");
|
|
1696
|
+
}
|
|
1697
|
+
const [orgId, agentCtx] = await Promise.all([
|
|
1698
|
+
getActiveOrg(),
|
|
1699
|
+
resolveAgentContext(options.agent)
|
|
1700
|
+
]);
|
|
1701
|
+
const isTypeAvailable = (type) => {
|
|
1702
|
+
const config = CONNECTOR_TYPES[type];
|
|
1703
|
+
const flag = config.featureFlag;
|
|
1704
|
+
const hasApiToken = "api-token" in config.authMethods;
|
|
1705
|
+
return !flag || isFeatureEnabled(flag, { orgId }) || hasApiToken;
|
|
1706
|
+
};
|
|
1707
|
+
const { results, total } = searchConnectors(
|
|
1708
|
+
trimmed,
|
|
1709
|
+
options.limit,
|
|
1710
|
+
isTypeAvailable
|
|
1711
|
+
);
|
|
1712
|
+
if (results.length === 0) {
|
|
1713
|
+
console.log("No matches found.");
|
|
1714
|
+
return;
|
|
1715
|
+
}
|
|
1716
|
+
const topScore = results[0].score;
|
|
1717
|
+
if (topScore < EXACT_MATCH_THRESHOLD) {
|
|
1718
|
+
console.log("No exact match. Showing closest:");
|
|
1719
|
+
}
|
|
1720
|
+
if (total > options.limit) {
|
|
1721
|
+
console.log(`Too many results (top ${options.limit} of ${total}):`);
|
|
1722
|
+
}
|
|
1723
|
+
const typeHeader = "TYPE";
|
|
1724
|
+
const labelHeader = "LABEL";
|
|
1725
|
+
const typeWidth = Math.max(
|
|
1726
|
+
typeHeader.length,
|
|
1727
|
+
...results.map((r) => {
|
|
1728
|
+
return r.type.length;
|
|
1729
|
+
})
|
|
1730
|
+
);
|
|
1731
|
+
const labelWidth = Math.max(
|
|
1732
|
+
labelHeader.length,
|
|
1733
|
+
...results.map((r) => {
|
|
1734
|
+
return CONNECTOR_TYPES[r.type].label.length;
|
|
1735
|
+
})
|
|
1736
|
+
);
|
|
1737
|
+
const headerParts = [
|
|
1738
|
+
typeHeader.padEnd(typeWidth),
|
|
1739
|
+
labelHeader.padEnd(labelWidth)
|
|
1740
|
+
];
|
|
1741
|
+
if (agentCtx) {
|
|
1742
|
+
headerParts.push(`AUTHORIZED FOR ${agentCtx.displayName}`);
|
|
1743
|
+
}
|
|
1744
|
+
console.log(source_default.dim(headerParts.join(" ")));
|
|
1745
|
+
for (const result of results) {
|
|
1746
|
+
const config = CONNECTOR_TYPES[result.type];
|
|
1747
|
+
const parts = [
|
|
1748
|
+
result.type.padEnd(typeWidth),
|
|
1749
|
+
padEndAnsi2(config.label, labelWidth)
|
|
1750
|
+
];
|
|
1751
|
+
if (agentCtx) {
|
|
1752
|
+
parts.push(
|
|
1753
|
+
agentCtx.authorizedTypes.has(result.type) ? source_default.green("\u2713") : source_default.dim("-")
|
|
1754
|
+
);
|
|
1755
|
+
}
|
|
1756
|
+
console.log(parts.join(" "));
|
|
1757
|
+
}
|
|
1758
|
+
}
|
|
1759
|
+
)
|
|
1760
|
+
);
|
|
1761
|
+
|
|
1987
1762
|
// src/commands/zero/connector/status.ts
|
|
1988
1763
|
init_esm_shims();
|
|
1989
1764
|
|
|
@@ -2101,10 +1876,30 @@ function toISODateTime(dateTimeStr) {
|
|
|
2101
1876
|
return date.toISOString();
|
|
2102
1877
|
}
|
|
2103
1878
|
|
|
1879
|
+
// src/commands/zero/doctor/platform-url.ts
|
|
1880
|
+
init_esm_shims();
|
|
1881
|
+
function toPlatformUrl(apiUrl) {
|
|
1882
|
+
const parsed = new URL(apiUrl);
|
|
1883
|
+
const parts = parsed.hostname.split(".");
|
|
1884
|
+
if (parts[0].endsWith("-www")) {
|
|
1885
|
+
parts[0] = parts[0].slice(0, -"-www".length) + "-app";
|
|
1886
|
+
} else if (parts[0] === "www" || parts[0] === "platform") {
|
|
1887
|
+
parts[0] = "app";
|
|
1888
|
+
} else if (parts[0] !== "app" && parts[0] !== "localhost") {
|
|
1889
|
+
parts.unshift("app");
|
|
1890
|
+
}
|
|
1891
|
+
parsed.hostname = parts.join(".");
|
|
1892
|
+
return parsed;
|
|
1893
|
+
}
|
|
1894
|
+
async function getPlatformOrigin() {
|
|
1895
|
+
const apiUrl = await getApiUrl();
|
|
1896
|
+
return toPlatformUrl(apiUrl).origin;
|
|
1897
|
+
}
|
|
1898
|
+
|
|
2104
1899
|
// src/commands/zero/connector/status.ts
|
|
2105
1900
|
var LABEL_WIDTH = 16;
|
|
2106
|
-
var statusCommand2 = new Command().name("status").description("Show detailed status of a connector").argument("<type>", "Connector type (e.g., github)").action(
|
|
2107
|
-
withErrorHandler(async (type) => {
|
|
1901
|
+
var statusCommand2 = new Command().name("status").description("Show detailed status of a connector").argument("<type>", "Connector type (e.g., github)").option("--agent <id>", "Show authorization state for the given agent").action(
|
|
1902
|
+
withErrorHandler(async (type, options) => {
|
|
2108
1903
|
const parseResult = connectorTypeSchema.safeParse(type);
|
|
2109
1904
|
if (!parseResult.success) {
|
|
2110
1905
|
const available = Object.keys(CONNECTOR_TYPES).join(", ");
|
|
@@ -2112,7 +1907,10 @@ var statusCommand2 = new Command().name("status").description("Show detailed sta
|
|
|
2112
1907
|
cause: new Error(`Available connectors: ${available}`)
|
|
2113
1908
|
});
|
|
2114
1909
|
}
|
|
2115
|
-
const connector = await
|
|
1910
|
+
const [connector, agentCtx] = await Promise.all([
|
|
1911
|
+
getZeroConnector(parseResult.data),
|
|
1912
|
+
resolveAgentContext(options.agent)
|
|
1913
|
+
]);
|
|
2116
1914
|
console.log(`Connector: ${source_default.cyan(type)}`);
|
|
2117
1915
|
console.log();
|
|
2118
1916
|
if (connector) {
|
|
@@ -2154,67 +1952,37 @@ var statusCommand2 = new Command().name("status").description("Show detailed sta
|
|
|
2154
1952
|
`${"Last Updated:".padEnd(LABEL_WIDTH)}${formatDateTime(connector.updatedAt)}`
|
|
2155
1953
|
);
|
|
2156
1954
|
}
|
|
2157
|
-
console.log();
|
|
2158
|
-
console.log(source_default.dim("To disconnect:"));
|
|
2159
|
-
console.log(source_default.dim(` zero connector disconnect ${type}`));
|
|
2160
1955
|
} else {
|
|
2161
1956
|
console.log(
|
|
2162
1957
|
`${"Status:".padEnd(LABEL_WIDTH)}${source_default.dim("not connected")}`
|
|
2163
1958
|
);
|
|
2164
|
-
console.log();
|
|
2165
|
-
console.log(source_default.dim("To connect:"));
|
|
2166
|
-
console.log(source_default.dim(` zero connector connect ${type}`));
|
|
2167
1959
|
}
|
|
2168
|
-
|
|
2169
|
-
);
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
1960
|
+
if (agentCtx) {
|
|
1961
|
+
const authorized = agentCtx.authorizedTypes.has(parseResult.data);
|
|
1962
|
+
const glyph = authorized ? source_default.green("\u2713") : source_default.dim("-");
|
|
1963
|
+
console.log();
|
|
1964
|
+
console.log(
|
|
1965
|
+
`${"Authorized:".padEnd(LABEL_WIDTH)}${glyph} for agent ${agentCtx.displayName}`
|
|
1966
|
+
);
|
|
1967
|
+
if (!authorized) {
|
|
1968
|
+
const origin = await getPlatformOrigin();
|
|
1969
|
+
const url = `${origin}/connectors/${parseResult.data}/authorize?agentId=${agentCtx.agentId}`;
|
|
1970
|
+
console.log(
|
|
1971
|
+
`${"".padEnd(LABEL_WIDTH)}${source_default.dim("Authorize:")} ${url}`
|
|
1972
|
+
);
|
|
1973
|
+
}
|
|
2181
1974
|
}
|
|
2182
|
-
const connectorType = parseResult.data;
|
|
2183
|
-
await deleteZeroConnector(connectorType);
|
|
2184
|
-
console.log(source_default.green(`\u2713 Disconnected ${type}`));
|
|
2185
1975
|
})
|
|
2186
1976
|
);
|
|
2187
1977
|
|
|
2188
1978
|
// src/commands/zero/connector/index.ts
|
|
2189
|
-
var zeroConnectorCommand = new Command().name("connector").description("Check
|
|
1979
|
+
var zeroConnectorCommand = new Command().name("connector").description("Check third-party service connections (GitHub, Slack, etc.)").addCommand(listCommand6).addCommand(searchCommand).addCommand(statusCommand2);
|
|
2190
1980
|
|
|
2191
1981
|
// src/commands/zero/doctor/index.ts
|
|
2192
1982
|
init_esm_shims();
|
|
2193
1983
|
|
|
2194
1984
|
// src/commands/zero/doctor/check-connector.ts
|
|
2195
1985
|
init_esm_shims();
|
|
2196
|
-
|
|
2197
|
-
// src/commands/zero/doctor/platform-url.ts
|
|
2198
|
-
init_esm_shims();
|
|
2199
|
-
function toPlatformUrl(apiUrl) {
|
|
2200
|
-
const parsed = new URL(apiUrl);
|
|
2201
|
-
const parts = parsed.hostname.split(".");
|
|
2202
|
-
if (parts[0].endsWith("-www")) {
|
|
2203
|
-
parts[0] = parts[0].slice(0, -"-www".length) + "-app";
|
|
2204
|
-
} else if (parts[0] === "www" || parts[0] === "platform") {
|
|
2205
|
-
parts[0] = "app";
|
|
2206
|
-
} else if (parts[0] !== "app" && parts[0] !== "localhost") {
|
|
2207
|
-
parts.unshift("app");
|
|
2208
|
-
}
|
|
2209
|
-
parsed.hostname = parts.join(".");
|
|
2210
|
-
return parsed;
|
|
2211
|
-
}
|
|
2212
|
-
async function getPlatformOrigin() {
|
|
2213
|
-
const apiUrl = await getApiUrl();
|
|
2214
|
-
return toPlatformUrl(apiUrl).origin;
|
|
2215
|
-
}
|
|
2216
|
-
|
|
2217
|
-
// src/commands/zero/doctor/check-connector.ts
|
|
2218
1986
|
function resolveConnectorFromUrl(url) {
|
|
2219
1987
|
const allTypes = Object.keys(CONNECTOR_TYPES);
|
|
2220
1988
|
const normalized = url.endsWith("/") ? url.slice(0, -1) : url;
|
|
@@ -4222,10 +3990,10 @@ Notes:
|
|
|
4222
3990
|
|
|
4223
3991
|
// src/commands/zero/slack/download-file.ts
|
|
4224
3992
|
init_esm_shims();
|
|
4225
|
-
import { join
|
|
3993
|
+
import { join } from "path";
|
|
4226
3994
|
import { tmpdir } from "os";
|
|
4227
3995
|
function defaultOutPath(fileId) {
|
|
4228
|
-
return
|
|
3996
|
+
return join(tmpdir(), `slack-${fileId}`);
|
|
4229
3997
|
}
|
|
4230
3998
|
var downloadFileCommand = new Command().name("download-file").description("Download a Slack file by id using the bot token").argument("<file-id>", "Slack file id (e.g. F01234ABCD)").option(
|
|
4231
3999
|
"-o, --out <path>",
|
|
@@ -4520,7 +4288,7 @@ init_esm_shims();
|
|
|
4520
4288
|
// src/lib/skill-directory.ts
|
|
4521
4289
|
init_esm_shims();
|
|
4522
4290
|
import { readFileSync as readFileSync6, readdirSync } from "fs";
|
|
4523
|
-
import { join as
|
|
4291
|
+
import { join as join2 } from "path";
|
|
4524
4292
|
var IGNORED_NAMES = /* @__PURE__ */ new Set(["node_modules", ".git", ".DS_Store"]);
|
|
4525
4293
|
function readSkillDirectory(dirPath) {
|
|
4526
4294
|
const files = [];
|
|
@@ -4530,11 +4298,11 @@ function readSkillDirectory(dirPath) {
|
|
|
4530
4298
|
if (entry.name.startsWith(".") || IGNORED_NAMES.has(entry.name)) continue;
|
|
4531
4299
|
const relPath = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
4532
4300
|
if (entry.isDirectory()) {
|
|
4533
|
-
walk(
|
|
4301
|
+
walk(join2(dir, entry.name), relPath);
|
|
4534
4302
|
} else {
|
|
4535
4303
|
files.push({
|
|
4536
4304
|
path: relPath,
|
|
4537
|
-
content: readFileSync6(
|
|
4305
|
+
content: readFileSync6(join2(dir, entry.name), "utf-8")
|
|
4538
4306
|
});
|
|
4539
4307
|
}
|
|
4540
4308
|
}
|
|
@@ -4857,7 +4625,7 @@ function parseContextOptions(options) {
|
|
|
4857
4625
|
}
|
|
4858
4626
|
return { before, after };
|
|
4859
4627
|
}
|
|
4860
|
-
function
|
|
4628
|
+
function parseLimit2(value) {
|
|
4861
4629
|
if (!value) return void 0;
|
|
4862
4630
|
const limit = parseInt(value, 10);
|
|
4863
4631
|
if (isNaN(limit) || limit < 1 || limit > 50) {
|
|
@@ -4912,7 +4680,7 @@ function renderResults(response) {
|
|
|
4912
4680
|
);
|
|
4913
4681
|
}
|
|
4914
4682
|
}
|
|
4915
|
-
var
|
|
4683
|
+
var searchCommand2 = new Command().name("search").description("Search agent events across runs").argument("<keyword>", "Search keyword").option("-A, --after-context <n>", "Show n events after each match").option("-B, --before-context <n>", "Show n events before each match").option("-C, --context <n>", "Show n events before and after each match").option("--agent <name>", "Filter by agent name").option("--run <id>", "Filter by specific run ID").option("--since <time>", "Search logs since (default: 7d)").option("--limit <n>", "Maximum number of matches (default: 20)").addHelpText(
|
|
4916
4684
|
"after",
|
|
4917
4685
|
`
|
|
4918
4686
|
Examples:
|
|
@@ -4930,7 +4698,7 @@ Examples:
|
|
|
4930
4698
|
process.exit(1);
|
|
4931
4699
|
}
|
|
4932
4700
|
const since = options.since ? parseTime(options.since) : Date.now() - SEVEN_DAYS_MS;
|
|
4933
|
-
const limit =
|
|
4701
|
+
const limit = parseLimit2(options.limit);
|
|
4934
4702
|
const response = await searchZeroLogs({
|
|
4935
4703
|
keyword,
|
|
4936
4704
|
agent: options.agent,
|
|
@@ -5008,7 +4776,7 @@ async function showAgentEvents(runId, options) {
|
|
|
5008
4776
|
renderAgentEvent(event, renderer);
|
|
5009
4777
|
}
|
|
5010
4778
|
}
|
|
5011
|
-
var zeroLogsCommand = new Command().name("logs").description("View and search agent run logs").argument("[runId]", "Run ID to view agent events for").addCommand(listCommand11).addCommand(
|
|
4779
|
+
var zeroLogsCommand = new Command().name("logs").description("View and search agent run logs").argument("[runId]", "Run ID to view agent events for").addCommand(listCommand11).addCommand(searchCommand2).option(
|
|
5012
4780
|
"--since <time>",
|
|
5013
4781
|
"Show logs since timestamp (e.g., 5m, 2h, 1d, 2024-01-15T10:30:00Z)"
|
|
5014
4782
|
).option("--tail <n>", "Show last N entries (default: 5)").option("--head <n>", "Show first N entries").option("--all", "Fetch all log entries").addHelpText(
|
|
@@ -5117,7 +4885,7 @@ init_esm_shims();
|
|
|
5117
4885
|
// src/lib/computer-use/desktop-server.ts
|
|
5118
4886
|
init_esm_shims();
|
|
5119
4887
|
import {
|
|
5120
|
-
createServer
|
|
4888
|
+
createServer
|
|
5121
4889
|
} from "http";
|
|
5122
4890
|
import { createServer as createNetServer } from "net";
|
|
5123
4891
|
|
|
@@ -5126,12 +4894,12 @@ init_esm_shims();
|
|
|
5126
4894
|
import { execFile } from "child_process";
|
|
5127
4895
|
import { readFile, unlink } from "fs/promises";
|
|
5128
4896
|
import { randomUUID } from "crypto";
|
|
5129
|
-
import { join as
|
|
4897
|
+
import { join as join3 } from "path";
|
|
5130
4898
|
import { tmpdir as tmpdir2 } from "os";
|
|
5131
4899
|
import { promisify } from "util";
|
|
5132
4900
|
var execFileAsync = promisify(execFile);
|
|
5133
4901
|
async function captureScreenshot() {
|
|
5134
|
-
const tmpPath =
|
|
4902
|
+
const tmpPath = join3(tmpdir2(), `vm0-screenshot-${randomUUID()}.jpg`);
|
|
5135
4903
|
try {
|
|
5136
4904
|
await execFileAsync("screencapture", ["-x", "-t", "jpg", tmpPath]);
|
|
5137
4905
|
const info = await getScreenInfo();
|
|
@@ -5160,7 +4928,7 @@ async function captureScreenshot() {
|
|
|
5160
4928
|
}
|
|
5161
4929
|
}
|
|
5162
4930
|
async function captureRegionScreenshot(region) {
|
|
5163
|
-
const tmpPath =
|
|
4931
|
+
const tmpPath = join3(tmpdir2(), `vm0-zoom-${randomUUID()}.jpg`);
|
|
5164
4932
|
try {
|
|
5165
4933
|
const regionArg = `${region.x},${region.y},${region.width},${region.height}`;
|
|
5166
4934
|
await execFileAsync("screencapture", [
|
|
@@ -5417,7 +5185,7 @@ async function scroll(x, y, direction, amount = DEFAULT_SCROLL_AMOUNT) {
|
|
|
5417
5185
|
|
|
5418
5186
|
// src/lib/computer-use/clipboard.ts
|
|
5419
5187
|
init_esm_shims();
|
|
5420
|
-
import { execFile as execFile4, spawn
|
|
5188
|
+
import { execFile as execFile4, spawn } from "child_process";
|
|
5421
5189
|
import { promisify as promisify4 } from "util";
|
|
5422
5190
|
var execFileAsync4 = promisify4(execFile4);
|
|
5423
5191
|
async function readClipboard() {
|
|
@@ -5426,7 +5194,7 @@ async function readClipboard() {
|
|
|
5426
5194
|
}
|
|
5427
5195
|
async function writeClipboard(text) {
|
|
5428
5196
|
return new Promise((resolve, reject) => {
|
|
5429
|
-
const proc =
|
|
5197
|
+
const proc = spawn("pbcopy", { stdio: ["pipe", "ignore", "ignore"] });
|
|
5430
5198
|
proc.on("error", reject);
|
|
5431
5199
|
proc.on("close", (code) => {
|
|
5432
5200
|
if (code === 0) {
|
|
@@ -5653,7 +5421,7 @@ async function handleOpenApplication(req, res) {
|
|
|
5653
5421
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
5654
5422
|
res.end(JSON.stringify({ ok: true }));
|
|
5655
5423
|
}
|
|
5656
|
-
async function
|
|
5424
|
+
async function getRandomPort() {
|
|
5657
5425
|
return new Promise((resolve, reject) => {
|
|
5658
5426
|
const server = createNetServer();
|
|
5659
5427
|
server.listen(0, "127.0.0.1", () => {
|
|
@@ -5727,7 +5495,7 @@ async function handleRequest(token, req, res) {
|
|
|
5727
5495
|
}
|
|
5728
5496
|
function startDesktopServer(token, port) {
|
|
5729
5497
|
return new Promise((resolve, reject) => {
|
|
5730
|
-
const server =
|
|
5498
|
+
const server = createServer((req, res) => {
|
|
5731
5499
|
handleRequest(token, req, res).catch(() => {
|
|
5732
5500
|
if (!res.headersSent) {
|
|
5733
5501
|
res.writeHead(500, { "Content-Type": "text/plain" });
|
|
@@ -5744,7 +5512,7 @@ function startDesktopServer(token, port) {
|
|
|
5744
5512
|
|
|
5745
5513
|
// src/lib/computer-use/ngrok.ts
|
|
5746
5514
|
init_esm_shims();
|
|
5747
|
-
async function
|
|
5515
|
+
async function loadNgrok() {
|
|
5748
5516
|
try {
|
|
5749
5517
|
const mod = await import("@ngrok/ngrok");
|
|
5750
5518
|
return mod.default;
|
|
@@ -5756,7 +5524,7 @@ async function loadNgrok2() {
|
|
|
5756
5524
|
}
|
|
5757
5525
|
}
|
|
5758
5526
|
async function startDesktopTunnel(ngrokToken, endpointPrefix, port) {
|
|
5759
|
-
const ngrok = await
|
|
5527
|
+
const ngrok = await loadNgrok();
|
|
5760
5528
|
await ngrok.forward({
|
|
5761
5529
|
addr: `localhost:${port}`,
|
|
5762
5530
|
authtoken: ngrokToken,
|
|
@@ -5764,7 +5532,7 @@ async function startDesktopTunnel(ngrokToken, endpointPrefix, port) {
|
|
|
5764
5532
|
});
|
|
5765
5533
|
}
|
|
5766
5534
|
async function stopDesktopTunnel() {
|
|
5767
|
-
const ngrok = await
|
|
5535
|
+
const ngrok = await loadNgrok();
|
|
5768
5536
|
await ngrok.kill();
|
|
5769
5537
|
}
|
|
5770
5538
|
|
|
@@ -5786,7 +5554,7 @@ var hostStartCommand = new Command().name("start").description("Start the comput
|
|
|
5786
5554
|
}
|
|
5787
5555
|
console.log(source_default.cyan("Registering computer-use host..."));
|
|
5788
5556
|
const credentials = await registerComputerUseHost();
|
|
5789
|
-
const port = await
|
|
5557
|
+
const port = await getRandomPort();
|
|
5790
5558
|
const server = await startDesktopServer(credentials.token, port);
|
|
5791
5559
|
try {
|
|
5792
5560
|
await startDesktopTunnel(
|
|
@@ -5852,7 +5620,7 @@ var hostStopCommand = new Command().name("stop").description("Stop and unregiste
|
|
|
5852
5620
|
// src/commands/zero/computer-use/client.ts
|
|
5853
5621
|
init_esm_shims();
|
|
5854
5622
|
import { writeFile, mkdir } from "fs/promises";
|
|
5855
|
-
import { join as
|
|
5623
|
+
import { join as join4 } from "path";
|
|
5856
5624
|
|
|
5857
5625
|
// src/lib/computer-use/client.ts
|
|
5858
5626
|
init_esm_shims();
|
|
@@ -5920,7 +5688,7 @@ var clientScreenshotCommand = new Command().name("screenshot").description("Capt
|
|
|
5920
5688
|
const dir = "/tmp/computer-use";
|
|
5921
5689
|
await mkdir(dir, { recursive: true });
|
|
5922
5690
|
const timestamp = Date.now();
|
|
5923
|
-
const filePath =
|
|
5691
|
+
const filePath = join4(dir, `screenshot-${timestamp}.${data.format}`);
|
|
5924
5692
|
const buffer = Buffer.from(data.image, "base64");
|
|
5925
5693
|
await writeFile(filePath, buffer);
|
|
5926
5694
|
process.stdout.write(`${filePath}
|
|
@@ -5948,7 +5716,7 @@ var clientZoomCommand = new Command().name("zoom").description("Capture a region
|
|
|
5948
5716
|
const dir = "/tmp/computer-use";
|
|
5949
5717
|
await mkdir(dir, { recursive: true });
|
|
5950
5718
|
const timestamp = Date.now();
|
|
5951
|
-
const filePath =
|
|
5719
|
+
const filePath = join4(dir, `zoom-${timestamp}.${data.format}`);
|
|
5952
5720
|
const buffer = Buffer.from(data.image, "base64");
|
|
5953
5721
|
await writeFile(filePath, buffer);
|
|
5954
5722
|
process.stdout.write(`${filePath}
|
|
@@ -6172,7 +5940,7 @@ function printCallInfo(call, callId) {
|
|
|
6172
5940
|
// src/commands/zero/phone/call.ts
|
|
6173
5941
|
var POLL_INTERVAL_MS = 1e4;
|
|
6174
5942
|
var POLL_TIMEOUT_MS = 15 * 60 * 1e3;
|
|
6175
|
-
var
|
|
5943
|
+
var delay = {
|
|
6176
5944
|
ms: (ms) => {
|
|
6177
5945
|
return new Promise((resolve) => {
|
|
6178
5946
|
setTimeout(resolve, ms);
|
|
@@ -6243,7 +6011,7 @@ var callCommand = new Command().name("call").description("Initiate an outbound p
|
|
|
6243
6011
|
);
|
|
6244
6012
|
const startTime = Date.now();
|
|
6245
6013
|
while (Date.now() - startTime < POLL_TIMEOUT_MS) {
|
|
6246
|
-
await
|
|
6014
|
+
await delay.ms(POLL_INTERVAL_MS);
|
|
6247
6015
|
const detail = await getPhoneCallDetail(result.callId);
|
|
6248
6016
|
const status = detail.call.status;
|
|
6249
6017
|
const elapsed = Math.round((Date.now() - startTime) / 1e3);
|
|
@@ -6422,10 +6190,10 @@ init_esm_shims();
|
|
|
6422
6190
|
|
|
6423
6191
|
// src/commands/zero/web/download-file.ts
|
|
6424
6192
|
init_esm_shims();
|
|
6425
|
-
import { join as
|
|
6193
|
+
import { join as join5 } from "path";
|
|
6426
6194
|
import { tmpdir as tmpdir3 } from "os";
|
|
6427
6195
|
function defaultOutPath2(fileId) {
|
|
6428
|
-
return
|
|
6196
|
+
return join5(tmpdir3(), `web-${fileId}`);
|
|
6429
6197
|
}
|
|
6430
6198
|
var downloadFileCommand2 = new Command().name("download-file").description("Download a web-uploaded file by id").argument("<file-id>", "File id (UUID returned by the upload API)").option(
|
|
6431
6199
|
"-o, --out <path>",
|
|
@@ -6523,7 +6291,7 @@ function registerZeroCommands(prog, commands) {
|
|
|
6523
6291
|
var program = new Command();
|
|
6524
6292
|
program.name("zero").description(
|
|
6525
6293
|
"Zero CLI \u2014 interact with the zero platform from inside the sandbox"
|
|
6526
|
-
).version("9.
|
|
6294
|
+
).version("9.120.0").addHelpText(
|
|
6527
6295
|
"after",
|
|
6528
6296
|
`
|
|
6529
6297
|
Examples:
|