@vm0/cli 9.241.9 → 9.241.11
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/{agent-YCTYPYF7.js → agent-5TLH3FMD.js} +5 -5
- package/{banking-RWPXPGOY.js → banking-NEAT4R24.js} +3 -3
- package/{chat-XWVVRA3Q.js → chat-F5Y4Y6W5.js} +4 -4
- package/{chunk-HYARATBX.js → chunk-6IPI5G2W.js} +2 -2
- package/{chunk-N55TLKMY.js → chunk-7D6TPEG2.js} +4 -4
- package/{chunk-G2NMGFMS.js → chunk-ICKIMZYL.js} +4 -4
- package/{chunk-XG3T3KKC.js → chunk-IEMQM5BQ.js} +3 -3
- package/chunk-IEMQM5BQ.js.map +1 -0
- package/{chunk-GJ2YK4RB.js → chunk-JRH7ZD2I.js} +2 -2
- package/{chunk-43Q6LJ4M.js → chunk-NTHQBG2C.js} +2 -2
- package/{chunk-D7WBYCFZ.js → chunk-PAGGGOFZ.js} +2 -2
- package/{chunk-JZD2ALHL.js → chunk-SP77SLW3.js} +3 -3
- package/{chunk-DCY7MYWI.js → chunk-XMPEXKMZ.js} +7 -7
- package/chunk-XMPEXKMZ.js.map +1 -0
- package/{chunk-PM36DYSC.js → chunk-YWMCF6SQ.js} +168 -312
- package/chunk-YWMCF6SQ.js.map +1 -0
- package/{computer-use-AJ4LM52W.js → computer-use-FEAAE6TT.js} +3 -3
- package/{doctor-PGH6KBWK.js → connector-CM3CYVJ2.js} +605 -382
- package/connector-CM3CYVJ2.js.map +1 -0
- package/{credit-QS7QUF3Q.js → credit-W2JFXIEE.js} +4 -4
- package/{developer-support-QIN7JTGZ.js → developer-support-3SNDQLPM.js} +3 -3
- package/doctor-JZIBQ63P.js +99 -0
- package/doctor-JZIBQ63P.js.map +1 -0
- package/{generate-VGPYBDHG.js → generate-VMDERMRQ.js} +4 -4
- package/{github-DBVCDROM.js → github-IAAPK3LA.js} +3 -3
- package/{goal-VZEI2OD2.js → goal-IYAHG7OD.js} +3 -3
- package/{host-35I2D3WT.js → host-Y6II7XUE.js} +3 -3
- package/index.js +12 -12
- package/index.js.map +1 -1
- package/{logs-SW5VAI54.js → logs-BPDKBOIG.js} +5 -5
- package/{mail-YYSSPGP2.js → mail-O6HOSHJN.js} +5 -5
- package/{maps-DIQSL73V.js → maps-N3INUZF2.js} +3 -3
- package/{model-ZFYWBWJ3.js → model-NOMWYJFY.js} +4 -4
- package/{model-provider-7MXIPGCL.js → model-provider-RZDEASD3.js} +4 -4
- package/{org-E2T6M6MN.js → org-47E2LF2E.js} +3 -3
- package/package.json +1 -1
- package/{phone-KKPDS6J3.js → phone-EZSBFUQY.js} +3 -3
- package/{preference-MUE7N3MZ.js → preference-3U5KKXQ5.js} +3 -3
- package/{resource-3HUMK4UE.js → resource-FHIP3W3L.js} +3 -3
- package/{scrape-HH5G742T.js → scrape-5LAKGGQN.js} +3 -3
- package/{search-JSTRJBHA.js → search-3TJZAERR.js} +6 -6
- package/search-3TJZAERR.js.map +1 -0
- package/{secret-PH5S7HXR.js → secret-CZE2VOBQ.js} +3 -3
- package/{slack-5HWY6WME.js → slack-XG2XYZD4.js} +3 -3
- package/{teams-DJVOFNO6.js → teams-SHZAOOYC.js} +3 -3
- package/{telegram-3IPXE4FT.js → telegram-5APDUFXW.js} +3 -3
- package/{variable-XC2BRIE4.js → variable-CJIIWMIX.js} +3 -3
- package/{video-SAEKMO5Q.js → video-BFST4YFU.js} +2 -2
- package/{web-GEEMEX3J.js → web-6H5BRLZF.js} +3 -3
- package/{web-search-DLAG55F2.js → web-search-WTPWZGHE.js} +3 -3
- package/{whoami-EPCOG5DN.js → whoami-KY2VJFW7.js} +5 -5
- package/{workflow-VS75PBYU.js → workflow-L5Z6BS5N.js} +3 -3
- package/zero.js +36 -36
- package/zero.js.map +1 -1
- package/chunk-DCY7MYWI.js.map +0 -1
- package/chunk-PM36DYSC.js.map +0 -1
- package/chunk-XG3T3KKC.js.map +0 -1
- package/connector-RBJZ3XJO.js +0 -559
- package/connector-RBJZ3XJO.js.map +0 -1
- package/doctor-PGH6KBWK.js.map +0 -1
- package/search-JSTRJBHA.js.map +0 -1
- /package/{agent-YCTYPYF7.js.map → agent-5TLH3FMD.js.map} +0 -0
- /package/{banking-RWPXPGOY.js.map → banking-NEAT4R24.js.map} +0 -0
- /package/{chat-XWVVRA3Q.js.map → chat-F5Y4Y6W5.js.map} +0 -0
- /package/{chunk-HYARATBX.js.map → chunk-6IPI5G2W.js.map} +0 -0
- /package/{chunk-N55TLKMY.js.map → chunk-7D6TPEG2.js.map} +0 -0
- /package/{chunk-G2NMGFMS.js.map → chunk-ICKIMZYL.js.map} +0 -0
- /package/{chunk-GJ2YK4RB.js.map → chunk-JRH7ZD2I.js.map} +0 -0
- /package/{chunk-43Q6LJ4M.js.map → chunk-NTHQBG2C.js.map} +0 -0
- /package/{chunk-D7WBYCFZ.js.map → chunk-PAGGGOFZ.js.map} +0 -0
- /package/{chunk-JZD2ALHL.js.map → chunk-SP77SLW3.js.map} +0 -0
- /package/{computer-use-AJ4LM52W.js.map → computer-use-FEAAE6TT.js.map} +0 -0
- /package/{credit-QS7QUF3Q.js.map → credit-W2JFXIEE.js.map} +0 -0
- /package/{developer-support-QIN7JTGZ.js.map → developer-support-3SNDQLPM.js.map} +0 -0
- /package/{generate-VGPYBDHG.js.map → generate-VMDERMRQ.js.map} +0 -0
- /package/{github-DBVCDROM.js.map → github-IAAPK3LA.js.map} +0 -0
- /package/{goal-VZEI2OD2.js.map → goal-IYAHG7OD.js.map} +0 -0
- /package/{host-35I2D3WT.js.map → host-Y6II7XUE.js.map} +0 -0
- /package/{logs-SW5VAI54.js.map → logs-BPDKBOIG.js.map} +0 -0
- /package/{mail-YYSSPGP2.js.map → mail-O6HOSHJN.js.map} +0 -0
- /package/{maps-DIQSL73V.js.map → maps-N3INUZF2.js.map} +0 -0
- /package/{model-ZFYWBWJ3.js.map → model-NOMWYJFY.js.map} +0 -0
- /package/{model-provider-7MXIPGCL.js.map → model-provider-RZDEASD3.js.map} +0 -0
- /package/{org-E2T6M6MN.js.map → org-47E2LF2E.js.map} +0 -0
- /package/{phone-KKPDS6J3.js.map → phone-EZSBFUQY.js.map} +0 -0
- /package/{preference-MUE7N3MZ.js.map → preference-3U5KKXQ5.js.map} +0 -0
- /package/{resource-3HUMK4UE.js.map → resource-FHIP3W3L.js.map} +0 -0
- /package/{scrape-HH5G742T.js.map → scrape-5LAKGGQN.js.map} +0 -0
- /package/{secret-PH5S7HXR.js.map → secret-CZE2VOBQ.js.map} +0 -0
- /package/{slack-5HWY6WME.js.map → slack-XG2XYZD4.js.map} +0 -0
- /package/{teams-DJVOFNO6.js.map → teams-SHZAOOYC.js.map} +0 -0
- /package/{telegram-3IPXE4FT.js.map → telegram-5APDUFXW.js.map} +0 -0
- /package/{variable-XC2BRIE4.js.map → variable-CJIIWMIX.js.map} +0 -0
- /package/{video-SAEKMO5Q.js.map → video-BFST4YFU.js.map} +0 -0
- /package/{web-GEEMEX3J.js.map → web-6H5BRLZF.js.map} +0 -0
- /package/{web-search-DLAG55F2.js.map → web-search-WTPWZGHE.js.map} +0 -0
- /package/{whoami-EPCOG5DN.js.map → whoami-KY2VJFW7.js.map} +0 -0
- /package/{workflow-VS75PBYU.js.map → workflow-L5Z6BS5N.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-
|
|
6
|
+
} from "./chunk-6IPI5G2W.js";
|
|
7
|
+
import {
|
|
8
|
+
availableConnectorRefs,
|
|
9
|
+
findConnectorStatusItem,
|
|
10
|
+
resolveAgentContext,
|
|
11
|
+
resolveManualGrantAuthMethod,
|
|
12
|
+
searchPublicConnectorCatalog
|
|
13
|
+
} from "./chunk-JRH7ZD2I.js";
|
|
7
14
|
import {
|
|
8
15
|
getPlatformOrigin,
|
|
9
16
|
toPlatformUrl
|
|
10
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-PAGGGOFZ.js";
|
|
11
18
|
import {
|
|
12
19
|
UNKNOWN_PERMISSION_GRANT,
|
|
20
|
+
connectZeroConnectorManualGrant,
|
|
13
21
|
createComputerUseAuthorizationRequest,
|
|
22
|
+
customConnectorProposalSchema,
|
|
14
23
|
diagnoseZeroConnectorCheck,
|
|
15
|
-
|
|
24
|
+
getZeroAgent,
|
|
25
|
+
getZeroAgentCustomConnectors,
|
|
16
26
|
getZeroAgentUserConnectors,
|
|
17
|
-
getZeroBillingStatus,
|
|
18
27
|
getZeroConnector,
|
|
19
28
|
getZeroConnectorCatalogPermissions,
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
} from "./chunk-
|
|
29
|
+
getZeroCustomConnector,
|
|
30
|
+
listZeroConnectorCatalogStatus,
|
|
31
|
+
listZeroCustomConnectors
|
|
32
|
+
} from "./chunk-YWMCF6SQ.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-
|
|
39
|
+
} from "./chunk-IEMQM5BQ.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/
|
|
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/
|
|
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
|
|
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
|
-
"
|
|
191
|
+
"connector check requires --method to be a supported HTTP method."
|
|
145
192
|
);
|
|
146
193
|
case "invalid-url":
|
|
147
194
|
return new Error(
|
|
148
|
-
"
|
|
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
|
-
"
|
|
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
|
|
479
|
-
return `zero
|
|
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
|
|
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
|
|
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(
|
|
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(
|
|
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
|
|
637
|
+
`To re-diagnose after changes, run: zero connector check ${args.join(" ")}`
|
|
577
638
|
);
|
|
578
639
|
}
|
|
579
|
-
var checkConnectorCommand = new Command().name("check
|
|
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
|
|
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
|
|
611
|
-
zero
|
|
612
|
-
zero
|
|
613
|
-
zero
|
|
614
|
-
zero
|
|
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/
|
|
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
|
-
|
|
674
|
-
|
|
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
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
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/
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
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
|
-
|
|
813
|
+
if (connector.connection?.externalEmail)
|
|
814
|
+
return connector.connection.externalEmail;
|
|
815
|
+
return "-";
|
|
732
816
|
}
|
|
733
|
-
function
|
|
734
|
-
|
|
735
|
-
|
|
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
|
-
|
|
743
|
-
|
|
744
|
-
|
|
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
|
-
|
|
756
|
-
|
|
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
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
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
|
|
776
|
-
const
|
|
777
|
-
|
|
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
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
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
|
-
|
|
981
|
+
`${"Status:".padEnd(LABEL_WIDTH)}${source_default.dim("not connected")}`
|
|
789
982
|
);
|
|
790
983
|
return;
|
|
791
984
|
}
|
|
792
985
|
console.log(
|
|
793
|
-
|
|
986
|
+
`${"Status:".padEnd(LABEL_WIDTH)}${connector.connectionStatus === "reconnect-required" ? source_default.yellow("reconnect needed") : source_default.green("connected")}`
|
|
794
987
|
);
|
|
795
|
-
|
|
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
|
-
|
|
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
|
|
802
|
-
|
|
803
|
-
|
|
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
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
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
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
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
|
-
|
|
1185
|
+
`${"Status:".padEnd(LABEL_WIDTH2)}${renderConnected(connector)}`
|
|
838
1186
|
);
|
|
839
|
-
|
|
840
|
-
|
|
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
|
-
|
|
847
|
-
|
|
848
|
-
|
|
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
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
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 (
|
|
890
|
-
|
|
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
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
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
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
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
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
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/
|
|
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
|
|
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
|
|
957
|
-
const grantAction = args.action === "enable" ? "allow" : "deny";
|
|
1288
|
+
function printPermissionRequestMessage(args) {
|
|
958
1289
|
console.log(
|
|
959
|
-
`You can
|
|
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
|
|
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
|
|
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:
|
|
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
|
|
1020
|
-
|
|
1021
|
-
action,
|
|
1342
|
+
printSensitivePermissionGuidance(connectorRef, permission);
|
|
1343
|
+
printPermissionRequestMessage({
|
|
1022
1344
|
permission,
|
|
1023
1345
|
label,
|
|
1024
1346
|
url,
|
|
1025
|
-
duration
|
|
1347
|
+
duration
|
|
1026
1348
|
});
|
|
1027
1349
|
}
|
|
1028
|
-
var
|
|
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
|
|
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
|
|
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
|
|
1060
|
-
zero
|
|
1061
|
-
zero
|
|
1062
|
-
zero
|
|
1063
|
-
zero
|
|
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
|
|
1068
|
-
- Use --permission __unknown__ to
|
|
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
|
-
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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/
|
|
1114
|
-
|
|
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
|
-
|
|
1415
|
+
zeroConnectorCommand
|
|
1193
1416
|
};
|
|
1194
|
-
//# sourceMappingURL=
|
|
1417
|
+
//# sourceMappingURL=connector-CM3CYVJ2.js.map
|