@vm0/cli 9.241.9 → 9.241.10

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.
Files changed (98) hide show
  1. package/{agent-YCTYPYF7.js → agent-R6GX5WZK.js} +5 -5
  2. package/{banking-RWPXPGOY.js → banking-QXEV6VHK.js} +3 -3
  3. package/{chat-XWVVRA3Q.js → chat-CCDYINSK.js} +4 -4
  4. package/{chunk-XG3T3KKC.js → chunk-44EKQ5HS.js} +3 -3
  5. package/chunk-44EKQ5HS.js.map +1 -0
  6. package/{chunk-GJ2YK4RB.js → chunk-6NDKQYQ7.js} +2 -2
  7. package/{chunk-DCY7MYWI.js → chunk-A4YELTCO.js} +6 -5
  8. package/chunk-A4YELTCO.js.map +1 -0
  9. package/{chunk-HYARATBX.js → chunk-CCNJ3TMS.js} +2 -2
  10. package/{chunk-JZD2ALHL.js → chunk-ITFL2YCQ.js} +3 -3
  11. package/{chunk-N55TLKMY.js → chunk-JPUUXVCK.js} +4 -4
  12. package/{chunk-G2NMGFMS.js → chunk-JTTHBQX5.js} +4 -4
  13. package/{chunk-43Q6LJ4M.js → chunk-KOACS66Q.js} +2 -2
  14. package/{chunk-PM36DYSC.js → chunk-SIG5BQU7.js} +145 -302
  15. package/chunk-SIG5BQU7.js.map +1 -0
  16. package/{chunk-D7WBYCFZ.js → chunk-WUYQH7P6.js} +2 -2
  17. package/{computer-use-AJ4LM52W.js → computer-use-QA6IQNUM.js} +3 -3
  18. package/{doctor-PGH6KBWK.js → connector-ZRKGMLQV.js} +605 -382
  19. package/connector-ZRKGMLQV.js.map +1 -0
  20. package/{credit-QS7QUF3Q.js → credit-RA45SK2A.js} +4 -4
  21. package/{developer-support-QIN7JTGZ.js → developer-support-TWELXPIE.js} +3 -3
  22. package/doctor-RBV7YT5H.js +99 -0
  23. package/doctor-RBV7YT5H.js.map +1 -0
  24. package/{generate-VGPYBDHG.js → generate-OEJTQS4X.js} +4 -4
  25. package/{github-DBVCDROM.js → github-SF7JFEKG.js} +3 -3
  26. package/{goal-VZEI2OD2.js → goal-EDMGXLGF.js} +3 -3
  27. package/{host-35I2D3WT.js → host-FY63MGBO.js} +3 -3
  28. package/index.js +12 -12
  29. package/index.js.map +1 -1
  30. package/{logs-SW5VAI54.js → logs-DFPCRYBB.js} +5 -5
  31. package/{mail-YYSSPGP2.js → mail-JFPVKRAQ.js} +5 -5
  32. package/{maps-DIQSL73V.js → maps-SQ4KFU2B.js} +3 -3
  33. package/{model-ZFYWBWJ3.js → model-TCII3MKC.js} +4 -4
  34. package/{model-provider-7MXIPGCL.js → model-provider-QMDLZA4A.js} +4 -4
  35. package/{org-E2T6M6MN.js → org-72TDMI35.js} +3 -3
  36. package/package.json +1 -1
  37. package/{phone-KKPDS6J3.js → phone-ID5ADIL4.js} +3 -3
  38. package/{preference-MUE7N3MZ.js → preference-4ABPH3DP.js} +3 -3
  39. package/{resource-3HUMK4UE.js → resource-WXRM5ZLH.js} +3 -3
  40. package/{scrape-HH5G742T.js → scrape-TOIKQUQO.js} +3 -3
  41. package/{search-JSTRJBHA.js → search-J435DPB4.js} +6 -6
  42. package/search-J435DPB4.js.map +1 -0
  43. package/{secret-PH5S7HXR.js → secret-43UFWWZF.js} +3 -3
  44. package/{slack-5HWY6WME.js → slack-AFLHA6EV.js} +3 -3
  45. package/{teams-DJVOFNO6.js → teams-DRALNYB3.js} +3 -3
  46. package/{telegram-3IPXE4FT.js → telegram-FNF3CB2D.js} +3 -3
  47. package/{variable-XC2BRIE4.js → variable-TAGHFN6J.js} +3 -3
  48. package/{video-SAEKMO5Q.js → video-QZJWGO5E.js} +2 -2
  49. package/{web-GEEMEX3J.js → web-RVC3KCJ4.js} +3 -3
  50. package/{web-search-DLAG55F2.js → web-search-2AX2TD6R.js} +3 -3
  51. package/{whoami-EPCOG5DN.js → whoami-CITBGDEC.js} +5 -5
  52. package/{workflow-VS75PBYU.js → workflow-HLIF67NU.js} +3 -3
  53. package/zero.js +36 -36
  54. package/zero.js.map +1 -1
  55. package/chunk-DCY7MYWI.js.map +0 -1
  56. package/chunk-PM36DYSC.js.map +0 -1
  57. package/chunk-XG3T3KKC.js.map +0 -1
  58. package/connector-RBJZ3XJO.js +0 -559
  59. package/connector-RBJZ3XJO.js.map +0 -1
  60. package/doctor-PGH6KBWK.js.map +0 -1
  61. package/search-JSTRJBHA.js.map +0 -1
  62. /package/{agent-YCTYPYF7.js.map → agent-R6GX5WZK.js.map} +0 -0
  63. /package/{banking-RWPXPGOY.js.map → banking-QXEV6VHK.js.map} +0 -0
  64. /package/{chat-XWVVRA3Q.js.map → chat-CCDYINSK.js.map} +0 -0
  65. /package/{chunk-GJ2YK4RB.js.map → chunk-6NDKQYQ7.js.map} +0 -0
  66. /package/{chunk-HYARATBX.js.map → chunk-CCNJ3TMS.js.map} +0 -0
  67. /package/{chunk-JZD2ALHL.js.map → chunk-ITFL2YCQ.js.map} +0 -0
  68. /package/{chunk-N55TLKMY.js.map → chunk-JPUUXVCK.js.map} +0 -0
  69. /package/{chunk-G2NMGFMS.js.map → chunk-JTTHBQX5.js.map} +0 -0
  70. /package/{chunk-43Q6LJ4M.js.map → chunk-KOACS66Q.js.map} +0 -0
  71. /package/{chunk-D7WBYCFZ.js.map → chunk-WUYQH7P6.js.map} +0 -0
  72. /package/{computer-use-AJ4LM52W.js.map → computer-use-QA6IQNUM.js.map} +0 -0
  73. /package/{credit-QS7QUF3Q.js.map → credit-RA45SK2A.js.map} +0 -0
  74. /package/{developer-support-QIN7JTGZ.js.map → developer-support-TWELXPIE.js.map} +0 -0
  75. /package/{generate-VGPYBDHG.js.map → generate-OEJTQS4X.js.map} +0 -0
  76. /package/{github-DBVCDROM.js.map → github-SF7JFEKG.js.map} +0 -0
  77. /package/{goal-VZEI2OD2.js.map → goal-EDMGXLGF.js.map} +0 -0
  78. /package/{host-35I2D3WT.js.map → host-FY63MGBO.js.map} +0 -0
  79. /package/{logs-SW5VAI54.js.map → logs-DFPCRYBB.js.map} +0 -0
  80. /package/{mail-YYSSPGP2.js.map → mail-JFPVKRAQ.js.map} +0 -0
  81. /package/{maps-DIQSL73V.js.map → maps-SQ4KFU2B.js.map} +0 -0
  82. /package/{model-ZFYWBWJ3.js.map → model-TCII3MKC.js.map} +0 -0
  83. /package/{model-provider-7MXIPGCL.js.map → model-provider-QMDLZA4A.js.map} +0 -0
  84. /package/{org-E2T6M6MN.js.map → org-72TDMI35.js.map} +0 -0
  85. /package/{phone-KKPDS6J3.js.map → phone-ID5ADIL4.js.map} +0 -0
  86. /package/{preference-MUE7N3MZ.js.map → preference-4ABPH3DP.js.map} +0 -0
  87. /package/{resource-3HUMK4UE.js.map → resource-WXRM5ZLH.js.map} +0 -0
  88. /package/{scrape-HH5G742T.js.map → scrape-TOIKQUQO.js.map} +0 -0
  89. /package/{secret-PH5S7HXR.js.map → secret-43UFWWZF.js.map} +0 -0
  90. /package/{slack-5HWY6WME.js.map → slack-AFLHA6EV.js.map} +0 -0
  91. /package/{teams-DJVOFNO6.js.map → teams-DRALNYB3.js.map} +0 -0
  92. /package/{telegram-3IPXE4FT.js.map → telegram-FNF3CB2D.js.map} +0 -0
  93. /package/{variable-XC2BRIE4.js.map → variable-TAGHFN6J.js.map} +0 -0
  94. /package/{video-SAEKMO5Q.js.map → video-QZJWGO5E.js.map} +0 -0
  95. /package/{web-GEEMEX3J.js.map → web-RVC3KCJ4.js.map} +0 -0
  96. /package/{web-search-DLAG55F2.js.map → web-search-2AX2TD6R.js.map} +0 -0
  97. /package/{whoami-EPCOG5DN.js.map → whoami-CITBGDEC.js.map} +0 -0
  98. /package/{workflow-VS75PBYU.js.map → workflow-HLIF67NU.js.map} +0 -0
@@ -3,31 +3,40 @@ import { createRequire as __createRequire } from "node:module";
3
3
  const require = __createRequire(import.meta.url);
4
4
  import {
5
5
  findFirewallMetadataPermission
6
- } from "./chunk-HYARATBX.js";
6
+ } from "./chunk-CCNJ3TMS.js";
7
+ import {
8
+ availableConnectorRefs,
9
+ findConnectorStatusItem,
10
+ resolveAgentContext,
11
+ resolveManualGrantAuthMethod,
12
+ searchPublicConnectorCatalog
13
+ } from "./chunk-6NDKQYQ7.js";
7
14
  import {
8
15
  getPlatformOrigin,
9
16
  toPlatformUrl
10
- } from "./chunk-D7WBYCFZ.js";
17
+ } from "./chunk-WUYQH7P6.js";
11
18
  import {
12
19
  UNKNOWN_PERMISSION_GRANT,
20
+ connectZeroConnectorManualGrant,
13
21
  createComputerUseAuthorizationRequest,
22
+ customConnectorProposalSchema,
14
23
  diagnoseZeroConnectorCheck,
15
- diagnoseZeroConnectorPermissionDeny,
24
+ getZeroAgent,
25
+ getZeroAgentCustomConnectors,
16
26
  getZeroAgentUserConnectors,
17
- getZeroBillingStatus,
18
27
  getZeroConnector,
19
28
  getZeroConnectorCatalogPermissions,
20
- getZeroOrg,
21
- getZeroOrgMembers,
22
- hasUnsafeFirewallPath
23
- } from "./chunk-PM36DYSC.js";
29
+ getZeroCustomConnector,
30
+ listZeroConnectorCatalogStatus,
31
+ listZeroCustomConnectors
32
+ } from "./chunk-SIG5BQU7.js";
24
33
  import "./chunk-LTDQISD7.js";
25
34
  import {
26
35
  ApiRequestError,
27
36
  getApiUrl,
28
37
  source_default,
29
38
  withErrorHandler
30
- } from "./chunk-XG3T3KKC.js";
39
+ } from "./chunk-44EKQ5HS.js";
31
40
  import "./chunk-LRHXR7JT.js";
32
41
  import {
33
42
  Command,
@@ -37,11 +46,35 @@ import {
37
46
  init_esm_shims
38
47
  } from "./chunk-DIRAZ3YX.js";
39
48
 
40
- // src/commands/zero/doctor/index.ts
49
+ // src/commands/zero/connector/index.ts
50
+ init_esm_shims();
51
+
52
+ // src/commands/zero/connector/check.ts
41
53
  init_esm_shims();
42
54
 
43
- // src/commands/zero/doctor/check-connector.ts
55
+ // src/commands/zero/connector/computer-use-guidance.ts
44
56
  init_esm_shims();
57
+ var COMPUTER_USE_CONNECTOR_REF = "computer-use";
58
+ var COMPUTER_USE_CAPABILITY = "computer-use:write";
59
+ var COMPUTER_USE_PATH_PREFIX = "/computer-use";
60
+ var COMPUTER_USE_PATH_PREFIX_WITH_SLASH = `${COMPUTER_USE_PATH_PREFIX}/`;
61
+ function isComputerUsePermissionTarget(target) {
62
+ return target.connectorRef === COMPUTER_USE_CONNECTOR_REF || target.permission === COMPUTER_USE_CAPABILITY || target.path === COMPUTER_USE_PATH_PREFIX || target.path?.startsWith(COMPUTER_USE_PATH_PREFIX_WITH_SLASH) === true;
63
+ }
64
+ function printComputerUsePermissionGuidance() {
65
+ console.log("Computer Use access is not managed as a connector permission.");
66
+ console.log(
67
+ "The current run token needs computer-use:write, which is issued only when a Zero Desktop Computer Use host is selected for the chat or thread before the run starts."
68
+ );
69
+ console.log(
70
+ "Open Zero Desktop, make sure Computer Use is online, select the Computer Use host for this chat/thread, then start a new run. Existing run tokens cannot be upgraded in place."
71
+ );
72
+ console.log(
73
+ "Run `zero whoami` to confirm whether the current ZERO_TOKEN includes computer-use:write."
74
+ );
75
+ }
76
+
77
+ // src/commands/zero/connector/check.ts
45
78
  function stripUrlQueryAndFragment(url) {
46
79
  const queryIndex = url.indexOf("?");
47
80
  const fragmentIndex = url.indexOf("#");
@@ -74,7 +107,21 @@ function connectorSelectionCommand(url, method, connectorRef) {
74
107
  if (method !== "GET") {
75
108
  args.push(`--method ${shellQuoteArg(method)}`);
76
109
  }
77
- return `zero doctor check-connector ${args.join(" ")}`;
110
+ return `zero connector check ${args.join(" ")}`;
111
+ }
112
+ function rawPathFromUrl(url) {
113
+ const sanitizedUrl = stripUrlQueryAndFragment(url);
114
+ const schemeEnd = sanitizedUrl.indexOf("://");
115
+ if (schemeEnd === -1) return void 0;
116
+ const pathStart = sanitizedUrl.indexOf("/", schemeEnd + 3);
117
+ return pathStart === -1 ? "/" : sanitizedUrl.slice(pathStart);
118
+ }
119
+ function isComputerUseCheckTarget(opts) {
120
+ return isComputerUsePermissionTarget({
121
+ connectorRef: opts.connector ?? "",
122
+ path: opts.url === void 0 ? void 0 : rawPathFromUrl(opts.url),
123
+ permission: opts.checkPermission
124
+ });
78
125
  }
79
126
  function validateCheckConnectorOptions(opts, command) {
80
127
  const hasUrl = opts.url !== void 0;
@@ -141,15 +188,15 @@ function unsafeInputError(reason) {
141
188
  switch (reason) {
142
189
  case "invalid-method":
143
190
  return new Error(
144
- "check-connector requires --method to be a supported HTTP method."
191
+ "connector check requires --method to be a supported HTTP method."
145
192
  );
146
193
  case "invalid-url":
147
194
  return new Error(
148
- "check-connector requires --url to be a valid absolute http or https URL."
195
+ "connector check requires --url to be a valid absolute http or https URL."
149
196
  );
150
197
  case "unsafe-path":
151
198
  return new Error(
152
- "check-connector cannot diagnose unsafe URL paths because they are blocked before permission policy evaluation."
199
+ "connector check cannot diagnose unsafe URL paths because they are blocked before permission policy evaluation."
153
200
  );
154
201
  }
155
202
  }
@@ -433,7 +480,7 @@ function printUnavailablePolicy(policy) {
433
480
  return;
434
481
  }
435
482
  }
436
- function printNamedPolicyResult(permission, policy) {
483
+ function printNamedPolicyResult(connectorRef, permission, policy) {
437
484
  switch (policy.outcome) {
438
485
  case "allow": {
439
486
  switch (policy.basis) {
@@ -464,19 +511,25 @@ function printNamedPolicyResult(permission, policy) {
464
511
  console.log(
465
512
  policy.basis === "deny-list" ? `Result: "${permission}" is in the deny list \u2014 denied.` : `Result: The unknown-endpoint policy denies "${permission}".`
466
513
  );
514
+ console.log(
515
+ `To request this permission, run: ${permissionRequestCommand(connectorRef, permission)}`
516
+ );
467
517
  return;
468
518
  case "ask":
469
519
  console.log(
470
520
  policy.basis === "ask-list" ? `Result: "${permission}" is in the ask list \u2014 blocked until approval.` : `Result: The unknown-endpoint policy blocks "${permission}" until approval.`
471
521
  );
522
+ console.log(
523
+ `To request this permission, run: ${permissionRequestCommand(connectorRef, permission)}`
524
+ );
472
525
  return;
473
526
  case "unavailable":
474
527
  printUnavailablePolicy(policy);
475
528
  return;
476
529
  }
477
530
  }
478
- function unknownPermissionChangeCommand(connectorRef) {
479
- return `zero doctor permission-change ${connectorRef} --permission __unknown__ --enable --duration 1h`;
531
+ function permissionRequestCommand(connectorRef, permission) {
532
+ return `zero connector permission-request ${connectorRef} --permission ${permission} --duration 1h`;
480
533
  }
481
534
  function printUnknownEndpointPolicy(connectorRef, policy) {
482
535
  switch (policy.outcome) {
@@ -490,7 +543,7 @@ function printUnknownEndpointPolicy(connectorRef, policy) {
490
543
  "Result: No permission matched. The unknown endpoint policy denies this request."
491
544
  );
492
545
  console.log(
493
- `To allow unknown endpoints, run: ${unknownPermissionChangeCommand(connectorRef)}`
546
+ `To request access to unknown endpoints, run: ${permissionRequestCommand(connectorRef, "__unknown__")}`
494
547
  );
495
548
  return;
496
549
  case "ask":
@@ -498,7 +551,7 @@ function printUnknownEndpointPolicy(connectorRef, policy) {
498
551
  "Result: No permission matched. The unknown endpoint policy requires approval."
499
552
  );
500
553
  console.log(
501
- `To allow unknown endpoints, run: ${unknownPermissionChangeCommand(connectorRef)}`
554
+ `To request access to unknown endpoints, run: ${permissionRequestCommand(connectorRef, "__unknown__")}`
502
555
  );
503
556
  return;
504
557
  case "unavailable":
@@ -521,7 +574,11 @@ function printUrlPermissionDiagnostic(result) {
521
574
  );
522
575
  console.log("");
523
576
  for (const permission of result.permission.permissions) {
524
- printNamedPolicyResult(permission.name, permission.policy);
577
+ printNamedPolicyResult(
578
+ result.connector.connectorRef,
579
+ permission.name,
580
+ permission.policy
581
+ );
525
582
  }
526
583
  } else {
527
584
  console.log(
@@ -550,7 +607,11 @@ function printEnvironmentPermissionDiagnostic(result, permissionName) {
550
607
  `Checking permission: "${permissionName}" for the ${result.connector.label} connector.`
551
608
  );
552
609
  console.log("");
553
- printNamedPolicyResult(permissionName, result.permission);
610
+ printNamedPolicyResult(
611
+ result.connector.connectorRef,
612
+ permissionName,
613
+ result.permission
614
+ );
554
615
  console.log("");
555
616
  }
556
617
  function printRediagnoseHint(opts, method) {
@@ -573,10 +634,10 @@ function printRediagnoseHint(opts, method) {
573
634
  args.push(`--check-permission ${shellQuoteArg(opts.checkPermission)}`);
574
635
  }
575
636
  console.log(
576
- `To re-diagnose after changes, run: zero doctor check-connector ${args.join(" ")}`
637
+ `To re-diagnose after changes, run: zero connector check ${args.join(" ")}`
577
638
  );
578
639
  }
579
- var checkConnectorCommand = new Command().name("check-connector").description(
640
+ var checkConnectorCommand = new Command().name("check").description(
580
641
  "Diagnose connector health: environment names, connector configuration, and permission policies"
581
642
  ).addOption(
582
643
  new Option(
@@ -596,7 +657,7 @@ var checkConnectorCommand = new Command().name("check-connector").description(
596
657
  ).addOption(
597
658
  new Option(
598
659
  "--method <METHOD>",
599
- "HTTP method to use when matching permissions with --url (default: GET)"
660
+ "HTTP method to use when matching permissions with --url"
600
661
  ).default("GET")
601
662
  ).addOption(
602
663
  new Option(
@@ -607,11 +668,11 @@ var checkConnectorCommand = new Command().name("check-connector").description(
607
668
  "after",
608
669
  `
609
670
  Examples:
610
- zero doctor check-connector --env-name GITHUB_TOKEN
611
- zero doctor check-connector --url https://api.github.com/repos/owner/repo
612
- zero doctor check-connector --url https://api.accounts.nintendo.com/2.0.0/users/me --connector nintendo-store
613
- zero doctor check-connector --url https://slack.com/api/chat.postMessage --method POST
614
- zero doctor check-connector --env-name SLACK_TOKEN --check-permission chat:write
671
+ zero connector check --env-name GITHUB_TOKEN
672
+ zero connector check --url https://api.github.com/repos/owner/repo
673
+ zero connector check --url https://api.accounts.nintendo.com/2.0.0/users/me --connector nintendo-store
674
+ zero connector check --url https://slack.com/api/chat.postMessage --method POST
675
+ zero connector check --env-name SLACK_TOKEN --check-permission chat:write
615
676
 
616
677
  How connectors work:
617
678
  A Connector holds the real credentials for an external service. These credentials
@@ -623,6 +684,10 @@ How connectors work:
623
684
  ).action(
624
685
  withErrorHandler(async (opts, command) => {
625
686
  validateCheckConnectorOptions(opts, command);
687
+ if (isComputerUseCheckTarget(opts)) {
688
+ printComputerUsePermissionGuidance();
689
+ return;
690
+ }
626
691
  const method = opts.method.toUpperCase();
627
692
  const request = buildDiagnosticRequest(opts, method);
628
693
  const diagnostic = await diagnoseZeroConnectorCheck(request);
@@ -665,254 +730,522 @@ How connectors work:
665
730
  })
666
731
  );
667
732
 
668
- // src/commands/zero/doctor/permission-deny.ts
669
- init_esm_shims();
670
-
671
- // src/commands/zero/doctor/computer-use-guidance.ts
733
+ // src/commands/zero/connector/connect.ts
672
734
  init_esm_shims();
673
- var COMPUTER_USE_CONNECTOR_REF = "computer-use";
674
- var COMPUTER_USE_CAPABILITY = "computer-use:write";
675
- var COMPUTER_USE_PATH_PREFIX = "/computer-use";
676
- var COMPUTER_USE_PATH_PREFIX_WITH_SLASH = `${COMPUTER_USE_PATH_PREFIX}/`;
677
- function isComputerUsePermissionTarget(target) {
678
- return target.connectorRef === COMPUTER_USE_CONNECTOR_REF || target.permission === COMPUTER_USE_CAPABILITY || target.path === COMPUTER_USE_PATH_PREFIX || target.path?.startsWith(COMPUTER_USE_PATH_PREFIX_WITH_SLASH) === true;
735
+ function collectValue(value, previous) {
736
+ return [...previous, value];
679
737
  }
680
- function printComputerUsePermissionGuidance() {
681
- console.log("Computer Use access is not managed as a connector permission.");
682
- console.log(
683
- "The current run token needs computer-use:write, which is issued only when a Zero Desktop Computer Use host is selected for the chat or thread before the run starts."
684
- );
685
- console.log(
686
- "Open Zero Desktop, make sure Computer Use is online, select the Computer Use host for this chat/thread, then start a new run. Existing run tokens cannot be upgraded in place."
687
- );
688
- console.log(
689
- "Run `zero whoami` to confirm whether the current ZERO_TOKEN includes computer-use:write."
690
- );
738
+ function parseConnectorValues(rawValues) {
739
+ if (!rawValues || rawValues.length === 0) {
740
+ throw new Error("At least one --value NAME=VALUE is required", {
741
+ cause: new Error(
742
+ "Example: zero connector connect zendesk --value apiToken=token"
743
+ )
744
+ });
745
+ }
746
+ const values = {};
747
+ for (const rawValue of rawValues) {
748
+ const separatorIndex = rawValue.indexOf("=");
749
+ if (separatorIndex <= 0) {
750
+ throw new Error("Invalid --value format", {
751
+ cause: new Error("Use --value NAME=VALUE")
752
+ });
753
+ }
754
+ const name = rawValue.slice(0, separatorIndex);
755
+ if (!name.trim()) {
756
+ throw new Error("Invalid --value format", {
757
+ cause: new Error("Field name cannot be empty")
758
+ });
759
+ }
760
+ values[name] = rawValue.slice(separatorIndex + 1);
761
+ }
762
+ return values;
691
763
  }
764
+ var connectCommand = new Command().name("connect").description("Connect a connector with manual grant values").argument("<type>", "Connector type (e.g., zendesk)").option("--auth-method <method>", "Connector auth method to use").option(
765
+ "--value <name=value>",
766
+ "Connector field value; repeat for multiple fields",
767
+ collectValue,
768
+ []
769
+ ).option("--json", "Print the connector response as JSON").action(
770
+ withErrorHandler(async (type, options) => {
771
+ const values = parseConnectorValues(options.value);
772
+ const catalog = await listZeroConnectorCatalogStatus();
773
+ const connectorMetadata = findConnectorStatusItem(
774
+ catalog.connectors,
775
+ type
776
+ );
777
+ if (!connectorMetadata) {
778
+ throw new Error(`Unknown or unavailable connector: ${type}`, {
779
+ cause: new Error(
780
+ `Available connectors: ${availableConnectorRefs(catalog.connectors)}`
781
+ )
782
+ });
783
+ }
784
+ const authMethod = resolveManualGrantAuthMethod(
785
+ connectorMetadata,
786
+ options.authMethod
787
+ );
788
+ const connector = await connectZeroConnectorManualGrant(
789
+ connectorMetadata.connectorRef,
790
+ authMethod.id,
791
+ values
792
+ );
793
+ if (options.json) {
794
+ console.log(JSON.stringify(connector, null, 2));
795
+ return;
796
+ }
797
+ console.log(source_default.green(`\u2713 ${connectorMetadata.label} connected`));
798
+ console.log(source_default.dim(` Type: ${connector.type}`));
799
+ console.log(source_default.dim(` Auth Method: ${connector.authMethod}`));
800
+ console.log(source_default.dim(` Run: zero connector status ${connector.type}`));
801
+ })
802
+ );
692
803
 
693
- // src/commands/zero/doctor/permission-deny.ts
694
- var VALID_DENIED_METHODS = /* @__PURE__ */ new Set([
695
- "GET",
696
- "POST",
697
- "PUT",
698
- "PATCH",
699
- "DELETE",
700
- "HEAD",
701
- "OPTIONS"
702
- ]);
703
- function unknownPermissionChangeCommand2(connectorRef) {
704
- return `zero doctor permission-change ${connectorRef} --permission ${UNKNOWN_PERMISSION_GRANT} --enable --duration 1h`;
705
- }
706
- function pathOnlyError() {
707
- return new Error(
708
- "permission-deny now requires --url because method/path alone can match the wrong API base."
709
- );
710
- }
711
- function invalidUrlError() {
712
- return new Error(
713
- "permission-deny requires --url to be a valid absolute http or https URL."
714
- );
715
- }
716
- function invalidMethodError() {
717
- return new Error(
718
- "permission-deny requires --method to be one of GET, POST, PUT, PATCH, DELETE, HEAD, or OPTIONS."
719
- );
720
- }
721
- function unsafePathError() {
722
- return new Error(
723
- "permission-deny cannot diagnose unsafe URL paths because they are blocked before permission policy evaluation."
724
- );
725
- }
726
- function parseDeniedMethod(method) {
727
- const upperMethod = method.toUpperCase();
728
- if (!VALID_DENIED_METHODS.has(upperMethod)) {
729
- throw invalidMethodError();
804
+ // src/commands/zero/connector/list.ts
805
+ init_esm_shims();
806
+
807
+ // src/commands/zero/connector/connected-as.ts
808
+ init_esm_shims();
809
+ function renderIdentity(connector) {
810
+ if (connector.connection?.externalUsername) {
811
+ return `@${connector.connection.externalUsername}`;
730
812
  }
731
- return upperMethod;
813
+ if (connector.connection?.externalEmail)
814
+ return connector.connection.externalEmail;
815
+ return "-";
732
816
  }
733
- function rawAuthorityFromDeniedUrl(url) {
734
- const schemeEnd = url.indexOf("://");
735
- if (schemeEnd === -1) return null;
736
- const authorityStart = schemeEnd + 3;
737
- let authorityEnd = url.length;
738
- for (const delimiter of ["/", "?", "#"]) {
739
- const index = url.indexOf(delimiter, authorityStart);
740
- if (index !== -1) authorityEnd = Math.min(authorityEnd, index);
817
+ function renderConnectedAsCell(connector) {
818
+ if (!connector || connector.connectionStatus === "not-connected") {
819
+ return source_default.dim("(not connected)");
741
820
  }
742
- return url.slice(authorityStart, authorityEnd);
743
- }
744
- function rawAuthorityHasUnsafeSyntax(url) {
745
- const authority = rawAuthorityFromDeniedUrl(url);
746
- if (authority === null) return false;
747
- return authority === "" || authority.includes("\\") || authority.includes("%") || [...authority].some((char) => {
748
- return char.charCodeAt(0) > 127;
749
- });
750
- }
751
- function validateDeniedUrl(url) {
752
- if (!url.includes("://") || /\s/.test(url) || rawAuthorityHasUnsafeSyntax(url)) {
753
- throw invalidUrlError();
821
+ const identity = renderIdentity(connector);
822
+ if (connector.connectionStatus === "reconnect-required") {
823
+ return source_default.yellow(`${identity} (reconnect needed)`);
754
824
  }
755
- try {
756
- const parsed = new URL(url);
757
- if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
758
- throw invalidUrlError();
759
- }
760
- if (parsed.username !== "" || parsed.password !== "") {
761
- throw invalidUrlError();
762
- }
763
- } catch {
764
- throw invalidUrlError();
825
+ if (connector.scopeMismatch || connector.connectionStatus === "scope-mismatch") {
826
+ return source_default.yellow(`${identity} (permissions update available)`);
765
827
  }
828
+ return identity;
766
829
  }
767
- function stripUrlQueryAndFragment2(url) {
768
- const queryIndex = url.indexOf("?");
769
- const fragmentIndex = url.indexOf("#");
770
- let end = url.length;
771
- if (queryIndex !== -1) end = Math.min(end, queryIndex);
772
- if (fragmentIndex !== -1) end = Math.min(end, fragmentIndex);
773
- return url.slice(0, end);
830
+ var ESC = "\x1B";
831
+ var ANSI_PATTERN = new RegExp(`${ESC}\\[[0-9;]*m`, "g");
832
+ function stripAnsi(s) {
833
+ return s.replace(ANSI_PATTERN, "");
774
834
  }
775
- function rawPathFromDeniedUrl(url) {
776
- const urlWithoutQuery = stripUrlQueryAndFragment2(url);
777
- const schemeEnd = urlWithoutQuery.indexOf("://");
778
- const authorityStart = schemeEnd === -1 ? 0 : schemeEnd + 3;
779
- const pathStart = urlWithoutQuery.indexOf("/", authorityStart);
780
- return pathStart === -1 ? "/" : urlWithoutQuery.slice(pathStart);
835
+ function padEndAnsi(s, width) {
836
+ const visible = stripAnsi(s).length;
837
+ return s + " ".repeat(Math.max(0, width - visible));
781
838
  }
782
- function printPermissionChangeGuidance(connectorRef, permissions) {
783
- const sortedPermissions = [...permissions].sort();
784
- if (sortedPermissions.length === 1) {
785
- const permission = sortedPermissions[0];
786
- console.log(`This is covered by the "${permission}" permission.`);
839
+
840
+ // src/commands/zero/connector/list.ts
841
+ var listCommand = new Command().name("list").alias("ls").description("List all connectors and their status").option("--agent <id>", "Show per-agent authorization column").action(
842
+ withErrorHandler(async (options) => {
843
+ const [{ connectors }, agentCtx] = await Promise.all([
844
+ listZeroConnectorCatalogStatus(),
845
+ resolveAgentContext(options.agent)
846
+ ]);
847
+ const allTypes = connectors.map((connector) => {
848
+ return connector.connectorRef;
849
+ });
850
+ const typeWidth = Math.max(
851
+ 4,
852
+ ...allTypes.map((t) => {
853
+ return t.length;
854
+ })
855
+ );
856
+ const connectedAsHeader = "CONNECTED AS";
857
+ const connectedCells = connectors.map((connector) => {
858
+ return renderConnectedAsCell(connector);
859
+ });
860
+ const connectedAsWidth = Math.max(
861
+ connectedAsHeader.length,
862
+ ...connectedCells.map((c) => {
863
+ return stripAnsi(c).length;
864
+ })
865
+ );
866
+ const authorizedHeader = agentCtx ? `AUTHORIZED FOR ${agentCtx.displayName}` : null;
867
+ const headerParts = [
868
+ "TYPE".padEnd(typeWidth),
869
+ connectedAsHeader.padEnd(connectedAsWidth)
870
+ ];
871
+ if (authorizedHeader) headerParts.push(authorizedHeader);
872
+ console.log(source_default.dim(headerParts.join(" ")));
873
+ for (let i = 0; i < allTypes.length; i++) {
874
+ const type = allTypes[i];
875
+ const connectedCell = padEndAnsi(connectedCells[i], connectedAsWidth);
876
+ const parts = [type.padEnd(typeWidth), connectedCell];
877
+ if (agentCtx) {
878
+ parts.push(
879
+ agentCtx.authorizedTypes.has(type) ? source_default.green("\u2713") : source_default.dim("-")
880
+ );
881
+ }
882
+ console.log(parts.join(" "));
883
+ }
884
+ })
885
+ );
886
+
887
+ // src/commands/zero/connector/search.ts
888
+ init_esm_shims();
889
+ var DEFAULT_LIMIT = 5;
890
+ var EXACT_MATCH_THRESHOLD = 80;
891
+ function parseLimit(raw) {
892
+ const trimmed = raw.trim();
893
+ const n = Number(trimmed);
894
+ if (!/^\d+$/.test(trimmed) || !Number.isSafeInteger(n) || n <= 0) {
895
+ throw new Error(`--limit must be a positive integer, got "${raw}".`);
896
+ }
897
+ return n;
898
+ }
899
+ var searchCommand = new Command().name("search").description(
900
+ "Search connectors by type, label, category, generation type, or tag"
901
+ ).argument("<keyword>", "Search keyword (case-insensitive)").option("--agent <id>", "Show per-agent authorization column").option(
902
+ "--limit <n>",
903
+ `Maximum number of results to display (default ${DEFAULT_LIMIT})`,
904
+ parseLimit,
905
+ DEFAULT_LIMIT
906
+ ).action(
907
+ withErrorHandler(
908
+ async (keyword, options) => {
909
+ const trimmed = keyword.trim();
910
+ if (!trimmed) {
911
+ throw new Error("Keyword cannot be empty.");
912
+ }
913
+ const [{ connectors }, agentCtx] = await Promise.all([
914
+ listZeroConnectorCatalogStatus(),
915
+ resolveAgentContext(options.agent)
916
+ ]);
917
+ const { results, total } = searchPublicConnectorCatalog(
918
+ connectors,
919
+ trimmed,
920
+ options.limit
921
+ );
922
+ if (results.length === 0) {
923
+ console.log("No matches found.");
924
+ return;
925
+ }
926
+ const topScore = results[0].score;
927
+ if (topScore < EXACT_MATCH_THRESHOLD) {
928
+ console.log("No exact match. Showing closest:");
929
+ }
930
+ if (total > options.limit) {
931
+ console.log(`Too many results (top ${options.limit} of ${total}):`);
932
+ }
933
+ const typeHeader = "TYPE";
934
+ const connectedAsHeader = "CONNECTED AS";
935
+ const connectedCells = results.map((r) => {
936
+ return renderConnectedAsCell(r.connector);
937
+ });
938
+ const typeWidth = Math.max(
939
+ typeHeader.length,
940
+ ...results.map((r) => {
941
+ return r.connector.connectorRef.length;
942
+ })
943
+ );
944
+ const connectedAsWidth = Math.max(
945
+ connectedAsHeader.length,
946
+ ...connectedCells.map((c) => {
947
+ return stripAnsi(c).length;
948
+ })
949
+ );
950
+ const headerParts = [
951
+ typeHeader.padEnd(typeWidth),
952
+ connectedAsHeader.padEnd(connectedAsWidth)
953
+ ];
954
+ if (agentCtx) {
955
+ headerParts.push(`AUTHORIZED FOR ${agentCtx.displayName}`);
956
+ }
957
+ console.log(source_default.dim(headerParts.join(" ")));
958
+ for (let i = 0; i < results.length; i++) {
959
+ const result = results[i];
960
+ const parts = [
961
+ result.connector.connectorRef.padEnd(typeWidth),
962
+ padEndAnsi(connectedCells[i], connectedAsWidth)
963
+ ];
964
+ if (agentCtx) {
965
+ parts.push(
966
+ agentCtx.authorizedTypes.has(result.connector.connectorRef) ? source_default.green("\u2713") : source_default.dim("-")
967
+ );
968
+ }
969
+ console.log(parts.join(" "));
970
+ }
971
+ }
972
+ )
973
+ );
974
+
975
+ // src/commands/zero/connector/status.ts
976
+ init_esm_shims();
977
+ var LABEL_WIDTH = 16;
978
+ function printConnectorDetails(connector) {
979
+ if (connector.connectionStatus === "not-connected") {
787
980
  console.log(
788
- `To allow this permission, run: zero doctor permission-change ${connectorRef} --permission ${permission} --enable --duration 1h`
981
+ `${"Status:".padEnd(LABEL_WIDTH)}${source_default.dim("not connected")}`
789
982
  );
790
983
  return;
791
984
  }
792
985
  console.log(
793
- `This is covered by these permissions: ${sortedPermissions.join(", ")}.`
986
+ `${"Status:".padEnd(LABEL_WIDTH)}${connector.connectionStatus === "reconnect-required" ? source_default.yellow("reconnect needed") : source_default.green("connected")}`
794
987
  );
795
- for (const permission of sortedPermissions) {
988
+ if (connector.connection?.externalUsername) {
989
+ console.log(
990
+ `${"Account:".padEnd(LABEL_WIDTH)}@${connector.connection.externalUsername}`
991
+ );
992
+ } else if (connector.connection?.externalEmail) {
993
+ console.log(
994
+ `${"Account:".padEnd(LABEL_WIDTH)}${connector.connection.externalEmail}`
995
+ );
996
+ }
997
+ if (connector.connection?.authMethod) {
796
998
  console.log(
797
- `To allow ${permission}, run: zero doctor permission-change ${connectorRef} --permission ${permission} --enable --duration 1h`
999
+ `${"Auth Method:".padEnd(LABEL_WIDTH)}${connector.connection.authMethod}`
1000
+ );
1001
+ }
1002
+ if (connector.scopeMismatch) {
1003
+ console.log(
1004
+ `${"Permissions:".padEnd(LABEL_WIDTH)}${source_default.yellow("update available")}`
1005
+ );
1006
+ }
1007
+ if (connector.tokenExpiresAt) {
1008
+ console.log(
1009
+ `${"Token Expires:".padEnd(LABEL_WIDTH)}${connector.tokenExpiresAt}`
798
1010
  );
799
1011
  }
800
1012
  }
801
- function printFilteredRequest(label, method, relativePath, base) {
802
- console.log(
803
- `The ${label} permission filtered ${method} ${relativePath} relative to base URL ${base}.`
804
- );
1013
+ async function printAgentAction(connector, agentCtx) {
1014
+ const connectorRef = connector.connectorRef;
1015
+ const authorized = agentCtx.authorizedTypes.has(connectorRef);
1016
+ const isConnected = connector.connected;
1017
+ const needsReconnect = connector.connectionStatus === "reconnect-required";
1018
+ const agentLabel = agentCtx.displayName === agentCtx.agentId ? agentCtx.agentId : `${agentCtx.displayName} (${agentCtx.agentId})`;
1019
+ console.log();
1020
+ if (needsReconnect) {
1021
+ const origin = await getPlatformOrigin();
1022
+ const url = `${origin}/connectors`;
1023
+ console.log(
1024
+ `The ${connectorRef} connector is connected but needs to be reconnected before agent ${agentLabel} can use it.`
1025
+ );
1026
+ console.log(`Reconnect it at: [Reconnect ${connectorRef}](${url})`);
1027
+ } else if (authorized && !isConnected) {
1028
+ const origin = await getPlatformOrigin();
1029
+ const url = `${origin}/connectors/${connectorRef}/connect?agentId=${agentCtx.agentId}`;
1030
+ console.log(
1031
+ `The ${connectorRef} connector is authorized for agent ${agentLabel}, but it is not connected.`
1032
+ );
1033
+ console.log(`Connect it at: [Connect ${connectorRef}](${url})`);
1034
+ } else if (authorized) {
1035
+ console.log(
1036
+ `The ${connectorRef} connector is authorized for agent ${agentLabel}.`
1037
+ );
1038
+ } else if (!isConnected) {
1039
+ const origin = await getPlatformOrigin();
1040
+ const url = `${origin}/connectors/${connectorRef}/connect?agentId=${agentCtx.agentId}`;
1041
+ console.log(
1042
+ `The ${connectorRef} connector is not connected. Once connected, it will be authorized for agent ${agentLabel}.`
1043
+ );
1044
+ console.log(
1045
+ `Connect and authorize it at: [Connect ${connectorRef}](${url})`
1046
+ );
1047
+ } else {
1048
+ const origin = await getPlatformOrigin();
1049
+ const url = `${origin}/connectors/${connectorRef}/authorize?agentId=${agentCtx.agentId}`;
1050
+ console.log(
1051
+ `The ${connectorRef} connector is not authorized for agent ${agentLabel}.`
1052
+ );
1053
+ console.log(`Authorize it at: [Authorize ${connectorRef}](${url})`);
1054
+ }
805
1055
  }
806
- function unsafeInputError2(reason) {
807
- switch (reason) {
808
- case "invalid-method":
809
- return invalidMethodError();
810
- case "invalid-url":
811
- return invalidUrlError();
812
- case "unsafe-path":
813
- return unsafePathError();
1056
+ async function printStandaloneAction(connector) {
1057
+ const connectorRef = connector.connectorRef;
1058
+ if (connector.connectionStatus === "connected" || connector.connectionStatus === "scope-mismatch") {
1059
+ return;
1060
+ }
1061
+ const origin = await getPlatformOrigin();
1062
+ console.log();
1063
+ if (connector.connectionStatus === "reconnect-required") {
1064
+ const url = `${origin}/connectors`;
1065
+ console.log(
1066
+ `The ${connectorRef} connector is connected but needs to be reconnected.`
1067
+ );
1068
+ console.log(`Reconnect it at: [Reconnect ${connectorRef}](${url})`);
1069
+ } else {
1070
+ const url = `${origin}/connectors/${connectorRef}/connect`;
1071
+ console.log(`Connect it at: [Connect ${connectorRef}](${url})`);
814
1072
  }
815
1073
  }
816
- function handleDiagnosticResult(connectorRef, method, result) {
817
- switch (result.outcome) {
818
- case "matched":
819
- printFilteredRequest(
820
- result.label,
821
- method,
822
- result.relativePath,
823
- result.base
824
- );
825
- printPermissionChangeGuidance(connectorRef, result.permissions);
826
- return;
827
- case "unknown-endpoint":
828
- printFilteredRequest(
829
- result.label,
830
- method,
831
- result.relativePath,
832
- result.base
833
- );
834
- console.log("No named permission was found covering this request.");
835
- console.log("This request is governed by the unknown endpoint policy.");
1074
+ var statusCommand = 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(
1075
+ withErrorHandler(async (type, options) => {
1076
+ const [catalog, agentCtx] = await Promise.all([
1077
+ listZeroConnectorCatalogStatus(),
1078
+ resolveAgentContext(options.agent)
1079
+ ]);
1080
+ const connector = findConnectorStatusItem(catalog.connectors, type);
1081
+ if (!connector) {
1082
+ throw new Error(`Unknown or unavailable connector: ${type}`, {
1083
+ cause: new Error(
1084
+ `Available connectors: ${availableConnectorRefs(catalog.connectors)}`
1085
+ )
1086
+ });
1087
+ }
1088
+ console.log(`Connector: ${source_default.cyan(connector.connectorRef)}`);
1089
+ console.log();
1090
+ printConnectorDetails(connector);
1091
+ if (agentCtx) {
1092
+ await printAgentAction(connector, agentCtx);
1093
+ } else {
1094
+ await printStandaloneAction(connector);
1095
+ }
1096
+ })
1097
+ );
1098
+
1099
+ // src/commands/zero/connector/custom/index.ts
1100
+ init_esm_shims();
1101
+ import { readFile } from "fs/promises";
1102
+ var LABEL_WIDTH2 = 18;
1103
+ function renderConnected(connector) {
1104
+ if (connector.connected) {
1105
+ return source_default.green("connected");
1106
+ }
1107
+ if (connector.missingRequiredFields.length === 0) {
1108
+ return source_default.dim("not connected");
1109
+ }
1110
+ return source_default.yellow(`missing ${connector.missingRequiredFields.join(", ")}`);
1111
+ }
1112
+ function encodeBase64UrlJson(value) {
1113
+ return Buffer.from(JSON.stringify(value), "utf8").toString("base64url");
1114
+ }
1115
+ function isJsonObject(value) {
1116
+ return typeof value === "object" && value !== null && !Array.isArray(value);
1117
+ }
1118
+ async function resolveCustomAgentContext(agentId) {
1119
+ const resolvedAgentId = agentId ?? process.env.ZERO_AGENT_ID;
1120
+ if (!resolvedAgentId) {
1121
+ return null;
1122
+ }
1123
+ const [agent, enabledIds] = await Promise.all([
1124
+ getZeroAgent(resolvedAgentId),
1125
+ getZeroAgentCustomConnectors(resolvedAgentId)
1126
+ ]);
1127
+ return {
1128
+ agentId: agent.agentId,
1129
+ displayName: agent.displayName ?? agent.agentId,
1130
+ authorizedIds: new Set(enabledIds)
1131
+ };
1132
+ }
1133
+ var listCommand2 = new Command().name("list").alias("ls").description("List org custom connectors").option("--agent <id>", "Show per-agent authorization column").action(
1134
+ withErrorHandler(async (options) => {
1135
+ const [connectors, agentCtx] = await Promise.all([
1136
+ listZeroCustomConnectors(),
1137
+ resolveCustomAgentContext(options.agent)
1138
+ ]);
1139
+ const idWidth = Math.max(
1140
+ 2,
1141
+ ...connectors.map((connector) => {
1142
+ return connector.id.length;
1143
+ })
1144
+ );
1145
+ const nameWidth = Math.max(
1146
+ 4,
1147
+ ...connectors.map((connector) => {
1148
+ return connector.displayName.length;
1149
+ })
1150
+ );
1151
+ const header = ["ID".padEnd(idWidth), "NAME".padEnd(nameWidth), "STATUS"];
1152
+ if (agentCtx) {
1153
+ header.push(`AUTHORIZED FOR ${agentCtx.displayName}`);
1154
+ }
1155
+ console.log(source_default.dim(header.join(" ")));
1156
+ for (const connector of connectors) {
1157
+ const row = [
1158
+ connector.id.padEnd(idWidth),
1159
+ connector.displayName.padEnd(nameWidth),
1160
+ renderConnected(connector)
1161
+ ];
1162
+ if (agentCtx) {
1163
+ row.push(
1164
+ agentCtx.authorizedIds.has(connector.id) ? source_default.green("\u2713") : source_default.dim("-")
1165
+ );
1166
+ }
1167
+ console.log(row.join(" "));
1168
+ }
1169
+ })
1170
+ );
1171
+ var statusCommand2 = new Command().name("status").description("Show detailed status of a custom connector").argument("<connector-id>", "Custom connector id").option("--agent <id>", "Show authorization state for the given agent").action(
1172
+ withErrorHandler(
1173
+ async (connectorId, options) => {
1174
+ const [connector, agentCtx] = await Promise.all([
1175
+ getZeroCustomConnector(connectorId),
1176
+ resolveCustomAgentContext(options.agent)
1177
+ ]);
1178
+ if (!connector) {
1179
+ throw new Error(`Custom connector not found: ${connectorId}`);
1180
+ }
1181
+ console.log(`Custom connector: ${source_default.cyan(connector.displayName)}`);
1182
+ console.log();
1183
+ console.log(`${"ID:".padEnd(LABEL_WIDTH2)}${connector.id}`);
836
1184
  console.log(
837
- `To allow unknown endpoints, run: ${unknownPermissionChangeCommand2(connectorRef)}`
1185
+ `${"Status:".padEnd(LABEL_WIDTH2)}${renderConnected(connector)}`
838
1186
  );
839
- return;
840
- case "unknown-connector":
841
- throw new Error(`Unknown connector type: ${connectorRef}`);
842
- case "no-matching-base":
843
- throw new Error(
844
- `No registered ${result.label} base URL matches the provided URL.`
1187
+ console.log(
1188
+ `${"Prefixes:".padEnd(LABEL_WIDTH2)}${connector.prefixTemplates.join(", ")}`
845
1189
  );
846
- case "unresolved-dynamic-base":
847
- throw new Error(
848
- `No authoritative ${result.label} base URL is available for this diagnostic. Verify the ${connectorRef} connector configuration for the affected context and retry.`
1190
+ console.log(
1191
+ `${"Fields:".padEnd(LABEL_WIDTH2)}${connector.fields.map((field) => {
1192
+ return `${field.kind}:${field.key}${field.required ? "" : "?"}`;
1193
+ }).join(", ")}`
849
1194
  );
850
- case "unsafe-input":
851
- throw unsafeInputError2(result.reason);
852
- }
853
- const exhaustiveResult = result;
854
- return exhaustiveResult;
855
- }
856
- var permissionDenyCommand = new Command().name("permission-deny").description(
857
- "Diagnose a permission denial and find the permission that covers it"
858
- ).argument("<connector-ref>", "The connector type (e.g. github)").addOption(
859
- new Option(
860
- "--method <method>",
861
- "The denied HTTP method"
862
- ).makeOptionMandatory()
863
- ).addOption(
864
- new Option(
865
- "--url <url>",
866
- "The denied request URL; query strings are ignored (required)"
867
- )
868
- ).addOption(new Option("--path <path>", "Deprecated: use --url").hideHelp()).addHelpText(
869
- "after",
870
- `
871
- Examples:
872
- zero doctor permission-deny github --method GET --url https://api.github.com/repos/owner/repo/pulls
873
- zero doctor permission-deny slack --method POST --url https://slack.com/api/chat.postMessage
874
- zero doctor permission-deny youtube --method PUT --url https://youtube.googleapis.com/upload/youtube/v3/videos
875
-
876
- Notes:
877
- - Identifies which named permission covers a denied request
878
- - If the firewall denial response includes a url field, pass that value to --url
879
- - Requires the denied URL origin and path because method/path alone can match the wrong API base
880
- - Query strings and fragments are ignored for matching; omit them when they may contain secrets
881
- - Use permission-change to request or enable the permission
882
- - Permission-change enable requests default to --duration 1h; pick 24h, 7d, or always only when appropriate`
883
- ).action(
884
- withErrorHandler(
885
- async (connectorRef, opts) => {
886
- if (opts.path !== void 0) {
887
- throw pathOnlyError();
1195
+ if (connector.headerInjections.length > 0) {
1196
+ console.log(
1197
+ `${"Headers:".padEnd(LABEL_WIDTH2)}${connector.headerInjections.map((header) => {
1198
+ return header.name;
1199
+ }).join(", ")}`
1200
+ );
888
1201
  }
889
- if (!opts.url) {
890
- throw pathOnlyError();
1202
+ if (connector.queryInjections.length > 0) {
1203
+ console.log(
1204
+ `${"Query params:".padEnd(LABEL_WIDTH2)}${connector.queryInjections.map((query) => {
1205
+ return query.name;
1206
+ }).join(", ")}`
1207
+ );
891
1208
  }
892
- const method = parseDeniedMethod(opts.method);
893
- validateDeniedUrl(opts.url);
894
- const deniedPath = rawPathFromDeniedUrl(opts.url);
895
- if (hasUnsafeFirewallPath(deniedPath)) {
896
- throw unsafePathError();
1209
+ if (agentCtx) {
1210
+ console.log(
1211
+ `${"Authorized:".padEnd(LABEL_WIDTH2)}${agentCtx.authorizedIds.has(connector.id) ? source_default.green("yes") : source_default.yellow("no")}`
1212
+ );
897
1213
  }
898
- if (isComputerUsePermissionTarget({
899
- connectorRef,
900
- path: deniedPath
901
- })) {
902
- printComputerUsePermissionGuidance();
903
- return;
1214
+ }
1215
+ )
1216
+ );
1217
+ var proposeCommand = new Command().name("propose").description("Create a browser save link for a custom connector proposal").requiredOption("--proposal-file <path>", "JSON proposal file").option("--connector-id <id>", "Override connector id for update proposals").option("--agent <id>", "Authorize this agent when the proposal is saved").action(
1218
+ withErrorHandler(
1219
+ async (options) => {
1220
+ const raw = await readFile(options.proposalFile, "utf8");
1221
+ const proposalJson = JSON.parse(raw);
1222
+ if (!isJsonObject(proposalJson)) {
1223
+ throw new Error("Proposal file must contain a JSON object");
904
1224
  }
905
- const result = await diagnoseZeroConnectorPermissionDeny(
906
- connectorRef,
907
- method,
908
- stripUrlQueryAndFragment2(opts.url)
1225
+ const parsed = customConnectorProposalSchema.parse({
1226
+ ...proposalJson,
1227
+ ...options.connectorId ? { connectorId: options.connectorId } : {}
1228
+ });
1229
+ const origin = await getPlatformOrigin();
1230
+ const params = new URLSearchParams({
1231
+ p: encodeBase64UrlJson(parsed)
1232
+ });
1233
+ const agentId = options.agent ?? process.env.ZERO_AGENT_ID;
1234
+ if (agentId) {
1235
+ params.set("agentId", agentId);
1236
+ }
1237
+ const url = `${origin}/connectors/custom/proposal?${params.toString()}`;
1238
+ console.log(`[Configure ${parsed.displayName}](${url})`);
1239
+ console.log();
1240
+ console.log(
1241
+ "Open this link to review, save values, and authorize the connector."
909
1242
  );
910
- handleDiagnosticResult(connectorRef, method, result);
911
1243
  }
912
1244
  )
913
1245
  );
1246
+ var customConnectorCommand = new Command().name("custom").description("Inspect and propose org custom connectors").addCommand(listCommand2).addCommand(statusCommand2).addCommand(proposeCommand);
914
1247
 
915
- // src/commands/zero/doctor/permission-change.ts
1248
+ // src/commands/zero/connector/permission-request.ts
916
1249
  init_esm_shims();
917
1250
  var DEFAULT_PERMISSION_GRANT_DURATION = "1h";
918
1251
  var PERMISSION_GRANT_DURATIONS = [
@@ -924,8 +1257,7 @@ var PERMISSION_GRANT_DURATIONS = [
924
1257
  function permissionDescription(permission) {
925
1258
  return permission === UNKNOWN_PERMISSION_GRANT ? "unknown endpoints" : `the "${permission}" permission`;
926
1259
  }
927
- function printSensitivePermissionGuidance(connectorRef, permission, action) {
928
- if (action !== "enable") return;
1260
+ function printSensitivePermissionGuidance(connectorRef, permission) {
929
1261
  if (connectorRef === "slack" && permission === "chat:write") {
930
1262
  console.log("");
931
1263
  console.log(
@@ -953,16 +1285,13 @@ function printSensitivePermissionGuidance(connectorRef, permission, action) {
953
1285
  console.log("");
954
1286
  }
955
1287
  }
956
- function printPermissionActionMessage(args) {
957
- const grantAction = args.action === "enable" ? "allow" : "deny";
1288
+ function printPermissionRequestMessage(args) {
958
1289
  console.log(
959
- `You can ${grantAction} ${permissionDescription(args.permission)} for your connector access: [Manage ${args.label} permissions](${args.url})`
1290
+ `You can allow ${permissionDescription(args.permission)} for your connector access: [Manage ${args.label} permissions](${args.url})`
1291
+ );
1292
+ console.log(
1293
+ `Requested duration: ${args.duration}. Use --duration 1h|24h|7d|always to choose a different grant lifetime.`
960
1294
  );
961
- if (args.duration) {
962
- console.log(
963
- `Requested duration: ${args.duration}. Use --duration 1h|24h|7d|always to choose a different grant lifetime.`
964
- );
965
- }
966
1295
  }
967
1296
  function printComputerUseAuthorizationLink(args) {
968
1297
  console.log(
@@ -976,11 +1305,7 @@ function printComputerUseAuthorizationLink(args) {
976
1305
  `This link expires at ${args.expiresAt}. Existing run tokens cannot be upgraded in place; start a new run after authorization.`
977
1306
  );
978
1307
  }
979
- async function printComputerUsePermissionChangeMessage(action) {
980
- if (action !== "enable") {
981
- printComputerUsePermissionGuidance();
982
- return;
983
- }
1308
+ async function printComputerUsePermissionRequestMessage() {
984
1309
  if (!process.env.ZERO_TOKEN) {
985
1310
  printComputerUsePermissionGuidance();
986
1311
  return;
@@ -1004,49 +1329,34 @@ async function printComputerUsePermissionChangeMessage(action) {
1004
1329
  printComputerUsePermissionGuidance();
1005
1330
  }
1006
1331
  }
1007
- async function outputPermissionChangeMessage(connectorRef, label, permission, action, duration, agentId) {
1332
+ async function outputPermissionRequestMessage(connectorRef, label, permission, duration, agentId) {
1008
1333
  const platformOrigin = await getPlatformOrigin();
1009
1334
  const urlParams = new URLSearchParams({
1010
1335
  ref: connectorRef,
1011
1336
  permission,
1012
- action: action === "enable" ? "allow" : "deny"
1337
+ action: "allow",
1338
+ expiresIn: duration
1013
1339
  });
1014
- if (action === "enable") {
1015
- urlParams.set("expiresIn", duration ?? DEFAULT_PERMISSION_GRANT_DURATION);
1016
- }
1017
1340
  const pagePath = agentId ? `/agents/${agentId}/permissions` : "/agents";
1018
1341
  const url = `${platformOrigin}${pagePath}?${urlParams.toString()}`;
1019
- printSensitivePermissionGuidance(connectorRef, permission, action);
1020
- printPermissionActionMessage({
1021
- action,
1342
+ printSensitivePermissionGuidance(connectorRef, permission);
1343
+ printPermissionRequestMessage({
1022
1344
  permission,
1023
1345
  label,
1024
1346
  url,
1025
- duration: action === "enable" ? duration ?? DEFAULT_PERMISSION_GRANT_DURATION : void 0
1347
+ duration
1026
1348
  });
1027
1349
  }
1028
- var permissionChangeCommand = new Command().name("permission-change").description("Change or request a permission (enable or disable)").argument("<connector-ref>", "The connector type (e.g. github)").addOption(
1350
+ var permissionRequestCommand2 = new Command().name("permission-request").description("Request permission to use a connector capability").argument("<connector-ref>", "The connector type (e.g. github)").addOption(
1029
1351
  new Option(
1030
1352
  "--permission <name>",
1031
- "The permission name to change"
1353
+ "The permission name to request"
1032
1354
  ).makeOptionMandatory()
1033
- ).addOption(
1034
- new Option(
1035
- "--enable",
1036
- "Enable or request enabling the permission"
1037
- ).conflicts("disable")
1038
- ).addOption(
1039
- new Option(
1040
- "--disable",
1041
- "Disable or request disabling the permission"
1042
- ).conflicts("enable")
1043
1355
  ).addOption(
1044
1356
  new Option(
1045
1357
  "--duration <duration>",
1046
- "Requested allow duration: 1h, 24h, 7d, or always (default: 1h)"
1047
- ).choices([...PERMISSION_GRANT_DURATIONS])
1048
- ).addOption(
1049
- new Option("--reason <text>", "Brief reason for the permission change")
1358
+ "Requested allow duration: 1h, 24h, 7d, or always"
1359
+ ).choices([...PERMISSION_GRANT_DURATIONS]).default(DEFAULT_PERMISSION_GRANT_DURATION)
1050
1360
  ).addOption(
1051
1361
  new Option(
1052
1362
  "--agent <id>",
@@ -1056,36 +1366,27 @@ var permissionChangeCommand = new Command().name("permission-change").descriptio
1056
1366
  "after",
1057
1367
  `
1058
1368
  Examples:
1059
- zero doctor permission-change github --permission contents:read --enable
1060
- zero doctor permission-change github --permission contents:write --enable --duration 24h
1061
- zero doctor permission-change gmail --permission messages.write --enable --agent <agent-id>
1062
- zero doctor permission-change slack --permission chat:write --disable
1063
- zero doctor permission-change cloudflare --permission __unknown__ --disable
1064
- zero doctor permission-change computer-use --permission computer-use:write --enable
1369
+ zero connector permission-request github --permission contents:read
1370
+ zero connector permission-request github --permission contents:write --duration 24h
1371
+ zero connector permission-request gmail --permission messages.write --agent <agent-id>
1372
+ zero connector permission-request cloudflare --permission __unknown__
1373
+ zero connector permission-request computer-use --permission computer-use:write
1065
1374
 
1066
1375
  Notes:
1067
- - Outputs a platform URL for the user to adjust the permission
1068
- - Use --permission __unknown__ to change unknown endpoint policy
1376
+ - Outputs a platform URL for the user to allow the permission
1377
+ - Use --permission __unknown__ to request access to unknown endpoints
1069
1378
  - Use --agent to request a permission for another agent; defaults to ZERO_AGENT_ID
1070
- - Enable requests default to --duration 1h; use 24h or 7d for longer user-approved work
1379
+ - Requests default to --duration 1h; use 24h or 7d for longer user-approved work
1071
1380
  - Use --duration always only when the user explicitly asks for persistent access
1072
- - Permission changes update the current user's connector grants`
1381
+ - Permission requests update the current user's connector grants after confirmation`
1073
1382
  ).action(
1074
1383
  withErrorHandler(
1075
1384
  async (connectorRef, opts) => {
1076
- if (!opts.enable && !opts.disable) {
1077
- throw new Error("Either --enable or --disable is required");
1078
- }
1079
- if (opts.disable && opts.duration !== void 0) {
1080
- throw new Error("--duration is only supported with --enable");
1081
- }
1082
1385
  if (isComputerUsePermissionTarget({
1083
1386
  connectorRef,
1084
1387
  permission: opts.permission
1085
1388
  })) {
1086
- await printComputerUsePermissionChangeMessage(
1087
- opts.enable ? "enable" : "disable"
1088
- );
1389
+ await printComputerUsePermissionRequestMessage();
1089
1390
  return;
1090
1391
  }
1091
1392
  const metadata = await getZeroConnectorCatalogPermissions(connectorRef);
@@ -1097,12 +1398,10 @@ Notes:
1097
1398
  `Unknown permission "${opts.permission}" for ${connectorRef}`
1098
1399
  );
1099
1400
  }
1100
- const action = opts.enable ? "enable" : "disable";
1101
- await outputPermissionChangeMessage(
1401
+ await outputPermissionRequestMessage(
1102
1402
  connectorRef,
1103
1403
  metadata.label,
1104
1404
  opts.permission,
1105
- action,
1106
1405
  opts.duration,
1107
1406
  opts.agent ?? process.env.ZERO_AGENT_ID
1108
1407
  );
@@ -1110,85 +1409,9 @@ Notes:
1110
1409
  )
1111
1410
  );
1112
1411
 
1113
- // src/commands/zero/doctor/credit.ts
1114
- init_esm_shims();
1115
- function memberName(member) {
1116
- const name = [member.firstName, member.lastName].filter(Boolean).join(" ");
1117
- return name ? `${name} <${member.email}>` : member.email;
1118
- }
1119
- var creditCommand = new Command().name("credit").description("Diagnose current organization credit and purchase access").action(
1120
- withErrorHandler(async () => {
1121
- const [org, billing, members] = await Promise.all([
1122
- getZeroOrg(),
1123
- getZeroBillingStatus(),
1124
- getZeroOrgMembers()
1125
- ]);
1126
- const admins = members.members.filter((member) => {
1127
- return member.role === "admin";
1128
- });
1129
- const isAdmin = members.role === "admin";
1130
- const canPurchaseCredits = isAdmin;
1131
- console.log(source_default.bold("Credit diagnostics:"));
1132
- console.log(` Org: ${source_default.green(org.slug)}`);
1133
- console.log(` Tier: ${source_default.cyan(billing.tier)}`);
1134
- console.log(
1135
- ` Available credits: ${source_default.cyan(billing.credits.toLocaleString())}`
1136
- );
1137
- console.log(` Current user role: ${source_default.cyan(members.role)}`);
1138
- console.log(
1139
- ` Can purchase credits: ${canPurchaseCredits ? source_default.green("yes") : source_default.yellow("no")}`
1140
- );
1141
- console.log(
1142
- ` Auto-recharge: ${billing.autoRecharge.enabled ? source_default.green("enabled") : "disabled"}`
1143
- );
1144
- if (billing.autoRecharge.enabled) {
1145
- console.log(
1146
- ` Threshold: ${billing.autoRecharge.threshold?.toLocaleString() ?? "not set"}`
1147
- );
1148
- console.log(
1149
- ` Amount: ${billing.autoRecharge.amount?.toLocaleString() ?? "not set"}`
1150
- );
1151
- }
1152
- if (!isAdmin) {
1153
- console.log(source_default.bold("\nOrganization admins:"));
1154
- for (const admin of admins) {
1155
- console.log(` - ${memberName(admin)}`);
1156
- }
1157
- console.log(
1158
- source_default.yellow(
1159
- "\nAsk an organization admin to buy credits or upgrade the plan."
1160
- )
1161
- );
1162
- } else if (billing.tier === "free") {
1163
- console.log(
1164
- "\nFree-tier admins can upgrade to Pro from billing or buy credits with `zero credit <credits>`."
1165
- );
1166
- } else {
1167
- console.log("\nUse `zero credit <credits>` to buy more credits.");
1168
- }
1169
- })
1170
- );
1171
-
1172
- // src/commands/zero/doctor/index.ts
1173
- var zeroDoctorCommand = new Command().name("doctor").description("Diagnose runtime issues (connector health, permission denials)").addCommand(checkConnectorCommand).addCommand(creditCommand).addCommand(permissionDenyCommand).addCommand(permissionChangeCommand).addHelpText(
1174
- "after",
1175
- `
1176
- Examples:
1177
- Check a connector? zero doctor check-connector --env-name GITHUB_TOKEN
1178
- Check a URL? zero doctor check-connector --url https://api.github.com/repos/owner/repo
1179
- Check credits? zero doctor credit
1180
- Check with permission? zero doctor check-connector --env-name SLACK_TOKEN --check-permission chat:write
1181
- Permission denied? zero doctor permission-deny github --method GET --url https://api.github.com/repos/owner/repo
1182
- Change a permission? zero doctor permission-change github --permission contents:read --enable --duration 1h
1183
- Disable unknown URLs? zero doctor permission-change cloudflare --permission __unknown__ --disable
1184
-
1185
- Notes:
1186
- - Use zero doctor credit when a run or generation fails because the org has insufficient credits, when a user asks how to recharge, or before trying to buy credits
1187
- - Use this when your task fails due to a missing connector environment name or permission denial
1188
- - Use zero generate <type> (no --prompt) to see every provider available for a given generation type
1189
- - The doctor will identify the issue and give the user a link to resolve it`
1190
- );
1412
+ // src/commands/zero/connector/index.ts
1413
+ var zeroConnectorCommand = new Command().name("connector").description("Manage and diagnose third-party service connections").addCommand(checkConnectorCommand).addCommand(customConnectorCommand).addCommand(connectCommand).addCommand(listCommand).addCommand(searchCommand).addCommand(statusCommand).addCommand(permissionRequestCommand2);
1191
1414
  export {
1192
- zeroDoctorCommand
1415
+ zeroConnectorCommand
1193
1416
  };
1194
- //# sourceMappingURL=doctor-PGH6KBWK.js.map
1417
+ //# sourceMappingURL=connector-ZRKGMLQV.js.map