@divergeai/cli 0.1.2 → 0.1.3
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/README.md +6 -3
- package/dist/diverge.mjs +157 -33
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@ model gateway, and call platform tools as yourself.
|
|
|
5
5
|
|
|
6
6
|
```bash
|
|
7
7
|
npm install -g @divergeai/cli
|
|
8
|
-
diverge login #
|
|
8
|
+
diverge login # browser sign-in; the organization is chosen afterwards in the CLI
|
|
9
9
|
diverge agents setup claude # Claude Code on the gateway
|
|
10
10
|
diverge agents run dsh -- --profile web --port 3131 --no-open
|
|
11
11
|
diverge tools list --organization-id <id>
|
|
@@ -16,8 +16,11 @@ Node 22 or later. Linux and macOS are supported; Windows is best-effort.
|
|
|
16
16
|
## Sign in
|
|
17
17
|
|
|
18
18
|
`diverge login` runs the browser sign-in (authorization code with PKCE on a
|
|
19
|
-
loopback listener).
|
|
20
|
-
|
|
19
|
+
loopback listener). The browser only authenticates you; the organization is
|
|
20
|
+
chosen afterwards in the CLI, never through the browser: `--organization-id
|
|
21
|
+
<id|name>` if given, else the last login's, else your only membership, else a
|
|
22
|
+
menu. The login is bound to that organization on the platform, and `diverge
|
|
23
|
+
org use <id|name>` switches without a browser. The login is cached in
|
|
21
24
|
`~/.diverge/token.json` (mode 0600), refreshes itself, and `diverge logout`
|
|
22
25
|
revokes it on the platform before forgetting it.
|
|
23
26
|
|
package/dist/diverge.mjs
CHANGED
|
@@ -7387,7 +7387,7 @@ import path10 from "node:path";
|
|
|
7387
7387
|
import { parseArgs } from "node:util";
|
|
7388
7388
|
|
|
7389
7389
|
// src/version.ts
|
|
7390
|
-
var VERSION = true ? "0.1.
|
|
7390
|
+
var VERSION = true ? "0.1.3" : "dev";
|
|
7391
7391
|
var USER_AGENT = `diverge/${VERSION}`;
|
|
7392
7392
|
|
|
7393
7393
|
// src/http.ts
|
|
@@ -7686,15 +7686,25 @@ async function login(options, deps = defaultDeps) {
|
|
|
7686
7686
|
await loopback.close();
|
|
7687
7687
|
}
|
|
7688
7688
|
}
|
|
7689
|
-
async function refreshUserToken(baseUrl, clientId2, token, nowMs = Date.now()) {
|
|
7689
|
+
async function refreshUserToken(baseUrl, clientId2, token, nowMs = Date.now(), organizationId) {
|
|
7690
7690
|
if (!token.refresh_token) throw new CliError("Cached login expired. Run: diverge login");
|
|
7691
7691
|
const payload = await postToken(baseUrl, {
|
|
7692
7692
|
grant_type: "refresh_token",
|
|
7693
7693
|
refresh_token: token.refresh_token,
|
|
7694
|
-
client_id: clientId2
|
|
7694
|
+
client_id: clientId2,
|
|
7695
|
+
...organizationId ? { organization_id: organizationId } : {}
|
|
7695
7696
|
});
|
|
7696
7697
|
return cachedFrom(payload, token.base_url, token.refresh_token, nowMs);
|
|
7697
7698
|
}
|
|
7699
|
+
async function bindOrganization(source, organizationId, nowMs = Date.now()) {
|
|
7700
|
+
const token = loadUserToken(source.tokenFile);
|
|
7701
|
+
if (!token || token.base_url !== source.baseUrl.replace(/\/+$/, "")) {
|
|
7702
|
+
throw new CliError("No cached login for this deployment. Run: diverge login");
|
|
7703
|
+
}
|
|
7704
|
+
const bound = await refreshUserToken(source.baseUrl, source.clientId, token, nowMs, organizationId);
|
|
7705
|
+
saveUserToken(source.tokenFile, bound);
|
|
7706
|
+
return bound;
|
|
7707
|
+
}
|
|
7698
7708
|
async function getUserToken(source, freshForSeconds = 30, nowMs = Date.now()) {
|
|
7699
7709
|
const token = loadUserToken(source.tokenFile);
|
|
7700
7710
|
if (!token || token.base_url !== source.baseUrl.replace(/\/+$/, "")) {
|
|
@@ -8344,6 +8354,38 @@ ${agentsUsage}`);
|
|
|
8344
8354
|
// src/commands/login.ts
|
|
8345
8355
|
import { parseArgs as parseArgs2 } from "node:util";
|
|
8346
8356
|
|
|
8357
|
+
// src/auth/organizations.ts
|
|
8358
|
+
function chooseOrganization(input) {
|
|
8359
|
+
const memberships = input.memberships;
|
|
8360
|
+
const flag = input.flag?.trim();
|
|
8361
|
+
if (flag) {
|
|
8362
|
+
const match = memberships.find((organization) => organization.id === flag || organization.name.toLowerCase() === flag.toLowerCase());
|
|
8363
|
+
if (match) return { kind: "chosen", organizationId: match.id, name: match.name, reason: "flag" };
|
|
8364
|
+
if (input.platformActor) return { kind: "chosen", organizationId: flag, reason: "flag" };
|
|
8365
|
+
throw new CliError(`Not one of your organizations: ${flag}. Yours: ${memberships.map((organization) => `${organization.name} (${organization.id})`).join(", ") || "none"}`);
|
|
8366
|
+
}
|
|
8367
|
+
const remembered = input.remembered?.trim();
|
|
8368
|
+
if (remembered) {
|
|
8369
|
+
const match = memberships.find((organization) => organization.id === remembered);
|
|
8370
|
+
if (match) return { kind: "chosen", organizationId: match.id, name: match.name, reason: "remembered" };
|
|
8371
|
+
if (input.platformActor) return { kind: "chosen", organizationId: remembered, reason: "remembered" };
|
|
8372
|
+
}
|
|
8373
|
+
if (memberships.length === 1) return { kind: "chosen", organizationId: memberships[0].id, name: memberships[0].name, reason: "only" };
|
|
8374
|
+
if (memberships.length === 0) return { kind: "none" };
|
|
8375
|
+
return { kind: "ask", options: memberships };
|
|
8376
|
+
}
|
|
8377
|
+
function organizationMenu(options) {
|
|
8378
|
+
return options.map((organization, index) => ` ${index + 1}. ${organization.name} (${organization.id})`);
|
|
8379
|
+
}
|
|
8380
|
+
function pickFromMenu(answer, options) {
|
|
8381
|
+
const trimmed = answer.trim();
|
|
8382
|
+
const index = Number(trimmed);
|
|
8383
|
+
if (Number.isInteger(index) && index >= 1 && index <= options.length) return options[index - 1];
|
|
8384
|
+
const match = options.find((organization) => organization.id === trimmed || organization.name.toLowerCase() === trimmed.toLowerCase());
|
|
8385
|
+
if (!match) throw new CliError(`Not one of the listed organizations: ${trimmed}`);
|
|
8386
|
+
return match;
|
|
8387
|
+
}
|
|
8388
|
+
|
|
8347
8389
|
// src/auth/userinfo.ts
|
|
8348
8390
|
async function fetchUserInfo(baseUrl, accessToken) {
|
|
8349
8391
|
return fetchJson(userinfoEndpoint(baseUrl), { headers: { Authorization: `Bearer ${accessToken}` }, timeoutMs: 15e3 });
|
|
@@ -8357,12 +8399,25 @@ async function describeAccount(baseUrl, accessToken, fallbackSub, options = {})
|
|
|
8357
8399
|
}
|
|
8358
8400
|
}
|
|
8359
8401
|
|
|
8402
|
+
// src/prompt.ts
|
|
8403
|
+
import readline from "node:readline";
|
|
8404
|
+
function ask(question) {
|
|
8405
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stderr });
|
|
8406
|
+
return new Promise((resolve) => rl.question(question, (answer) => {
|
|
8407
|
+
rl.close();
|
|
8408
|
+
resolve(answer);
|
|
8409
|
+
}));
|
|
8410
|
+
}
|
|
8411
|
+
|
|
8360
8412
|
// src/commands/login.ts
|
|
8361
8413
|
var DEFAULT_SCOPES = "mcp:read mcp:execute inference:execute";
|
|
8362
|
-
var loginUsage = `diverge login [--organization-id <id>] [--scopes "<scopes>"] [--as <email>] [--no-browser] [--api-url <url>]
|
|
8414
|
+
var loginUsage = `diverge login [--organization-id <id|name>] [--scopes "<scopes>"] [--as <email>] [--no-browser] [--api-url <url>]
|
|
8363
8415
|
|
|
8364
|
-
Sign in through the browser
|
|
8365
|
-
|
|
8416
|
+
Sign in through the browser, then choose where to act. The browser only
|
|
8417
|
+
authenticates the person; the organization is chosen here afterwards \u2014 the
|
|
8418
|
+
one named by --organization-id (id or name), else the last login's, else the
|
|
8419
|
+
only membership, else a menu \u2014 and the login is bound to it on the platform.
|
|
8420
|
+
Switch later with: diverge org use <id|name>.
|
|
8366
8421
|
--as <email> names the account: the platform signs that account in instead of
|
|
8367
8422
|
reusing whatever session the browser holds, and issues nothing to any other.
|
|
8368
8423
|
Without --as, the account of the last login is used; switching is explicit.
|
|
@@ -8404,29 +8459,90 @@ async function runLogin(args, io) {
|
|
|
8404
8459
|
baseUrl: apiUrl,
|
|
8405
8460
|
clientId: clientId(io.env),
|
|
8406
8461
|
scopes,
|
|
8407
|
-
organizationId: values["organization-id"],
|
|
8408
|
-
selectOrganization: !values["organization-id"],
|
|
8409
8462
|
openBrowser: !values["no-browser"],
|
|
8410
8463
|
tokenFile: tokenFile(io.env),
|
|
8411
8464
|
loginHint,
|
|
8412
8465
|
print: io.stdout
|
|
8413
8466
|
});
|
|
8414
8467
|
const claims = tokenClaims(token.access_token);
|
|
8415
|
-
|
|
8416
|
-
io.stdout(`Logged in to ${apiUrl} for organization ${claims.organizationId ?? "none"}; token cached (${remaining}s to expiry, auto-refreshes).`);
|
|
8417
|
-
let account;
|
|
8468
|
+
let info;
|
|
8418
8469
|
try {
|
|
8419
|
-
|
|
8470
|
+
info = await fetchUserInfo(apiUrl, token.access_token);
|
|
8420
8471
|
} catch (error) {
|
|
8421
|
-
|
|
8472
|
+
throw new CliError(`Signed in, but the platform could not say who or where (${error instanceof Error ? error.message : String(error)}); run: diverge login`);
|
|
8422
8473
|
}
|
|
8423
|
-
|
|
8424
|
-
|
|
8474
|
+
io.stdout(`Signed in as: ${info.email}`);
|
|
8475
|
+
const bound = await bindChosenOrganization(io, apiUrl, values["organization-id"], config.organization, info);
|
|
8476
|
+
const remaining = Math.max(0, Math.round(bound.token.expires_at - Date.now() / 1e3));
|
|
8477
|
+
io.stdout(`Logged in to ${apiUrl}; token cached (${remaining}s to expiry, auto-refreshes).`);
|
|
8478
|
+
writeConfig({ ...readConfig(io.env), account: info.email, scopes, organization: bound.organizationId }, io.env);
|
|
8425
8479
|
const granted = new Set(claims.scopes ?? []);
|
|
8426
8480
|
const missing = scopes.split(" ").filter((scope) => scope && !granted.has(scope));
|
|
8427
8481
|
if (missing.length) io.stderr(`Not granted at this organization (your roles lack them): ${missing.join(" ")}`);
|
|
8428
8482
|
return 0;
|
|
8429
8483
|
}
|
|
8484
|
+
async function bindChosenOrganization(io, apiUrl, flag, remembered, info) {
|
|
8485
|
+
const memberships = info.organizations ?? [];
|
|
8486
|
+
let choice = chooseOrganization({ flag, remembered, memberships, platformActor: info.platformActor });
|
|
8487
|
+
if (choice.kind === "none") {
|
|
8488
|
+
throw new CliError("You are not a member of any organization; ask an administrator to add you, then sign in again.");
|
|
8489
|
+
}
|
|
8490
|
+
if (choice.kind === "ask") {
|
|
8491
|
+
if (!io.interactive) {
|
|
8492
|
+
throw new CliError(`You belong to several organizations; pass --organization-id <id|name>:
|
|
8493
|
+
${organizationMenu(choice.options).join("\n")}`);
|
|
8494
|
+
}
|
|
8495
|
+
io.stdout("Choose the organization to act in:");
|
|
8496
|
+
for (const line of organizationMenu(choice.options)) io.stdout(line);
|
|
8497
|
+
const picked = pickFromMenu(await ask("Organization (number, id or name): "), choice.options);
|
|
8498
|
+
choice = { kind: "chosen", organizationId: picked.id, name: picked.name, reason: "flag" };
|
|
8499
|
+
}
|
|
8500
|
+
const source = { tokenFile: tokenFile(io.env), baseUrl: apiUrl, clientId: clientId(io.env) };
|
|
8501
|
+
const token = await bindOrganization(source, choice.organizationId);
|
|
8502
|
+
const label = choice.name ? `${choice.name} (${choice.organizationId})` : choice.organizationId;
|
|
8503
|
+
const why = choice.reason === "remembered" ? " (the last login; pass --organization-id to switch)" : choice.reason === "only" ? " (your only organization)" : "";
|
|
8504
|
+
io.stdout(`Organization: ${label}${why}`);
|
|
8505
|
+
return { organizationId: choice.organizationId, token };
|
|
8506
|
+
}
|
|
8507
|
+
|
|
8508
|
+
// src/commands/org.ts
|
|
8509
|
+
import { parseArgs as parseArgs3 } from "node:util";
|
|
8510
|
+
var orgUsage = `diverge org [use <id|name>]
|
|
8511
|
+
|
|
8512
|
+
Without a verb: the organizations you may act in, the bound one marked.
|
|
8513
|
+
use <id|name>: bind the login to that organization on the platform, without a
|
|
8514
|
+
browser; every later command acts there. A platform actor may name an
|
|
8515
|
+
organization they are not a member of.`;
|
|
8516
|
+
async function runOrg(args, io) {
|
|
8517
|
+
const { positionals } = parseArgs3({ args, options: {}, strict: true, allowPositionals: true });
|
|
8518
|
+
const apiUrl = resolveApiUrl(void 0, io.env);
|
|
8519
|
+
const source = { tokenFile: tokenFile(io.env), baseUrl: apiUrl, clientId: clientId(io.env) };
|
|
8520
|
+
const token = await getUserToken(source);
|
|
8521
|
+
const info = await fetchUserInfo(apiUrl, token.access_token);
|
|
8522
|
+
const memberships = info.organizations ?? [];
|
|
8523
|
+
const current = tokenClaims(token.access_token).organizationId ?? void 0;
|
|
8524
|
+
const verb = positionals[0];
|
|
8525
|
+
if (!verb) {
|
|
8526
|
+
if (memberships.length === 0 && !current) {
|
|
8527
|
+
io.stdout("You are not a member of any organization.");
|
|
8528
|
+
return 0;
|
|
8529
|
+
}
|
|
8530
|
+
for (const organization of memberships) io.stdout(`${organization.id === current ? "*" : " "} ${organization.name} (${organization.id})`);
|
|
8531
|
+
if (current && !memberships.some((organization) => organization.id === current)) io.stdout(`* ${current} (not a membership; acting as the platform)`);
|
|
8532
|
+
return 0;
|
|
8533
|
+
}
|
|
8534
|
+
if (verb !== "use") throw new CliError(`Unknown verb: ${verb}
|
|
8535
|
+
|
|
8536
|
+
${orgUsage}`);
|
|
8537
|
+
const target = positionals[1];
|
|
8538
|
+
if (!target) throw new CliError("org use needs an organization id or name");
|
|
8539
|
+
const choice = chooseOrganization({ flag: target, memberships, platformActor: info.platformActor });
|
|
8540
|
+
if (choice.kind !== "chosen") throw new CliError("org use needs an organization id or name");
|
|
8541
|
+
const bound = await bindOrganization(source, choice.organizationId);
|
|
8542
|
+
writeConfig({ ...readConfig(io.env), organization: choice.organizationId }, io.env);
|
|
8543
|
+
io.stdout(`Organization: ${choice.name ? `${choice.name} (${choice.organizationId})` : choice.organizationId}; scopes ${(tokenClaims(bound.access_token).scopes ?? []).join(" ") || "none"}`);
|
|
8544
|
+
return 0;
|
|
8545
|
+
}
|
|
8430
8546
|
|
|
8431
8547
|
// src/commands/logout.ts
|
|
8432
8548
|
var logoutUsage = "diverge logout\n\nRevoke the login's session on the platform and forget it locally.";
|
|
@@ -8524,8 +8640,10 @@ async function runStatus(_args, io) {
|
|
|
8524
8640
|
const remaining = Math.round(token.expires_at - Date.now() / 1e3);
|
|
8525
8641
|
const mismatch = token.base_url !== apiUrl ? ` (for ${token.base_url}, not the configured deployment)` : "";
|
|
8526
8642
|
io.stdout(`Login: ${isFresh(token, 0) ? `valid for ${remaining}s` : "expired (auto-refreshes)"}; refresh token ${token.refresh_token ? "present" : "absent"}${mismatch}`);
|
|
8527
|
-
|
|
8528
|
-
io.stdout(`
|
|
8643
|
+
const account = await signedInAs(token, io);
|
|
8644
|
+
io.stdout(`Signed in as: ${account.line}`);
|
|
8645
|
+
const organization = account.organizations?.find((candidate) => candidate.id === claims.organizationId);
|
|
8646
|
+
io.stdout(`Organization: ${claims.organizationId ? `${organization ? `${organization.name} (${claims.organizationId})` : claims.organizationId}` : "none (run: diverge org use <id|name>)"}`);
|
|
8529
8647
|
io.stdout(`Scopes: ${(claims.scopes ?? []).join(" ") || "none"}`);
|
|
8530
8648
|
io.stdout(describeToolExecution(io.env));
|
|
8531
8649
|
return 0;
|
|
@@ -8536,9 +8654,14 @@ async function signedInAs(cached, io) {
|
|
|
8536
8654
|
try {
|
|
8537
8655
|
accessToken = (await getUserToken({ tokenFile: tokenFile(io.env), baseUrl: cached.base_url, clientId: clientId(io.env) })).access_token;
|
|
8538
8656
|
} catch (error) {
|
|
8539
|
-
return `${sub ?? "unknown user"} (email unavailable: ${error instanceof Error ? error.message : String(error)})
|
|
8657
|
+
return { line: `${sub ?? "unknown user"} (email unavailable: ${error instanceof Error ? error.message : String(error)})` };
|
|
8658
|
+
}
|
|
8659
|
+
try {
|
|
8660
|
+
const info = await fetchUserInfo(cached.base_url, accessToken);
|
|
8661
|
+
return { line: `${info.email} (${info.sub})`, organizations: info.organizations };
|
|
8662
|
+
} catch (error) {
|
|
8663
|
+
return { line: `${sub ?? "unknown user"} (email unavailable: ${error instanceof Error ? error.message : String(error)})` };
|
|
8540
8664
|
}
|
|
8541
|
-
return describeAccount(cached.base_url, accessToken, sub, { withSub: true });
|
|
8542
8665
|
}
|
|
8543
8666
|
|
|
8544
8667
|
// src/commands/token.ts
|
|
@@ -8551,10 +8674,10 @@ async function runToken(_args, io) {
|
|
|
8551
8674
|
}
|
|
8552
8675
|
|
|
8553
8676
|
// src/commands/tools.ts
|
|
8554
|
-
import { parseArgs as
|
|
8677
|
+
import { parseArgs as parseArgs4 } from "node:util";
|
|
8555
8678
|
|
|
8556
8679
|
// src/mcp/bridge.ts
|
|
8557
|
-
import
|
|
8680
|
+
import readline2 from "node:readline";
|
|
8558
8681
|
|
|
8559
8682
|
// src/tools/client.ts
|
|
8560
8683
|
var PENDING_INVOCATION_STATUSES = ["pending", "approved", "executing"];
|
|
@@ -8831,7 +8954,7 @@ var BridgeServer = class {
|
|
|
8831
8954
|
}
|
|
8832
8955
|
};
|
|
8833
8956
|
async function serveBridge(server, input, output) {
|
|
8834
|
-
const lines =
|
|
8957
|
+
const lines = readline2.createInterface({ input, crlfDelay: Infinity });
|
|
8835
8958
|
for await (const raw of lines) {
|
|
8836
8959
|
const line = raw.trim();
|
|
8837
8960
|
if (!line) continue;
|
|
@@ -8998,7 +9121,7 @@ async function runTools(args, io) {
|
|
|
8998
9121
|
}
|
|
8999
9122
|
switch (verb) {
|
|
9000
9123
|
case "list": {
|
|
9001
|
-
const { values } =
|
|
9124
|
+
const { values } = parseArgs4({ args: rest, options: { ...SCOPE_OPTIONS, filter: { type: "string" }, capability: { type: "string" }, json: { type: "boolean", default: false } }, strict: true });
|
|
9002
9125
|
const { client: tools } = await client(values, io);
|
|
9003
9126
|
let list = await tools.listTools();
|
|
9004
9127
|
if (values.filter) list = list.filter((tool) => tool.name.includes(values.filter));
|
|
@@ -9008,7 +9131,7 @@ async function runTools(args, io) {
|
|
|
9008
9131
|
return ExitCode.Ok;
|
|
9009
9132
|
}
|
|
9010
9133
|
case "capabilities": {
|
|
9011
|
-
const { values } =
|
|
9134
|
+
const { values } = parseArgs4({ args: rest, options: { ...SCOPE_OPTIONS, json: { type: "boolean", default: false } }, strict: true });
|
|
9012
9135
|
const { client: tools } = await client(values, io);
|
|
9013
9136
|
const list = await tools.listTools();
|
|
9014
9137
|
if (values.json) io.stdout(JSON.stringify(capabilityClusters(list), null, 2));
|
|
@@ -9016,7 +9139,7 @@ async function runTools(args, io) {
|
|
|
9016
9139
|
return ExitCode.Ok;
|
|
9017
9140
|
}
|
|
9018
9141
|
case "describe": {
|
|
9019
|
-
const { values, positionals } =
|
|
9142
|
+
const { values, positionals } = parseArgs4({ args: rest, options: { ...SCOPE_OPTIONS, json: { type: "boolean", default: false } }, strict: true, allowPositionals: true });
|
|
9020
9143
|
const name = positionals[0];
|
|
9021
9144
|
if (!name) throw new CliError("describe needs a tool name");
|
|
9022
9145
|
const { settings, client: tools } = await client(values, io);
|
|
@@ -9031,7 +9154,7 @@ async function runTools(args, io) {
|
|
|
9031
9154
|
return ExitCode.Ok;
|
|
9032
9155
|
}
|
|
9033
9156
|
case "call": {
|
|
9034
|
-
const { values, positionals } =
|
|
9157
|
+
const { values, positionals } = parseArgs4({ args: rest, options: { ...SCOPE_OPTIONS, "args-json": { type: "string", default: "{}" }, wait: { type: "boolean", default: false }, timeout: { type: "string", default: "600" } }, strict: true, allowPositionals: true });
|
|
9035
9158
|
const name = positionals[0];
|
|
9036
9159
|
if (!name) throw new CliError("call needs a tool name");
|
|
9037
9160
|
let parsedArgs;
|
|
@@ -9060,7 +9183,7 @@ async function runTools(args, io) {
|
|
|
9060
9183
|
return emit(io, settledOutcome(invocation));
|
|
9061
9184
|
}
|
|
9062
9185
|
case "invocation": {
|
|
9063
|
-
const { values, positionals } =
|
|
9186
|
+
const { values, positionals } = parseArgs4({ args: rest, options: { ...SCOPE_OPTIONS, wait: { type: "boolean", default: false }, timeout: { type: "string", default: "600" }, json: { type: "boolean", default: false } }, strict: true, allowPositionals: true });
|
|
9064
9187
|
const id = positionals[0];
|
|
9065
9188
|
if (!id) throw new CliError("invocation needs an id");
|
|
9066
9189
|
const { client: tools } = await client(values, io);
|
|
@@ -9078,7 +9201,7 @@ async function runTools(args, io) {
|
|
|
9078
9201
|
return emit(io, settledOutcome(invocation));
|
|
9079
9202
|
}
|
|
9080
9203
|
case "bridge": {
|
|
9081
|
-
const { values } =
|
|
9204
|
+
const { values } = parseArgs4({ args: rest, options: { ...SCOPE_OPTIONS, tools: { type: "string" } }, strict: true });
|
|
9082
9205
|
const { client: tools } = await client(values, io);
|
|
9083
9206
|
const allow = (values.tools ?? "").split(",").map((name) => name.trim()).filter(Boolean);
|
|
9084
9207
|
return serveBridge(new BridgeServer(tools, { tools: allow }), process.stdin, process.stdout);
|
|
@@ -9092,7 +9215,7 @@ ${toolsUsage}`);
|
|
|
9092
9215
|
|
|
9093
9216
|
// src/commands/plugins.ts
|
|
9094
9217
|
import fs7 from "node:fs";
|
|
9095
|
-
import { parseArgs as
|
|
9218
|
+
import { parseArgs as parseArgs5 } from "node:util";
|
|
9096
9219
|
var pluginsUsage = `diverge plugins <validate|publish|list|retire> [--organization-id <id>] ...
|
|
9097
9220
|
|
|
9098
9221
|
validate <manifest.json> (dry run: the platform's full validation, nothing stored)
|
|
@@ -9155,7 +9278,7 @@ async function runPlugins(args, io) {
|
|
|
9155
9278
|
}
|
|
9156
9279
|
switch (verb) {
|
|
9157
9280
|
case "validate": {
|
|
9158
|
-
const { values, positionals } =
|
|
9281
|
+
const { values, positionals } = parseArgs5({ args: rest, options: { ...SCOPE_OPTIONS2, json: { type: "boolean", default: false } }, allowPositionals: true, strict: true });
|
|
9159
9282
|
const manifest = readManifest(positionals[0]);
|
|
9160
9283
|
const tools = await client2(values, io);
|
|
9161
9284
|
const outcome = await tools.publishPlugin(manifest, { dryRun: true });
|
|
@@ -9172,7 +9295,7 @@ async function runPlugins(args, io) {
|
|
|
9172
9295
|
return ExitCode.Ok;
|
|
9173
9296
|
}
|
|
9174
9297
|
case "publish": {
|
|
9175
|
-
const { values, positionals } =
|
|
9298
|
+
const { values, positionals } = parseArgs5({ args: rest, options: { ...SCOPE_OPTIONS2, json: { type: "boolean", default: false } }, allowPositionals: true, strict: true });
|
|
9176
9299
|
const manifest = readManifest(positionals[0]);
|
|
9177
9300
|
const tools = await client2(values, io);
|
|
9178
9301
|
const outcome = await tools.publishPlugin(manifest, { dryRun: false });
|
|
@@ -9190,7 +9313,7 @@ async function runPlugins(args, io) {
|
|
|
9190
9313
|
return ExitCode.Ok;
|
|
9191
9314
|
}
|
|
9192
9315
|
case "list": {
|
|
9193
|
-
const { values } =
|
|
9316
|
+
const { values } = parseArgs5({ args: rest, options: { ...SCOPE_OPTIONS2, json: { type: "boolean", default: false } }, strict: true });
|
|
9194
9317
|
const tools = await client2(values, io);
|
|
9195
9318
|
const plugins = await tools.listPlugins();
|
|
9196
9319
|
if (values.json) io.stdout(JSON.stringify(plugins, null, 2));
|
|
@@ -9199,7 +9322,7 @@ async function runPlugins(args, io) {
|
|
|
9199
9322
|
return ExitCode.Ok;
|
|
9200
9323
|
}
|
|
9201
9324
|
case "retire": {
|
|
9202
|
-
const { values, positionals } =
|
|
9325
|
+
const { values, positionals } = parseArgs5({ args: rest, options: SCOPE_OPTIONS2, allowPositionals: true, strict: true });
|
|
9203
9326
|
const pluginId = positionals[0];
|
|
9204
9327
|
if (!pluginId) throw new CliError(`A plugin id is required.
|
|
9205
9328
|
|
|
@@ -9269,6 +9392,7 @@ var COMMANDS = [
|
|
|
9269
9392
|
{ name: "login", summary: "Sign in through the browser", usage: loginUsage, run: runLogin },
|
|
9270
9393
|
{ name: "logout", summary: "Revoke the login and forget it", usage: logoutUsage, run: runLogout },
|
|
9271
9394
|
{ name: "status", summary: "Show the deployment and the cached login", usage: statusUsage, run: runStatus },
|
|
9395
|
+
{ name: "org", summary: "Show or switch the organization the login acts in", usage: orgUsage, run: runOrg },
|
|
9272
9396
|
{ name: "token", summary: "Print a fresh access token", usage: tokenUsage, run: runToken },
|
|
9273
9397
|
{ name: "agents", summary: "Point a coding agent at the model gateway (setup, run, status)", usage: agentsUsage, run: runAgents },
|
|
9274
9398
|
{ name: "tools", summary: "Discover and execute platform tools; raise and read approvals", usage: toolsUsage, run: runTools },
|