@vm0/cli 9.98.2 → 9.100.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vm0/cli",
3
- "version": "9.98.2",
3
+ "version": "9.100.0",
4
4
  "description": "CLI application",
5
5
  "repository": {
6
6
  "type": "git",
package/zero.js CHANGED
@@ -90,6 +90,7 @@ import {
90
90
  removeZeroOrgMember,
91
91
  renderRunCreated,
92
92
  resolveCompose,
93
+ resolveFirewallPolicies,
93
94
  resolveZeroScheduleByAgent,
94
95
  saveConfig,
95
96
  searchZeroLogs,
@@ -108,7 +109,7 @@ import {
108
109
  updateZeroUserPreferences,
109
110
  upsertZeroOrgModelProvider,
110
111
  withErrorHandler
111
- } from "./chunk-3S6PEJ3G.js";
112
+ } from "./chunk-2KKNOZ4M.js";
112
113
 
113
114
  // src/zero.ts
114
115
  import { Command as Command73 } from "commander";
@@ -1268,30 +1269,139 @@ Notes:
1268
1269
  // src/commands/zero/agent/view.ts
1269
1270
  import { Command as Command26 } from "commander";
1270
1271
  import chalk23 from "chalk";
1271
- var viewCommand = new Command26().name("view").description("View a zero agent").argument("<agent-id>", "Agent ID").option("--instructions", "Also show instructions content").addHelpText(
1272
+ function getConnectorPermissionInfo(type, resolvedPolicies) {
1273
+ if (!isFirewallConnectorType(type)) {
1274
+ return {
1275
+ type,
1276
+ hasFirewall: false,
1277
+ permissions: [],
1278
+ policies: null,
1279
+ allowed: 0,
1280
+ total: 0
1281
+ };
1282
+ }
1283
+ const policies = resolvedPolicies?.[type] ?? null;
1284
+ const config = getConnectorFirewall(type);
1285
+ const permissions = config.apis.flatMap((a) => {
1286
+ return a.permissions ?? [];
1287
+ });
1288
+ const total = permissions.length;
1289
+ const allowed = policies ? permissions.filter((p) => {
1290
+ return policies[p.name] === "allow";
1291
+ }).length : 0;
1292
+ return { type, hasFirewall: true, permissions, policies, allowed, total };
1293
+ }
1294
+ function formatConnectorIdentity(connector) {
1295
+ if (!connector) return "";
1296
+ if (connector.externalUsername) return `@${connector.externalUsername}`;
1297
+ if (connector.externalEmail) return connector.externalEmail;
1298
+ return "";
1299
+ }
1300
+ function formatConnectorSummary(info, identity) {
1301
+ const id = formatConnectorIdentity(identity);
1302
+ const idStr = id ? ` ${id}` : "";
1303
+ if (!info.hasFirewall) return `${info.type}${idStr}`;
1304
+ if (!info.policies) return `${info.type}${idStr} (full access)`;
1305
+ return `${info.type}${idStr} (${info.allowed}/${info.total} allowed)`;
1306
+ }
1307
+ function printAccountLine(connector) {
1308
+ if (!connector) return;
1309
+ let identity = "";
1310
+ if (connector.externalUsername && connector.externalEmail) {
1311
+ identity = `@${connector.externalUsername} (${connector.externalEmail})`;
1312
+ } else if (connector.externalUsername) {
1313
+ identity = `@${connector.externalUsername}`;
1314
+ } else if (connector.externalEmail) {
1315
+ identity = connector.externalEmail;
1316
+ }
1317
+ if (!identity) return;
1318
+ if (connector.needsReconnect) {
1319
+ identity += ` ${chalk23.yellow("(needs reconnect)")}`;
1320
+ }
1321
+ console.log(` Account: ${identity}`);
1322
+ }
1323
+ var viewCommand = new Command26().name("view").description("View a zero agent").argument("<agent-id>", "Agent ID").option("--instructions", "Also show instructions content").option("--permissions", "Show full permission details for each connector").addHelpText(
1272
1324
  "after",
1273
1325
  `
1274
1326
  Examples:
1275
1327
  View basic info: zero agent view <agent-id>
1276
1328
  Include instructions: zero agent view <agent-id> --instructions
1329
+ Show permissions: zero agent view <agent-id> --permissions
1277
1330
  View yourself: zero agent view $ZERO_AGENT_ID --instructions`
1278
1331
  ).action(
1279
1332
  withErrorHandler(
1280
1333
  async (agentId, options) => {
1281
- const agent = await getZeroAgent(agentId);
1334
+ const [agent, connectorTypes, connectorIdentities] = await Promise.all([
1335
+ getZeroAgent(agentId),
1336
+ getZeroAgentUserConnectors(agentId),
1337
+ listZeroConnectors().catch(() => {
1338
+ return { connectors: [] };
1339
+ })
1340
+ ]);
1341
+ const identityMap = new Map(
1342
+ connectorIdentities.connectors.map((c) => {
1343
+ return [c.type, c];
1344
+ })
1345
+ );
1282
1346
  console.log(chalk23.bold(agent.agentId));
1283
1347
  if (agent.displayName) console.log(chalk23.dim(agent.displayName));
1284
1348
  console.log();
1285
1349
  console.log(`Agent ID: ${agent.agentId}`);
1286
- const connectors = await getZeroAgentUserConnectors(agentId);
1287
- if (connectors.length > 0)
1288
- console.log(`Connectors: ${connectors.join(", ")}`);
1350
+ const resolvedPolicies = resolveFirewallPolicies(
1351
+ agent.firewallPolicies,
1352
+ connectorTypes
1353
+ );
1354
+ const connectorInfos = connectorTypes.map((type) => {
1355
+ return getConnectorPermissionInfo(type, resolvedPolicies);
1356
+ });
1357
+ if (connectorInfos.length > 0) {
1358
+ const summaries = connectorInfos.map((info) => {
1359
+ return formatConnectorSummary(info, identityMap.get(info.type));
1360
+ });
1361
+ console.log(`Connectors: ${summaries.join(", ")}`);
1362
+ }
1289
1363
  if (agent.customSkills?.length > 0) {
1290
1364
  console.log(`Skills: ${agent.customSkills.join(", ")}`);
1291
1365
  }
1292
1366
  if (agent.description)
1293
1367
  console.log(`Description: ${agent.description}`);
1294
1368
  if (agent.sound) console.log(`Sound: ${agent.sound}`);
1369
+ if (options.permissions && connectorInfos.length > 0) {
1370
+ console.log();
1371
+ for (const info of connectorInfos) {
1372
+ if (!info.hasFirewall) {
1373
+ console.log(chalk23.dim(`\u2500\u2500 ${info.type} \u2500\u2500`));
1374
+ printAccountLine(identityMap.get(info.type));
1375
+ console.log(" No firewall configured.");
1376
+ continue;
1377
+ }
1378
+ if (!info.policies) {
1379
+ console.log(chalk23.dim(`\u2500\u2500 ${info.type} (full access) \u2500\u2500`));
1380
+ printAccountLine(identityMap.get(info.type));
1381
+ console.log(
1382
+ " No permission rules configured \u2014 all API calls allowed."
1383
+ );
1384
+ continue;
1385
+ }
1386
+ console.log(
1387
+ chalk23.dim(
1388
+ `\u2500\u2500 ${info.type} (${info.allowed}/${info.total} allowed) \u2500\u2500`
1389
+ )
1390
+ );
1391
+ printAccountLine(identityMap.get(info.type));
1392
+ const nameWidth = Math.max(
1393
+ ...info.permissions.map((p) => {
1394
+ return p.name.length;
1395
+ })
1396
+ );
1397
+ for (const perm of info.permissions) {
1398
+ const policy = info.policies[perm.name] ?? "deny";
1399
+ const icon = policy === "allow" ? chalk23.green("\u2713") : policy === "ask" ? chalk23.yellow("?") : chalk23.dim("\u2717");
1400
+ const desc = perm.description ?? "";
1401
+ console.log(` ${icon} ${perm.name.padEnd(nameWidth)} ${desc}`);
1402
+ }
1403
+ }
1404
+ }
1295
1405
  if (options.instructions) {
1296
1406
  console.log();
1297
1407
  const result = await getZeroAgentInstructions(agentId);
@@ -2101,7 +2211,7 @@ Notes:
2101
2211
  const isConnected = connector !== null;
2102
2212
  const hasPermission = enabledTypes !== null && enabledTypes.includes(connectorType);
2103
2213
  if (!isConnected) {
2104
- const url = `${platformUrl.origin}/connectors`;
2214
+ const url = `${platformUrl.origin}/connectors/${connectorType}/connect`;
2105
2215
  console.log(
2106
2216
  `The ${label} connector is not connected. Ask the user to connect it at: [Connect ${label}](${url})`
2107
2217
  );
@@ -3730,6 +3840,44 @@ import chalk47 from "chalk";
3730
3840
  function isInsideSandbox() {
3731
3841
  return !!process.env.ZERO_AGENT_ID;
3732
3842
  }
3843
+ function formatConnectorIdentity2(connector) {
3844
+ let identity = "";
3845
+ if (connector.externalUsername && connector.externalEmail) {
3846
+ identity = `@${connector.externalUsername} (${connector.externalEmail})`;
3847
+ } else if (connector.externalUsername) {
3848
+ identity = `@${connector.externalUsername}`;
3849
+ } else if (connector.externalEmail) {
3850
+ identity = connector.externalEmail;
3851
+ }
3852
+ if (connector.needsReconnect) {
3853
+ identity += ` ${chalk47.yellow("(needs reconnect)")}`;
3854
+ }
3855
+ return identity;
3856
+ }
3857
+ function printConnectorPermissions(type, resolvedPolicies) {
3858
+ if (!isFirewallConnectorType(type)) return;
3859
+ const policies = resolvedPolicies?.[type] ?? null;
3860
+ if (!policies) {
3861
+ console.log(chalk47.dim(" full access \u2014 no permission rules configured"));
3862
+ return;
3863
+ }
3864
+ const config = getConnectorFirewall(type);
3865
+ const permissions = config.apis.flatMap((a) => {
3866
+ return a.permissions ?? [];
3867
+ });
3868
+ if (permissions.length === 0) return;
3869
+ const nameWidth = Math.max(
3870
+ ...permissions.map((p) => {
3871
+ return p.name.length;
3872
+ })
3873
+ );
3874
+ for (const perm of permissions) {
3875
+ const policy = policies[perm.name] ?? "deny";
3876
+ const icon = policy === "allow" ? chalk47.green("\u2713") : policy === "ask" ? chalk47.yellow("?") : chalk47.dim("\u2717");
3877
+ const desc = perm.description ?? "";
3878
+ console.log(` ${icon} ${perm.name.padEnd(nameWidth)} ${desc}`);
3879
+ }
3880
+ }
3733
3881
  async function showSandboxInfo() {
3734
3882
  const agentId = process.env.ZERO_AGENT_ID;
3735
3883
  const payload = decodeZeroTokenPayload();
@@ -3741,6 +3889,36 @@ async function showSandboxInfo() {
3741
3889
  console.log(chalk47.bold("Capabilities:"));
3742
3890
  console.log(` ${payload.capabilities.join(", ")}`);
3743
3891
  }
3892
+ try {
3893
+ const [connectorsResult, agentResult, enabledResult] = await Promise.allSettled([
3894
+ listZeroConnectors(),
3895
+ getZeroAgent(agentId),
3896
+ getZeroAgentUserConnectors(agentId)
3897
+ ]);
3898
+ if (connectorsResult.status === "rejected") return;
3899
+ const identities = connectorsResult.value.connectors.filter((c) => {
3900
+ return c.externalUsername !== null || c.externalEmail !== null;
3901
+ });
3902
+ if (identities.length === 0) return;
3903
+ let resolvedPolicies = null;
3904
+ const permissionDataAvailable = agentResult.status === "fulfilled" && enabledResult.status === "fulfilled";
3905
+ if (permissionDataAvailable) {
3906
+ resolvedPolicies = resolveFirewallPolicies(
3907
+ agentResult.value.firewallPolicies,
3908
+ enabledResult.value
3909
+ );
3910
+ }
3911
+ console.log();
3912
+ console.log(chalk47.bold("Connected Services:"));
3913
+ for (const connector of identities) {
3914
+ const identity = formatConnectorIdentity2(connector);
3915
+ console.log(` ${connector.type.padEnd(14)}${identity}`);
3916
+ if (permissionDataAvailable) {
3917
+ printConnectorPermissions(connector.type, resolvedPolicies);
3918
+ }
3919
+ }
3920
+ } catch {
3921
+ }
3744
3922
  }
3745
3923
  async function showLocalInfo() {
3746
3924
  const token = await getToken();
@@ -4458,6 +4636,7 @@ Examples:
4458
4636
  var COMMAND_CAPABILITY_MAP = {
4459
4637
  agent: "agent:read",
4460
4638
  skill: "agent:read",
4639
+ connector: "connector:read",
4461
4640
  run: "agent-run:write",
4462
4641
  schedule: "schedule:read",
4463
4642
  doctor: null,
@@ -4499,7 +4678,7 @@ function registerZeroCommands(prog, commands) {
4499
4678
  var program = new Command73();
4500
4679
  program.name("zero").description(
4501
4680
  "Zero CLI \u2014 interact with the zero platform from inside the sandbox"
4502
- ).version("9.98.2").addHelpText(
4681
+ ).version("9.100.0").addHelpText(
4503
4682
  "after",
4504
4683
  `
4505
4684
  Examples: