openpond 0.0.30-bootstrap.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +128 -0
- package/LICENSE +21 -0
- package/README.md +162 -0
- package/RELEASE.md +20 -0
- package/dist/api/core.d.ts +22 -0
- package/dist/api/deployments.d.ts +30 -0
- package/dist/api/types.d.ts +624 -0
- package/dist/api.d.ts +90 -0
- package/dist/cache.d.ts +22 -0
- package/dist/chunks/app-layer-YKXEQGOW.js +163 -0
- package/dist/chunks/apps-GGSIN2ZF.js +539 -0
- package/dist/chunks/chunk-3CC6MH35.js +1663 -0
- package/dist/chunks/chunk-3Y4EL3P6.js +1090 -0
- package/dist/chunks/chunk-4HYJG2JE.js +3875 -0
- package/dist/chunks/chunk-5G4E547X.js +294 -0
- package/dist/chunks/chunk-74O6FGVN.js +598 -0
- package/dist/chunks/chunk-AUJLPKGI.js +632 -0
- package/dist/chunks/chunk-BYAPLT37.js +744 -0
- package/dist/chunks/chunk-FUP7EGT7.js +1845 -0
- package/dist/chunks/chunk-I6HN3ZGW.js +88 -0
- package/dist/chunks/chunk-KRKGHVMQ.js +294 -0
- package/dist/chunks/chunk-LHYK6QO2.js +1300 -0
- package/dist/chunks/chunk-NLBKZZEK.js +224 -0
- package/dist/chunks/chunk-OG75GMVO.js +1 -0
- package/dist/chunks/chunk-Q57SVPEH.js +11663 -0
- package/dist/chunks/chunk-UACZUFIA.js +47 -0
- package/dist/chunks/chunk-VQX33YAG.js +5135 -0
- package/dist/chunks/chunk-W5GKHH77.js +168 -0
- package/dist/chunks/chunk-WYDVQOBL.js +17581 -0
- package/dist/chunks/chunk-XSAXENQD.js +4167 -0
- package/dist/chunks/chunk-Y6G6WRTG.js +210 -0
- package/dist/chunks/cli-NVKNE4AZ.js +11 -0
- package/dist/chunks/cli-X3HPLSOV.js +19 -0
- package/dist/chunks/core-commands-IM2UKLU4.js +41 -0
- package/dist/chunks/extend-YXCBULPO.js +84 -0
- package/dist/chunks/harness-GMK6IY2U.js +140 -0
- package/dist/chunks/help-LMH5FGT2.js +65 -0
- package/dist/chunks/opchat-BWXZ32GX.js +169 -0
- package/dist/chunks/organizations-4ISQRGMQ.js +738 -0
- package/dist/chunks/profile-NLDZDT3L.js +1110 -0
- package/dist/chunks/project-agent-ZPVO25HA.js +892 -0
- package/dist/chunks/sandbox-command-5GFJ2U3V.js +1652 -0
- package/dist/chunks/sandbox-template-LZN4F55Z.js +1646 -0
- package/dist/chunks/src-3RBI4DNN.js +3595 -0
- package/dist/chunks/src-EYXQS6XD.js +73427 -0
- package/dist/chunks/teams-bot-WP3FHKGA.js +137 -0
- package/dist/cli.js +77 -0
- package/dist/client-types.d.ts +222 -0
- package/dist/client.d.ts +19 -0
- package/dist/config.d.ts +184 -0
- package/dist/hosted-chat.d.ts +162 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +25481 -0
- package/dist/indicators.d.ts +38 -0
- package/dist/opchat-smoke.d.ts +47 -0
- package/dist/private-json-file.d.ts +3 -0
- package/dist/profile/local-profile-types.d.ts +160 -0
- package/dist/profile/local-profile.d.ts +69 -0
- package/dist/profile/profile-catalog.d.ts +14 -0
- package/dist/profile/profile-git.d.ts +17 -0
- package/dist/profile/profile-promotion.d.ts +21 -0
- package/dist/profile/profile-setup-gate.d.ts +22 -0
- package/dist/profile/profile-skills.d.ts +30 -0
- package/dist/profile/profile-source-upload.d.ts +29 -0
- package/dist/profile/source-upload-cache.d.ts +29 -0
- package/dist/sandbox/async-request-options.d.ts +2 -0
- package/dist/sandbox/client-handles.d.ts +113 -0
- package/dist/sandbox/client.d.ts +348 -0
- package/dist/sandbox/runtime-handle.d.ts +36 -0
- package/dist/sandbox/sandbox-instance-client.d.ts +72 -0
- package/dist/sandbox/smoke.d.ts +3 -0
- package/dist/sandbox/stream.d.ts +7 -0
- package/dist/sandbox/types/billing.d.ts +176 -0
- package/dist/sandbox/types/client.d.ts +103 -0
- package/dist/sandbox/types/core.d.ts +140 -0
- package/dist/sandbox/types/index.d.ts +14 -0
- package/dist/sandbox/types/io.d.ts +240 -0
- package/dist/sandbox/types/microsoft-teams-bot.d.ts +51 -0
- package/dist/sandbox/types/org-project-agent.d.ts +610 -0
- package/dist/sandbox/types/record.d.ts +53 -0
- package/dist/sandbox/types/responses.d.ts +295 -0
- package/dist/sandbox/types/runtime-profiles.d.ts +15 -0
- package/dist/sandbox/types/runtime.d.ts +152 -0
- package/dist/sandbox/types/schedules.d.ts +141 -0
- package/dist/sandbox/types/snapshots.d.ts +205 -0
- package/dist/sandbox/types/workflow-modes.d.ts +1 -0
- package/dist/sandbox/types/workload-sources.d.ts +20 -0
- package/dist/sandbox/url.d.ts +2 -0
- package/dist/sandbox-template/manifest.d.ts +304 -0
- package/dist/sandbox-template/manifest.js +18381 -0
- package/dist/skills/openpond-cli/SKILL.md +49 -0
- package/dist/skills/openpond-desktop-harness/SKILL.md +113 -0
- package/dist/skills/openpond-desktop-harness/agents/openai.yaml +4 -0
- package/dist/skills/openpond-taskset-authoring/SKILL.md +38 -0
- package/dist/skills/openpond-taskset-authoring/references/graders-and-rewards.md +11 -0
- package/dist/skills/openpond-taskset-authoring/references/method-selection.md +12 -0
- package/dist/skills/openpond-taskset-authoring/references/privacy-and-provenance.md +8 -0
- package/dist/skills/openpond-taskset-authoring/references/task-design.md +13 -0
- package/dist/stream.d.ts +20 -0
- package/dist/types.d.ts +57 -0
- package/dist/urls.d.ts +4 -0
- package/dist/web/assets/AppsView-Bu-Nc3Ew.js +1 -0
- package/dist/web/assets/AppsView-DIhprTIC.css +1 -0
- package/dist/web/assets/BrowserSidebar-CCguQ-DR.js +1 -0
- package/dist/web/assets/BrowserSidebar-D9i7gQzw.css +1 -0
- package/dist/web/assets/CloudWorkView-DNoPIlMj.css +1 -0
- package/dist/web/assets/CloudWorkView-Dr3xqLE5.js +1 -0
- package/dist/web/assets/CommandMenu-CnodJFHD.js +1 -0
- package/dist/web/assets/CommandMenu-hNQCm8mw.css +1 -0
- package/dist/web/assets/CommunityView-CIbjNUZr.js +1 -0
- package/dist/web/assets/CommunityView-DSik4sd2.css +1 -0
- package/dist/web/assets/GetStartedView-C3ZrnEz5.css +1 -0
- package/dist/web/assets/GetStartedView-C8nyH_PT.js +1 -0
- package/dist/web/assets/LabsExtensions-GtJzxDnK.js +1 -0
- package/dist/web/assets/LabsProfile-DG7rWYur.js +1 -0
- package/dist/web/assets/LabsRoute-D6MDHBzq.js +2 -0
- package/dist/web/assets/LabsRoute-TEt9j1vB.css +1 -0
- package/dist/web/assets/LabsSignals-BfsDN86w.js +1 -0
- package/dist/web/assets/LabsSignals-D6iA6Ryl.css +1 -0
- package/dist/web/assets/NewProjectDialog-CaKiCoVS.js +1 -0
- package/dist/web/assets/ProfileSettingsSection-DTQS2DVL.css +1 -0
- package/dist/web/assets/ProfileSettingsSection-DxEzoF3K.js +1 -0
- package/dist/web/assets/ProfileView-CEscW7Ru.js +1 -0
- package/dist/web/assets/SettingsView-DwbGu8Kj.css +1 -0
- package/dist/web/assets/SettingsView-JIRR_FO4.js +63 -0
- package/dist/web/assets/TeamChatView-B5M1ThhJ.js +3 -0
- package/dist/web/assets/TeamChatView-Bx44q3WV.css +1 -0
- package/dist/web/assets/TerminalOverlay-C1iP4OS1.js +19 -0
- package/dist/web/assets/TerminalOverlay-DwBiZLwk.css +1 -0
- package/dist/web/assets/TrainingSettingsSection-BDYvI2te.js +1 -0
- package/dist/web/assets/TrainingView-CoCFK6W3.js +5 -0
- package/dist/web/assets/WorkspaceDiffPanel-CMxKQeo7.js +14 -0
- package/dist/web/assets/WorkspaceEnvironmentMenu-B8JJbwIz.js +32 -0
- package/dist/web/assets/WorkspaceEnvironmentMenu-DGIFdG3o.css +1 -0
- package/dist/web/assets/WorkspaceGitDialogs-B4sp9BGn.js +1 -0
- package/dist/web/assets/WorkspaceMonacoEditor-BBqimG5X.js +845 -0
- package/dist/web/assets/WorkspaceMonacoEditor-BwKcXIZw.css +1 -0
- package/dist/web/assets/boxes-DAaDUabq.js +1 -0
- package/dist/web/assets/codicon-ngg6Pgfi.ttf +0 -0
- package/dist/web/assets/css.worker-DBVD8oXr.js +93 -0
- package/dist/web/assets/cssMode-CBF1mieJ.js +1 -0
- package/dist/web/assets/dockerfile-BG73LgW2.js +1 -0
- package/dist/web/assets/editor.worker-CdQrwHl8.js +26 -0
- package/dist/web/assets/git-commit-horizontal-CAickXpN.js +1 -0
- package/dist/web/assets/git-dialogs-BZDqS1eT.css +1 -0
- package/dist/web/assets/html.worker-CwpTb9lJ.js +470 -0
- package/dist/web/assets/htmlMode-2u8OHtWO.js +1 -0
- package/dist/web/assets/index-BdY6A-YN.css +1 -0
- package/dist/web/assets/index-CU2qhUYV.js +195 -0
- package/dist/web/assets/index-Dz2B3-4C.js +1 -0
- package/dist/web/assets/info-CQNTh78o.js +1 -0
- package/dist/web/assets/json.worker-BoL8UZqY.js +58 -0
- package/dist/web/assets/jsonMode-C4CWXViX.js +7 -0
- package/dist/web/assets/lspLanguageFeatures-CBs_BOlB.js +4 -0
- package/dist/web/assets/markdown-BFxVWTOG.js +1 -0
- package/dist/web/assets/monaco.contribution-C1LUxAKf.js +2 -0
- package/dist/web/assets/monaco.contribution-Cpf6dWsh.js +2 -0
- package/dist/web/assets/monaco.contribution-lOXpG2xQ.js +2 -0
- package/dist/web/assets/monaco.contribution-sd3cFkcN.js +2 -0
- package/dist/web/assets/monitor-DsIswrMV.js +1 -0
- package/dist/web/assets/play-CeRw21NV.js +1 -0
- package/dist/web/assets/python-CXYq3BUl.js +1 -0
- package/dist/web/assets/refresh-cw-N5b_6AP5.js +1 -0
- package/dist/web/assets/reply-BSKjZrJg.js +1 -0
- package/dist/web/assets/save-D0oHH1a3.js +1 -0
- package/dist/web/assets/settings-lists-BEg6LMcy.css +1 -0
- package/dist/web/assets/shell-DiJ1NA_G.js +1 -0
- package/dist/web/assets/toggleHighContrast-B7NOMXDY.css +1 -0
- package/dist/web/assets/toggleHighContrast-DRjlcwes.js +62 -0
- package/dist/web/assets/training-model-data-BPrc68VG.js +1 -0
- package/dist/web/assets/ts.worker-BH9nVgjN.js +67718 -0
- package/dist/web/assets/tsMode-x-1A7ZcB.js +11 -0
- package/dist/web/assets/wifi-off-Dt52ofzh.js +1 -0
- package/dist/web/assets/workers-Ciff6Dzi.js +1 -0
- package/dist/web/assets/yaml-CB67Kxnz.js +1 -0
- package/dist/web/connected-apps/github.svg +3 -0
- package/dist/web/connected-apps/google.svg +6 -0
- package/dist/web/connected-apps/linear.svg +3 -0
- package/dist/web/connected-apps/microsoft.svg +6 -0
- package/dist/web/connected-apps/notion.svg +3 -0
- package/dist/web/connected-apps/openpond-mcp.svg +4 -0
- package/dist/web/connected-apps/slack.svg +6 -0
- package/dist/web/connected-apps/x.svg +3 -0
- package/dist/web/favicon-16x16.png +0 -0
- package/dist/web/favicon-32x32.png +0 -0
- package/dist/web/index.html +16 -0
- package/dist/web/openpond-icon.png +0 -0
- package/dist/web/openpond-wordlogo-white.png +0 -0
- package/dist/web/tokens/eth.svg +1 -0
- package/dist/web/tokens/usdc.svg +1 -0
- package/docs/agent-edit-check-status-json.md +132 -0
- package/docs/command-reference.md +695 -0
- package/package.json +84 -0
|
@@ -0,0 +1,738 @@
|
|
|
1
|
+
import { createRequire as __openpondCreateRequire } from "node:module"; var require = __openpondCreateRequire(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
resolveSandboxClient
|
|
4
|
+
} from "./chunk-XSAXENQD.js";
|
|
5
|
+
import "./chunk-5G4E547X.js";
|
|
6
|
+
import {
|
|
7
|
+
parseBooleanOption,
|
|
8
|
+
parseCsvOption,
|
|
9
|
+
parseIntegerOption,
|
|
10
|
+
parseJsonOption
|
|
11
|
+
} from "./chunk-3Y4EL3P6.js";
|
|
12
|
+
import "./chunk-UACZUFIA.js";
|
|
13
|
+
|
|
14
|
+
// src/cli/organizations.ts
|
|
15
|
+
import { spawn } from "node:child_process";
|
|
16
|
+
import { createHash, randomBytes } from "node:crypto";
|
|
17
|
+
import { createServer } from "node:http";
|
|
18
|
+
function formatOrganizationLine(organization) {
|
|
19
|
+
return [
|
|
20
|
+
organization.slug,
|
|
21
|
+
`team=${organization.teamId}`,
|
|
22
|
+
`role=${organization.role}`,
|
|
23
|
+
`status=${organization.status}`,
|
|
24
|
+
organization.displayName
|
|
25
|
+
].join(" ");
|
|
26
|
+
}
|
|
27
|
+
function formatOrganizationMemberLine(member) {
|
|
28
|
+
return [
|
|
29
|
+
member.email ?? member.userId,
|
|
30
|
+
`user=${member.userId}`,
|
|
31
|
+
`role=${member.role}`,
|
|
32
|
+
member.createdAt
|
|
33
|
+
].join(" ");
|
|
34
|
+
}
|
|
35
|
+
function formatOrganizationMcpServerLine(server) {
|
|
36
|
+
if (!server) return "no mcp server configured";
|
|
37
|
+
return [
|
|
38
|
+
server.slug,
|
|
39
|
+
`team=${server.teamId}`,
|
|
40
|
+
`status=${server.status}`,
|
|
41
|
+
`tools=${server.toolset.join(",") || "-"}`,
|
|
42
|
+
server.resourceUrl
|
|
43
|
+
].join(" ");
|
|
44
|
+
}
|
|
45
|
+
var DEFAULT_MCP_AUTHORIZE_SCOPES = [
|
|
46
|
+
"estimate.read",
|
|
47
|
+
"estimate.write",
|
|
48
|
+
"estimate.execute",
|
|
49
|
+
"artifacts.read",
|
|
50
|
+
"artifacts.write"
|
|
51
|
+
];
|
|
52
|
+
function normalizeMcpResourceUrl(url) {
|
|
53
|
+
const trimmed = url.trim().replace(/\/$/, "");
|
|
54
|
+
if (!trimmed) {
|
|
55
|
+
throw new Error("MCP resource URL must be non-empty");
|
|
56
|
+
}
|
|
57
|
+
const parsed = new URL(trimmed);
|
|
58
|
+
return parsed.toString().replace(/\/$/, "");
|
|
59
|
+
}
|
|
60
|
+
function resolveMcpProbeResourceUrl(server, options) {
|
|
61
|
+
const explicit = typeof options.resourceUrl === "string" && options.resourceUrl.trim() ? options.resourceUrl.trim() : typeof options.url === "string" && options.url.trim() ? options.url.trim() : "";
|
|
62
|
+
if (explicit) {
|
|
63
|
+
return normalizeMcpResourceUrl(explicit);
|
|
64
|
+
}
|
|
65
|
+
if (!server?.resourceUrl) {
|
|
66
|
+
throw new Error(
|
|
67
|
+
"organization does not have an MCP server; run organizations mcp-generate first"
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
return normalizeMcpResourceUrl(server.resourceUrl);
|
|
71
|
+
}
|
|
72
|
+
function resolveMcpProbeOrigin(resourceUrl, options) {
|
|
73
|
+
const explicit = typeof options.origin === "string" && options.origin.trim() ? options.origin.trim() : "";
|
|
74
|
+
if (explicit) {
|
|
75
|
+
return normalizeMcpResourceUrl(explicit);
|
|
76
|
+
}
|
|
77
|
+
return new URL(resourceUrl).origin;
|
|
78
|
+
}
|
|
79
|
+
function randomOauthToken(bytes = 32) {
|
|
80
|
+
return randomBytes(bytes).toString("base64url");
|
|
81
|
+
}
|
|
82
|
+
function buildMcpOauthPkceChallenge(verifier) {
|
|
83
|
+
return createHash("sha256").update(verifier).digest("base64url");
|
|
84
|
+
}
|
|
85
|
+
function parseMcpOAuthScopes(options) {
|
|
86
|
+
const raw = typeof options.scope === "string" && options.scope.trim() ? options.scope : typeof options.scopes === "string" && options.scopes.trim() ? options.scopes : "";
|
|
87
|
+
if (!raw) {
|
|
88
|
+
return [...DEFAULT_MCP_AUTHORIZE_SCOPES];
|
|
89
|
+
}
|
|
90
|
+
const scopes = raw.split(/[,\s]+/g).map((scope) => scope.trim()).filter(Boolean);
|
|
91
|
+
if (scopes.length === 0) {
|
|
92
|
+
throw new Error("scope must include at least one OAuth scope");
|
|
93
|
+
}
|
|
94
|
+
return scopes;
|
|
95
|
+
}
|
|
96
|
+
function resolveMcpOAuthClientId(options) {
|
|
97
|
+
const value = typeof options.clientId === "string" && options.clientId.trim() ? options.clientId.trim() : "openpond-code-mcp-proof";
|
|
98
|
+
if (value === "true") {
|
|
99
|
+
throw new Error("client-id must be a non-empty value");
|
|
100
|
+
}
|
|
101
|
+
return value;
|
|
102
|
+
}
|
|
103
|
+
function resolveMcpOAuthTimeoutMs(options) {
|
|
104
|
+
const timeoutSeconds = parseIntegerOption(options.timeoutSeconds, "timeout-seconds") ?? parseIntegerOption(options.timeout, "timeout") ?? 180;
|
|
105
|
+
if (timeoutSeconds <= 0) {
|
|
106
|
+
throw new Error("timeout must be greater than zero");
|
|
107
|
+
}
|
|
108
|
+
return timeoutSeconds * 1e3;
|
|
109
|
+
}
|
|
110
|
+
function resolveMcpOAuthCallbackPort(options) {
|
|
111
|
+
const port = parseIntegerOption(options.callbackPort, "callback-port") ?? 0;
|
|
112
|
+
if (port < 0 || port > 65535) {
|
|
113
|
+
throw new Error("callback-port must be between 0 and 65535");
|
|
114
|
+
}
|
|
115
|
+
return port;
|
|
116
|
+
}
|
|
117
|
+
function closeServer(server) {
|
|
118
|
+
return new Promise((resolve, reject) => {
|
|
119
|
+
server.close((error) => {
|
|
120
|
+
if (error) reject(error);
|
|
121
|
+
else resolve();
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
async function startMcpOAuthCallbackListener(input) {
|
|
126
|
+
let settled = false;
|
|
127
|
+
let timeout = null;
|
|
128
|
+
let resolveCallback = null;
|
|
129
|
+
let rejectCallback = null;
|
|
130
|
+
const callbackPromise = new Promise(
|
|
131
|
+
(resolve, reject) => {
|
|
132
|
+
resolveCallback = resolve;
|
|
133
|
+
rejectCallback = reject;
|
|
134
|
+
}
|
|
135
|
+
);
|
|
136
|
+
const settle = (response, status, body, result, error) => {
|
|
137
|
+
if (settled) {
|
|
138
|
+
response.writeHead(204).end();
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
settled = true;
|
|
142
|
+
response.writeHead(status, {
|
|
143
|
+
"cache-control": "no-store",
|
|
144
|
+
"content-type": "text/html; charset=utf-8"
|
|
145
|
+
});
|
|
146
|
+
response.end(body);
|
|
147
|
+
if (timeout) clearTimeout(timeout);
|
|
148
|
+
if (result) {
|
|
149
|
+
resolveCallback?.(result);
|
|
150
|
+
} else {
|
|
151
|
+
rejectCallback?.(error ?? new Error("oauth_callback_failed"));
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
const server = createServer((request, response) => {
|
|
155
|
+
const host = request.headers.host ?? "127.0.0.1";
|
|
156
|
+
const url = new URL(request.url ?? "/", `http://${host}`);
|
|
157
|
+
if (url.pathname !== "/callback") {
|
|
158
|
+
response.writeHead(404, { "content-type": "text/plain; charset=utf-8" });
|
|
159
|
+
response.end("Not found");
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
const state = url.searchParams.get("state") ?? "";
|
|
163
|
+
const error = url.searchParams.get("error") ?? "";
|
|
164
|
+
const code = url.searchParams.get("code") ?? "";
|
|
165
|
+
if (state !== input.expectedState) {
|
|
166
|
+
settle(
|
|
167
|
+
response,
|
|
168
|
+
400,
|
|
169
|
+
"<!doctype html><title>OpenPond OAuth failed</title><p>State mismatch. Return to the terminal and retry.</p>",
|
|
170
|
+
void 0,
|
|
171
|
+
new Error("oauth_state_mismatch")
|
|
172
|
+
);
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
if (error) {
|
|
176
|
+
settle(
|
|
177
|
+
response,
|
|
178
|
+
400,
|
|
179
|
+
"<!doctype html><title>OpenPond OAuth denied</title><p>Authorization was not completed. Return to the terminal.</p>",
|
|
180
|
+
void 0,
|
|
181
|
+
new Error(`oauth_authorization_failed:${error}`)
|
|
182
|
+
);
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
if (!code) {
|
|
186
|
+
settle(
|
|
187
|
+
response,
|
|
188
|
+
400,
|
|
189
|
+
"<!doctype html><title>OpenPond OAuth failed</title><p>Missing authorization code. Return to the terminal and retry.</p>",
|
|
190
|
+
void 0,
|
|
191
|
+
new Error("oauth_code_missing")
|
|
192
|
+
);
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
settle(
|
|
196
|
+
response,
|
|
197
|
+
200,
|
|
198
|
+
"<!doctype html><title>OpenPond OAuth complete</title><p>Authorization complete. You can return to the terminal.</p>",
|
|
199
|
+
{ code, state }
|
|
200
|
+
);
|
|
201
|
+
});
|
|
202
|
+
await new Promise((resolve, reject) => {
|
|
203
|
+
const onError = (error) => {
|
|
204
|
+
server.off("listening", onListening);
|
|
205
|
+
reject(error);
|
|
206
|
+
};
|
|
207
|
+
const onListening = () => {
|
|
208
|
+
server.off("error", onError);
|
|
209
|
+
resolve();
|
|
210
|
+
};
|
|
211
|
+
server.once("error", onError);
|
|
212
|
+
server.once("listening", onListening);
|
|
213
|
+
server.listen(input.port, "127.0.0.1");
|
|
214
|
+
});
|
|
215
|
+
const address = server.address();
|
|
216
|
+
if (!address || typeof address.port !== "number") {
|
|
217
|
+
await closeServer(server);
|
|
218
|
+
throw new Error("oauth_callback_listener_failed");
|
|
219
|
+
}
|
|
220
|
+
timeout = setTimeout(() => {
|
|
221
|
+
if (!settled) {
|
|
222
|
+
settled = true;
|
|
223
|
+
rejectCallback?.(new Error("oauth_callback_timeout"));
|
|
224
|
+
}
|
|
225
|
+
}, input.timeoutMs);
|
|
226
|
+
return {
|
|
227
|
+
close: async () => {
|
|
228
|
+
if (timeout) clearTimeout(timeout);
|
|
229
|
+
await closeServer(server).catch(() => {
|
|
230
|
+
});
|
|
231
|
+
},
|
|
232
|
+
redirectUri: `http://127.0.0.1:${address.port}/callback`,
|
|
233
|
+
waitForCallback: () => callbackPromise
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
function openUrlWithSystemBrowser(url) {
|
|
237
|
+
const platform = process.platform;
|
|
238
|
+
const command = platform === "darwin" ? "open" : platform === "win32" ? "cmd" : "xdg-open";
|
|
239
|
+
const args = platform === "win32" ? ["/c", "start", "", url] : [url];
|
|
240
|
+
const child = spawn(command, args, {
|
|
241
|
+
detached: true,
|
|
242
|
+
stdio: "ignore"
|
|
243
|
+
});
|
|
244
|
+
child.unref();
|
|
245
|
+
}
|
|
246
|
+
function buildMcpOAuthAuthorizeUrl(input) {
|
|
247
|
+
const url = new URL(input.authorizationEndpoint);
|
|
248
|
+
url.searchParams.set("response_type", "code");
|
|
249
|
+
url.searchParams.set("client_id", input.clientId);
|
|
250
|
+
url.searchParams.set("redirect_uri", input.redirectUri);
|
|
251
|
+
url.searchParams.set("code_challenge", input.codeChallenge);
|
|
252
|
+
url.searchParams.set("code_challenge_method", "S256");
|
|
253
|
+
url.searchParams.set("resource", input.resourceUrl);
|
|
254
|
+
url.searchParams.set("scope", input.scopes.join(" "));
|
|
255
|
+
url.searchParams.set("state", input.state);
|
|
256
|
+
return url.toString();
|
|
257
|
+
}
|
|
258
|
+
async function exchangeMcpOAuthAuthorizationCode(input) {
|
|
259
|
+
const params = new URLSearchParams();
|
|
260
|
+
params.set("grant_type", "authorization_code");
|
|
261
|
+
params.set("client_id", input.clientId);
|
|
262
|
+
params.set("redirect_uri", input.redirectUri);
|
|
263
|
+
params.set("code", input.code);
|
|
264
|
+
params.set("code_verifier", input.codeVerifier);
|
|
265
|
+
const response = await fetch(`${input.origin}/oauth/token`, {
|
|
266
|
+
method: "POST",
|
|
267
|
+
headers: {
|
|
268
|
+
"content-type": "application/x-www-form-urlencoded"
|
|
269
|
+
},
|
|
270
|
+
body: params
|
|
271
|
+
});
|
|
272
|
+
const body = await readMcpProbeBody(response);
|
|
273
|
+
if (!response.ok) {
|
|
274
|
+
throw new Error(
|
|
275
|
+
`oauth_token_exchange_failed:${response.status}:${JSON.stringify(body)}`
|
|
276
|
+
);
|
|
277
|
+
}
|
|
278
|
+
if (!body || typeof body !== "object" || Array.isArray(body)) {
|
|
279
|
+
throw new Error("oauth_token_exchange_invalid_response");
|
|
280
|
+
}
|
|
281
|
+
const token = body;
|
|
282
|
+
if (typeof token.access_token !== "string" || !token.access_token.trim()) {
|
|
283
|
+
throw new Error("oauth_token_exchange_missing_access_token");
|
|
284
|
+
}
|
|
285
|
+
return {
|
|
286
|
+
access_token: token.access_token,
|
|
287
|
+
...typeof token.expires_in === "number" ? { expires_in: token.expires_in } : {},
|
|
288
|
+
...typeof token.refresh_token === "string" ? { refresh_token: token.refresh_token } : {},
|
|
289
|
+
...typeof token.scope === "string" ? { scope: token.scope } : {},
|
|
290
|
+
...typeof token.token_type === "string" ? { token_type: token.token_type } : {}
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
async function readMcpProbeBody(response) {
|
|
294
|
+
const text = await response.text().catch(() => "");
|
|
295
|
+
if (!text) {
|
|
296
|
+
return null;
|
|
297
|
+
}
|
|
298
|
+
const trimmed = text.trim();
|
|
299
|
+
const contentType = response.headers.get("content-type") ?? "";
|
|
300
|
+
if (contentType.toLowerCase().includes("application/json") || trimmed.startsWith("{") || trimmed.startsWith("[")) {
|
|
301
|
+
try {
|
|
302
|
+
return JSON.parse(trimmed);
|
|
303
|
+
} catch {
|
|
304
|
+
return text;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
return text;
|
|
308
|
+
}
|
|
309
|
+
async function fetchMcpProbe(url, init = {}) {
|
|
310
|
+
const response = await fetch(url, init);
|
|
311
|
+
return {
|
|
312
|
+
url,
|
|
313
|
+
status: response.status,
|
|
314
|
+
ok: response.ok,
|
|
315
|
+
headers: {
|
|
316
|
+
contentType: response.headers.get("content-type"),
|
|
317
|
+
location: response.headers.get("location"),
|
|
318
|
+
wwwAuthenticate: response.headers.get("www-authenticate")
|
|
319
|
+
},
|
|
320
|
+
body: await readMcpProbeBody(response)
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
function buildMcpJsonRpcRequest(id, method, params) {
|
|
324
|
+
return params ? { jsonrpc: "2.0", id, method, params } : { jsonrpc: "2.0", id, method };
|
|
325
|
+
}
|
|
326
|
+
function parseMcpToolArguments(options) {
|
|
327
|
+
const raw = typeof options.arguments === "string" && options.arguments.trim() ? options.arguments : typeof options.args === "string" && options.args.trim() ? options.args : "";
|
|
328
|
+
if (!raw) {
|
|
329
|
+
return {};
|
|
330
|
+
}
|
|
331
|
+
const parsed = parseJsonOption(raw, "arguments");
|
|
332
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
333
|
+
throw new Error("arguments must be a JSON object");
|
|
334
|
+
}
|
|
335
|
+
return parsed;
|
|
336
|
+
}
|
|
337
|
+
async function postMcpJsonRpcProbe(input) {
|
|
338
|
+
const headers = {
|
|
339
|
+
"content-type": "application/json"
|
|
340
|
+
};
|
|
341
|
+
if (input.accessToken) {
|
|
342
|
+
headers.authorization = `Bearer ${input.accessToken}`;
|
|
343
|
+
}
|
|
344
|
+
return fetchMcpProbe(input.resourceUrl, {
|
|
345
|
+
method: "POST",
|
|
346
|
+
headers,
|
|
347
|
+
body: JSON.stringify(
|
|
348
|
+
buildMcpJsonRpcRequest(input.id, input.method, input.params)
|
|
349
|
+
)
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
async function probeOrganizationMcp(input) {
|
|
353
|
+
const resourceUrl = normalizeMcpResourceUrl(input.resourceUrl);
|
|
354
|
+
const origin = normalizeMcpResourceUrl(input.origin);
|
|
355
|
+
const protectedResourceUrl = `${resourceUrl}/.well-known/oauth-protected-resource`;
|
|
356
|
+
const authorizationServerUrl = `${origin}/.well-known/oauth-authorization-server`;
|
|
357
|
+
const [
|
|
358
|
+
protectedResource,
|
|
359
|
+
authorizationServer,
|
|
360
|
+
directGetChallenge,
|
|
361
|
+
initialize,
|
|
362
|
+
toolsList,
|
|
363
|
+
unauthenticatedToolCall,
|
|
364
|
+
authenticatedToolCall
|
|
365
|
+
] = await Promise.all([
|
|
366
|
+
fetchMcpProbe(protectedResourceUrl),
|
|
367
|
+
fetchMcpProbe(authorizationServerUrl),
|
|
368
|
+
fetchMcpProbe(resourceUrl),
|
|
369
|
+
postMcpJsonRpcProbe({
|
|
370
|
+
resourceUrl,
|
|
371
|
+
id: 1,
|
|
372
|
+
method: "initialize"
|
|
373
|
+
}),
|
|
374
|
+
postMcpJsonRpcProbe({
|
|
375
|
+
resourceUrl,
|
|
376
|
+
id: 2,
|
|
377
|
+
method: "tools/list"
|
|
378
|
+
}),
|
|
379
|
+
postMcpJsonRpcProbe({
|
|
380
|
+
resourceUrl,
|
|
381
|
+
id: 3,
|
|
382
|
+
method: "tools/call",
|
|
383
|
+
params: {
|
|
384
|
+
name: input.toolName,
|
|
385
|
+
arguments: input.toolArguments
|
|
386
|
+
}
|
|
387
|
+
}),
|
|
388
|
+
input.accessToken ? postMcpJsonRpcProbe({
|
|
389
|
+
resourceUrl,
|
|
390
|
+
id: 4,
|
|
391
|
+
method: "tools/call",
|
|
392
|
+
params: {
|
|
393
|
+
name: input.toolName,
|
|
394
|
+
arguments: input.toolArguments
|
|
395
|
+
},
|
|
396
|
+
accessToken: input.accessToken
|
|
397
|
+
}) : Promise.resolve(null)
|
|
398
|
+
]);
|
|
399
|
+
return {
|
|
400
|
+
resourceUrl,
|
|
401
|
+
origin,
|
|
402
|
+
protectedResource,
|
|
403
|
+
authorizationServer,
|
|
404
|
+
directGetChallenge,
|
|
405
|
+
initialize,
|
|
406
|
+
toolsList,
|
|
407
|
+
unauthenticatedToolCall,
|
|
408
|
+
...authenticatedToolCall ? { authenticatedToolCall } : {}
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
function parseOrganizationRole(value) {
|
|
412
|
+
const role = typeof value === "string" ? value.trim() : "";
|
|
413
|
+
if (role === "owner" || role === "admin" || role === "member") {
|
|
414
|
+
return role;
|
|
415
|
+
}
|
|
416
|
+
throw new Error("role must be owner, admin, or member");
|
|
417
|
+
}
|
|
418
|
+
function buildOrganizationCreateInput(options) {
|
|
419
|
+
const displayName = typeof options.displayName === "string" && options.displayName.trim() ? options.displayName.trim() : typeof options.name === "string" && options.name.trim() ? options.name.trim() : "";
|
|
420
|
+
if (!displayName) {
|
|
421
|
+
throw new Error(
|
|
422
|
+
"usage: organizations create --name <name> [--slug <slug>]"
|
|
423
|
+
);
|
|
424
|
+
}
|
|
425
|
+
return {
|
|
426
|
+
displayName,
|
|
427
|
+
...typeof options.slug === "string" && options.slug.trim() ? { slug: options.slug.trim() } : {},
|
|
428
|
+
...typeof options.primaryContactEmail === "string" && options.primaryContactEmail.trim() ? { primaryContactEmail: options.primaryContactEmail.trim() } : {},
|
|
429
|
+
...typeof options.customDomain === "string" && options.customDomain.trim() ? { customDomain: options.customDomain.trim() } : {}
|
|
430
|
+
};
|
|
431
|
+
}
|
|
432
|
+
function buildOrganizationUpdateInput(options) {
|
|
433
|
+
const input = {};
|
|
434
|
+
const displayName = typeof options.displayName === "string" && options.displayName.trim() ? options.displayName.trim() : typeof options.name === "string" && options.name.trim() ? options.name.trim() : "";
|
|
435
|
+
if (displayName) input.displayName = displayName;
|
|
436
|
+
if (typeof options.slug === "string" && options.slug.trim()) {
|
|
437
|
+
input.slug = options.slug.trim();
|
|
438
|
+
}
|
|
439
|
+
if (typeof options.primaryContactEmail === "string") {
|
|
440
|
+
input.primaryContactEmail = options.primaryContactEmail.trim() || null;
|
|
441
|
+
}
|
|
442
|
+
if (typeof options.customDomain === "string") {
|
|
443
|
+
input.customDomain = options.customDomain.trim() || null;
|
|
444
|
+
}
|
|
445
|
+
if (typeof options.status === "string" && options.status.trim()) {
|
|
446
|
+
const status = options.status.trim();
|
|
447
|
+
if (status !== "active" && status !== "disabled" && status !== "archived") {
|
|
448
|
+
throw new Error("status must be active, disabled, or archived");
|
|
449
|
+
}
|
|
450
|
+
input.status = status;
|
|
451
|
+
}
|
|
452
|
+
if (Object.keys(input).length === 0) {
|
|
453
|
+
throw new Error("organizations update requires at least one changed field");
|
|
454
|
+
}
|
|
455
|
+
return input;
|
|
456
|
+
}
|
|
457
|
+
function buildOrganizationMemberInput(options) {
|
|
458
|
+
const email = typeof options.email === "string" ? options.email.trim() : "";
|
|
459
|
+
if (!email) {
|
|
460
|
+
throw new Error(
|
|
461
|
+
"usage: organizations member-upsert <slug> --email <email> --role <role>"
|
|
462
|
+
);
|
|
463
|
+
}
|
|
464
|
+
return {
|
|
465
|
+
email,
|
|
466
|
+
role: parseOrganizationRole(options.role)
|
|
467
|
+
};
|
|
468
|
+
}
|
|
469
|
+
function buildOrganizationMcpGenerateInput(options) {
|
|
470
|
+
return {
|
|
471
|
+
...typeof options.origin === "string" && options.origin.trim() ? { origin: options.origin.trim() } : {},
|
|
472
|
+
...typeof options.toolset === "string" && options.toolset.trim() ? { toolset: parseCsvOption(options.toolset) } : {}
|
|
473
|
+
};
|
|
474
|
+
}
|
|
475
|
+
async function runOrganizationsCommand(options, rest) {
|
|
476
|
+
const subcommand = rest[0] || "list";
|
|
477
|
+
const client = await resolveSandboxClient(options);
|
|
478
|
+
const outputJson = parseBooleanOption(options.json);
|
|
479
|
+
if (subcommand === "list") {
|
|
480
|
+
const organizations = await client.listOrganizations();
|
|
481
|
+
if (outputJson) {
|
|
482
|
+
console.log(JSON.stringify({ organizations }, null, 2));
|
|
483
|
+
return;
|
|
484
|
+
}
|
|
485
|
+
if (organizations.length === 0) {
|
|
486
|
+
console.log("no organizations found");
|
|
487
|
+
return;
|
|
488
|
+
}
|
|
489
|
+
for (const organization of organizations) {
|
|
490
|
+
console.log(formatOrganizationLine(organization));
|
|
491
|
+
}
|
|
492
|
+
return;
|
|
493
|
+
}
|
|
494
|
+
if (subcommand === "create") {
|
|
495
|
+
const organization = await client.createOrganization(
|
|
496
|
+
buildOrganizationCreateInput(options)
|
|
497
|
+
);
|
|
498
|
+
console.log(JSON.stringify({ organization }, null, 2));
|
|
499
|
+
return;
|
|
500
|
+
}
|
|
501
|
+
if (subcommand === "get") {
|
|
502
|
+
const slug = rest[1];
|
|
503
|
+
if (!slug) {
|
|
504
|
+
throw new Error("usage: organizations get <slug>");
|
|
505
|
+
}
|
|
506
|
+
const organization = await client.getOrganization(slug);
|
|
507
|
+
console.log(JSON.stringify({ organization }, null, 2));
|
|
508
|
+
return;
|
|
509
|
+
}
|
|
510
|
+
if (subcommand === "update") {
|
|
511
|
+
const slug = rest[1];
|
|
512
|
+
if (!slug) {
|
|
513
|
+
throw new Error("usage: organizations update <slug> [--name <name>]");
|
|
514
|
+
}
|
|
515
|
+
const organization = await client.updateOrganization(
|
|
516
|
+
slug,
|
|
517
|
+
buildOrganizationUpdateInput(options)
|
|
518
|
+
);
|
|
519
|
+
console.log(JSON.stringify({ organization }, null, 2));
|
|
520
|
+
return;
|
|
521
|
+
}
|
|
522
|
+
if (subcommand === "members" || subcommand === "member-list") {
|
|
523
|
+
const slug = rest[1];
|
|
524
|
+
if (!slug) {
|
|
525
|
+
throw new Error("usage: organizations members <slug>");
|
|
526
|
+
}
|
|
527
|
+
const members = await client.listOrganizationMembers(slug);
|
|
528
|
+
if (outputJson) {
|
|
529
|
+
console.log(JSON.stringify({ members }, null, 2));
|
|
530
|
+
return;
|
|
531
|
+
}
|
|
532
|
+
if (members.length === 0) {
|
|
533
|
+
console.log("no organization members found");
|
|
534
|
+
return;
|
|
535
|
+
}
|
|
536
|
+
for (const member of members) {
|
|
537
|
+
console.log(formatOrganizationMemberLine(member));
|
|
538
|
+
}
|
|
539
|
+
return;
|
|
540
|
+
}
|
|
541
|
+
if (subcommand === "member-upsert" || subcommand === "member-add") {
|
|
542
|
+
const slug = rest[1];
|
|
543
|
+
if (!slug) {
|
|
544
|
+
throw new Error(
|
|
545
|
+
"usage: organizations member-upsert <slug> --email <email> --role <role>"
|
|
546
|
+
);
|
|
547
|
+
}
|
|
548
|
+
const member = await client.upsertOrganizationMember(
|
|
549
|
+
slug,
|
|
550
|
+
buildOrganizationMemberInput(options)
|
|
551
|
+
);
|
|
552
|
+
console.log(JSON.stringify({ member }, null, 2));
|
|
553
|
+
return;
|
|
554
|
+
}
|
|
555
|
+
if (subcommand === "mcp-get" || subcommand === "mcp-server") {
|
|
556
|
+
const slug = rest[1];
|
|
557
|
+
if (!slug) {
|
|
558
|
+
throw new Error("usage: organizations mcp-get <slug>");
|
|
559
|
+
}
|
|
560
|
+
const mcpServer = await client.getOrganizationMcpServer(slug);
|
|
561
|
+
if (outputJson) {
|
|
562
|
+
console.log(JSON.stringify({ mcpServer }, null, 2));
|
|
563
|
+
return;
|
|
564
|
+
}
|
|
565
|
+
console.log(formatOrganizationMcpServerLine(mcpServer));
|
|
566
|
+
return;
|
|
567
|
+
}
|
|
568
|
+
if (subcommand === "mcp-generate") {
|
|
569
|
+
const slug = rest[1];
|
|
570
|
+
if (!slug) {
|
|
571
|
+
throw new Error(
|
|
572
|
+
"usage: organizations mcp-generate <slug> [--origin <url>]"
|
|
573
|
+
);
|
|
574
|
+
}
|
|
575
|
+
const mcpServer = await client.generateOrganizationMcpServer(
|
|
576
|
+
slug,
|
|
577
|
+
buildOrganizationMcpGenerateInput(options)
|
|
578
|
+
);
|
|
579
|
+
console.log(JSON.stringify({ mcpServer }, null, 2));
|
|
580
|
+
return;
|
|
581
|
+
}
|
|
582
|
+
if (subcommand === "mcp-probe" || subcommand === "mcp-inspect") {
|
|
583
|
+
const slug = rest[1];
|
|
584
|
+
if (!slug) {
|
|
585
|
+
throw new Error(
|
|
586
|
+
"usage: organizations mcp-probe <slug> [--origin <url>] [--tool <name>] [--arguments <json>] [--access-token <token>]"
|
|
587
|
+
);
|
|
588
|
+
}
|
|
589
|
+
const mcpServer = await client.getOrganizationMcpServer(slug);
|
|
590
|
+
const resourceUrl = resolveMcpProbeResourceUrl(mcpServer, options);
|
|
591
|
+
const origin = resolveMcpProbeOrigin(resourceUrl, options);
|
|
592
|
+
const toolName = typeof options.tool === "string" && options.tool.trim() ? options.tool.trim() : typeof options.toolName === "string" && options.toolName.trim() ? options.toolName.trim() : "estimate_search_history";
|
|
593
|
+
const toolArguments = parseMcpToolArguments(options);
|
|
594
|
+
const accessToken = typeof options.accessToken === "string" && options.accessToken.trim() ? options.accessToken.trim() : "";
|
|
595
|
+
const probe = await probeOrganizationMcp({
|
|
596
|
+
resourceUrl,
|
|
597
|
+
origin,
|
|
598
|
+
toolName,
|
|
599
|
+
toolArguments,
|
|
600
|
+
...accessToken ? { accessToken } : {}
|
|
601
|
+
});
|
|
602
|
+
console.log(JSON.stringify({ mcpServer, probe }, null, 2));
|
|
603
|
+
return;
|
|
604
|
+
}
|
|
605
|
+
if (subcommand === "mcp-authorize" || subcommand === "mcp-oauth") {
|
|
606
|
+
const slug = rest[1];
|
|
607
|
+
if (!slug) {
|
|
608
|
+
throw new Error(
|
|
609
|
+
"usage: organizations mcp-authorize <slug> [--origin <url>] [--scope <csv|space>] [--tool <name>] [--arguments <json>] [--open]"
|
|
610
|
+
);
|
|
611
|
+
}
|
|
612
|
+
const mcpServer = await client.getOrganizationMcpServer(slug);
|
|
613
|
+
const resourceUrl = resolveMcpProbeResourceUrl(mcpServer, options);
|
|
614
|
+
const origin = resolveMcpProbeOrigin(resourceUrl, options);
|
|
615
|
+
const clientId = resolveMcpOAuthClientId(options);
|
|
616
|
+
const scopes = parseMcpOAuthScopes(options);
|
|
617
|
+
const state = randomOauthToken(18);
|
|
618
|
+
const codeVerifier = randomOauthToken(48);
|
|
619
|
+
const codeChallenge = buildMcpOauthPkceChallenge(codeVerifier);
|
|
620
|
+
const callback = await startMcpOAuthCallbackListener({
|
|
621
|
+
expectedState: state,
|
|
622
|
+
port: resolveMcpOAuthCallbackPort(options),
|
|
623
|
+
timeoutMs: resolveMcpOAuthTimeoutMs(options)
|
|
624
|
+
});
|
|
625
|
+
const authorizationUrl = buildMcpOAuthAuthorizeUrl({
|
|
626
|
+
authorizationEndpoint: `${origin}/oauth/authorize`,
|
|
627
|
+
clientId,
|
|
628
|
+
codeChallenge,
|
|
629
|
+
redirectUri: callback.redirectUri,
|
|
630
|
+
resourceUrl,
|
|
631
|
+
scopes,
|
|
632
|
+
state
|
|
633
|
+
});
|
|
634
|
+
console.error(
|
|
635
|
+
"Open this URL to authorize the organization MCP connection:"
|
|
636
|
+
);
|
|
637
|
+
console.error(authorizationUrl);
|
|
638
|
+
console.error(`Waiting for OAuth callback on ${callback.redirectUri}`);
|
|
639
|
+
if (parseBooleanOption(options.open)) {
|
|
640
|
+
try {
|
|
641
|
+
openUrlWithSystemBrowser(authorizationUrl);
|
|
642
|
+
} catch (error) {
|
|
643
|
+
console.error(
|
|
644
|
+
`Unable to open a browser automatically: ${error instanceof Error ? error.message : String(error)}`
|
|
645
|
+
);
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
try {
|
|
649
|
+
const callbackResult = await callback.waitForCallback();
|
|
650
|
+
const token = await exchangeMcpOAuthAuthorizationCode({
|
|
651
|
+
clientId,
|
|
652
|
+
code: callbackResult.code,
|
|
653
|
+
codeVerifier,
|
|
654
|
+
origin,
|
|
655
|
+
redirectUri: callback.redirectUri
|
|
656
|
+
});
|
|
657
|
+
const toolName = typeof options.tool === "string" && options.tool.trim() ? options.tool.trim() : typeof options.toolName === "string" && options.toolName.trim() ? options.toolName.trim() : "estimate_search_history";
|
|
658
|
+
const toolArguments = parseMcpToolArguments(options);
|
|
659
|
+
const probe = await probeOrganizationMcp({
|
|
660
|
+
accessToken: token.access_token,
|
|
661
|
+
origin,
|
|
662
|
+
resourceUrl,
|
|
663
|
+
toolArguments,
|
|
664
|
+
toolName
|
|
665
|
+
});
|
|
666
|
+
const printToken = parseBooleanOption(options.printToken);
|
|
667
|
+
console.log(
|
|
668
|
+
JSON.stringify(
|
|
669
|
+
{
|
|
670
|
+
mcpServer,
|
|
671
|
+
oauth: {
|
|
672
|
+
accessTokenReceived: true,
|
|
673
|
+
clientId,
|
|
674
|
+
expiresIn: token.expires_in ?? null,
|
|
675
|
+
refreshTokenReceived: Boolean(token.refresh_token),
|
|
676
|
+
scope: token.scope ?? scopes.join(" "),
|
|
677
|
+
tokenType: token.token_type ?? "Bearer",
|
|
678
|
+
...printToken ? {
|
|
679
|
+
accessToken: token.access_token,
|
|
680
|
+
refreshToken: token.refresh_token ?? null
|
|
681
|
+
} : {}
|
|
682
|
+
},
|
|
683
|
+
probe
|
|
684
|
+
},
|
|
685
|
+
null,
|
|
686
|
+
2
|
|
687
|
+
)
|
|
688
|
+
);
|
|
689
|
+
} finally {
|
|
690
|
+
await callback.close();
|
|
691
|
+
}
|
|
692
|
+
return;
|
|
693
|
+
}
|
|
694
|
+
if (subcommand === "mcp-rotate" || subcommand === "mcp-disable" || subcommand === "mcp-enable") {
|
|
695
|
+
const slug = rest[1];
|
|
696
|
+
if (!slug) {
|
|
697
|
+
throw new Error(`usage: organizations ${subcommand} <slug>`);
|
|
698
|
+
}
|
|
699
|
+
const mcpServer = subcommand === "mcp-rotate" ? await client.rotateOrganizationMcpServer(slug) : subcommand === "mcp-disable" ? await client.disableOrganizationMcpServer(slug) : await client.enableOrganizationMcpServer(slug);
|
|
700
|
+
console.log(JSON.stringify({ mcpServer }, null, 2));
|
|
701
|
+
return;
|
|
702
|
+
}
|
|
703
|
+
throw new Error(
|
|
704
|
+
"usage: organizations <list|create|get|update|members|member-upsert|mcp-get|mcp-generate|mcp-probe|mcp-authorize|mcp-rotate|mcp-disable|mcp-enable> [args]"
|
|
705
|
+
);
|
|
706
|
+
}
|
|
707
|
+
export {
|
|
708
|
+
DEFAULT_MCP_AUTHORIZE_SCOPES,
|
|
709
|
+
buildMcpJsonRpcRequest,
|
|
710
|
+
buildMcpOAuthAuthorizeUrl,
|
|
711
|
+
buildMcpOauthPkceChallenge,
|
|
712
|
+
buildOrganizationCreateInput,
|
|
713
|
+
buildOrganizationMcpGenerateInput,
|
|
714
|
+
buildOrganizationMemberInput,
|
|
715
|
+
buildOrganizationUpdateInput,
|
|
716
|
+
closeServer,
|
|
717
|
+
exchangeMcpOAuthAuthorizationCode,
|
|
718
|
+
fetchMcpProbe,
|
|
719
|
+
formatOrganizationLine,
|
|
720
|
+
formatOrganizationMcpServerLine,
|
|
721
|
+
formatOrganizationMemberLine,
|
|
722
|
+
normalizeMcpResourceUrl,
|
|
723
|
+
openUrlWithSystemBrowser,
|
|
724
|
+
parseMcpOAuthScopes,
|
|
725
|
+
parseMcpToolArguments,
|
|
726
|
+
parseOrganizationRole,
|
|
727
|
+
postMcpJsonRpcProbe,
|
|
728
|
+
probeOrganizationMcp,
|
|
729
|
+
randomOauthToken,
|
|
730
|
+
readMcpProbeBody,
|
|
731
|
+
resolveMcpOAuthCallbackPort,
|
|
732
|
+
resolveMcpOAuthClientId,
|
|
733
|
+
resolveMcpOAuthTimeoutMs,
|
|
734
|
+
resolveMcpProbeOrigin,
|
|
735
|
+
resolveMcpProbeResourceUrl,
|
|
736
|
+
runOrganizationsCommand,
|
|
737
|
+
startMcpOAuthCallbackListener
|
|
738
|
+
};
|