@rosthq/cli 0.5.5 → 0.5.6

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/dist/index.d.ts CHANGED
@@ -5,6 +5,7 @@ import { type TokenStore } from "./token-store.js";
5
5
  type CliIo = {
6
6
  stdout: Pick<NodeJS.WriteStream, "write">;
7
7
  stderr: Pick<NodeJS.WriteStream, "write">;
8
+ interactive?: boolean;
8
9
  };
9
10
  type MainOptions = {
10
11
  store?: TokenStore;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAMA,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAoB,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AACzE,OAAO,EAAoB,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAYrE,KAAK,KAAK,GAAG;IACX,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;IAC1C,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;CAC3C,CAAC;AAEF,KAAK,WAAW,GAAG;IACjB,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,EAAE,CAAC,EAAE,KAAK,CAAC;IACX,KAAK,CAAC,EAAE,OAAO,gBAAgB,CAAC;IAChC,WAAW,CAAC,EAAE,OAAO,mBAAmB,CAAC;CAC1C,CAAC;AAEF,wBAAsB,IAAI,CAAC,IAAI,WAAwB,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,CAiKnG;AAiWD,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAUxF"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAMA,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAoB,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AACzE,OAAO,EAAoB,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAYrE,KAAK,KAAK,GAAG;IACX,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;IAC1C,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;IAK1C,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,CAAC;AAEF,KAAK,WAAW,GAAG;IACjB,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,EAAE,CAAC,EAAE,KAAK,CAAC;IACX,KAAK,CAAC,EAAE,OAAO,gBAAgB,CAAC;IAChC,WAAW,CAAC,EAAE,OAAO,mBAAmB,CAAC;CAC1C,CAAC;AAEF,wBAAsB,IAAI,CAAC,IAAI,WAAwB,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,CAyKnG;AAwXD,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAUxF"}
package/dist/index.js CHANGED
@@ -42241,7 +42241,7 @@ Agents should explain the job, the required tool category, the minimum permissio
42241
42241
  order: 48,
42242
42242
  title: "CLI and MCP installation guide",
42243
42243
  summary: "Install the public CLI, register remote token-backed MCP clients, and find the full command and tool catalog.",
42244
- version: "2026-06-18.7",
42244
+ version: "2026-06-18.8",
42245
42245
  public: true,
42246
42246
  audiences: ["human", "cli", "mcp", "in_app_agent"],
42247
42247
  stages: ["company_setup", "staffing"],
@@ -42306,7 +42306,7 @@ The MCP server is remote and token-backed. There is no local MCP daemon to insta
42306
42306
  A headless agent cannot complete setup unattended. Two things always require a human, so plan to announce the handoff rather than stall silently:
42307
42307
 
42308
42308
  - **Device-code approval at first login.** \`{{cli}} login --device\` prints a code; a human must open the workspace URL in a browser, sign in with Google, match the code, and approve.
42309
- - **Durable gated commands.** Setting or approving a Charter, staffing a seat, and taking an agent live each open a confirmation that a human approves (an agent never approves its own request \u2014 see the confirmations-guide). The CLI surfaces the \`confirmation_id\` and an \`approveVia\` URL for the human. (\`{{cli}} mcp install\` is the exception: it completes its own token-mint approval inline for the operator who runs it \u2014 see Approving the token mint below \u2014 so it is not a separate browser handoff.)
42309
+ - **Durable gated commands.** Setting or approving a Charter, staffing a seat, and taking an agent live each open a confirmation that a human approves (an agent never approves its own request \u2014 see the confirmations-guide). The CLI surfaces the \`confirmation_id\` and an \`approveVia\` URL for the human. (\`{{cli}} mcp install\` is a partial exception: for an **interactive** operator it completes its own token-mint approval inline; in a **headless/agent** session it surfaces the confirmation and stops unless \`--skip-permissions\` / \`{{envPrefix}}_CLI_SKIP_PERMISSIONS=1\` is set \u2014 see Approving the token mint below.)
42310
42310
 
42311
42311
  Treat these as blocking prerequisites: the agent prepares the request and waits for the human approver.
42312
42312
 
@@ -42420,6 +42420,8 @@ Or use the one-shot helper: \`{{cli}} init\` logs in when needed, optionally sel
42420
42420
 
42421
42421
  A direct \`mcp install\` now **requires an explicit \`--scope\`** \u2014 there is no silent default. Choose \`--scope seat --seat-id <id>\` (the narrowest scope, limited to one seat's Charter and permission manifest \u2014 prefer it for day-to-day operation) or \`--scope tenant-admin\` (can administer the whole company \u2014 reserve it for initial setup). Running \`mcp install\` without \`--scope\` errors and mints nothing, naming both options. (The first-run helper \`{{cli}} init\` is the exception: it defaults to \`--scope tenant-admin\` because no seats exist yet at setup; and \`--rotate\` inherits the old token's scope, so it does not need \`--scope\` either.)
42422
42422
 
42423
+ \`mcp install\` accepts an optional \`--skip-permissions\` flag (equivalently \`{{envPrefix}}_CLI_SKIP_PERMISSIONS=1\`). It governs the token-mint approval in a non-interactive session \u2014 see Approving the token mint below. An interactive operator never needs it.
42424
+
42423
42425
  Claude Code (tenant-admin):
42424
42426
 
42425
42427
  \`\`\`bash
@@ -42450,9 +42452,13 @@ The \`<seat-id>\` comes from \`{{cli}} command seat.create\` output or \`rost_ge
42450
42452
 
42451
42453
  ### Approving the token mint
42452
42454
 
42453
- Minting a token is a human-gated authority change at the command layer. For an interactive operator, \`{{cli}} mcp install\` completes that approval **inline**: the operator who ran the command is the human in the loop, so the CLI runs the gated mint, completes the confirmation for that same command, and prints the registration block \u2014 a single step, no separate URL to click.
42455
+ Minting a token (and the inline revoke that \`--rotate\` performs) is a human-gated authority change at the command layer. How \`{{cli}} mcp install\` handles that approval depends on whether it runs in an interactive session:
42456
+
42457
+ - **Interactive operator (a human at a real terminal).** The CLI completes the approval **inline**: the operator who ran the command is the human in the loop, so it runs the gated mint, completes the confirmation for that same command, and prints the registration block \u2014 a single step, no separate URL to click.
42458
+ - **Non-interactive / headless / agent session.** The CLI does **not** approve its own request. By default it **surfaces the confirmation and stops**, minting nothing: it prints the \`confirmation_id\`, the exact \`{{cli}} command confirmation.approve --json '{"confirmation_id":"<id>"}'\` command, and the \`approveVia\` URL when the server provided one, then exits non-zero ("pending human approval"). A human then approves it (in a browser or with that approve command) \u2014 and that approval **executes the mint and returns the token in the approve output** (shown once), so register it with your client from there. Do **not** re-run \`mcp install\` after approving: that starts a second mint and orphans the first token. (For an unattended agent that should mint and register in one step, use \`--skip-permissions\` below.)
42459
+ - **Opting into auto-approval in a headless session.** Pass \`--skip-permissions\` on \`mcp install\`, or set \`{{envPrefix}}_CLI_SKIP_PERMISSIONS=1\`, to auto-approve the mint/revoke confirmation inline even without a TTY. This is a deliberate loosening (the running session stands in for the human approver) \u2014 use it only for trusted automation where you accept that the agent approves its own token mint.
42454
42460
 
42455
- The broader rule still holds for durable changes an agent proposes \u2014 charters, decisions, compass and charter amendments \u2014 where an agent never approves its own request and a human approves the surfaced \`approveVia\` confirmation. See the confirmations-guide for the four confirmation levels and that flow. (For a fully unattended headless agent session, treat the inline mint as the one place the running operator's identity stands in for the approval; if you need a separate human in that loop, raise it with your operator.)
42461
+ The broader rule still holds for durable changes an agent proposes \u2014 charters, decisions, compass and charter amendments \u2014 where an agent never approves its own request and a human approves the surfaced \`approveVia\` confirmation. See the confirmations-guide for the four confirmation levels and that flow.
42456
42462
 
42457
42463
  ### Handling the printed token (read this before you paste anything)
42458
42464
 
@@ -42654,8 +42660,9 @@ These ergonomic wrappers (including the \`{{cli}} agent\` group) require **{{cli
42654
42660
 
42655
42661
  | Command | Purpose | Scope | Safe example |
42656
42662
  |---|---|---|---|
42657
- | \`{{cli}} mcp install --client claude-code|codex|cursor --scope tenant-admin|seat [--seat-id <id>] [--expires-in <days>|--no-expiry]\` | **Direct install** syntax. \`--scope\` is **required** (seat is narrower \u2014 prefer it for day-to-day; tenant-admin can administer the whole company). \`--expires-in <days>\` (1..365) or \`--no-expiry\` sets the token TTL (default 90 days). | Tenant | \`{{cli}} mcp install --client codex --scope tenant-admin --expires-in 30\` |
42663
+ | \`{{cli}} mcp install --client claude-code|codex|cursor --scope tenant-admin|seat [--seat-id <id>] [--expires-in <days>|--no-expiry] [--skip-permissions]\` | **Direct install** syntax. \`--scope\` is **required** (seat is narrower \u2014 prefer it for day-to-day; tenant-admin can administer the whole company). \`--expires-in <days>\` (1..365) or \`--no-expiry\` sets the token TTL (default 90 days). \`--skip-permissions\` auto-approves the token-mint confirmation in a non-interactive session (see below). | Tenant | \`{{cli}} mcp install --client codex --scope tenant-admin --expires-in 30\` |
42658
42664
  | \`{{cli}} mcp install --client claude-code|codex|cursor --rotate <old-token-id> (inherits the old token's scope; no --scope)\` | **Rotate** syntax. Mints a replacement, **inherits the old token's scope/seat** (so do not pass \`--scope\`), prints the new registration block, and revokes the old token. | Tenant | \`{{cli}} mcp install --client codex --rotate <old-token-id>\` |
42665
+ | \`{{cli}} mcp install ... --skip-permissions (or {{envPrefix}}_CLI_SKIP_PERMISSIONS=1 \u2014 auto-approves the token-mint confirmation in a non-interactive session)\` | **Skip-permissions** opt-in. In a headless/agent session, auto-approve the \`human_required\` token-mint (and rotate revoke) confirmation inline instead of surfacing it for a human (a deliberate loosening). An interactive operator never needs it. | Tenant | \`{{cli}} mcp install --client codex --scope seat --seat-id <seat-id> --skip-permissions\` |
42659
42666
  | \`{{cli}} mcp install --client claude-code --scope tenant-admin\` | Mint a tenant-admin MCP token and print a Claude Code registration command. | Tenant | \`{{cli}} mcp install --client claude-code --scope tenant-admin\` |
42660
42667
  | \`{{cli}} mcp install --client codex --scope tenant-admin\` | Mint a tenant-admin MCP token and print Codex TOML. | Tenant | \`{{cli}} mcp install --client codex --scope tenant-admin\` |
42661
42668
  | \`{{cli}} mcp install --client cursor --scope tenant-admin\` | Mint a tenant-admin MCP token and print Cursor JSON. | Tenant | \`{{cli}} mcp install --client cursor --scope tenant-admin\` |
@@ -44268,9 +44275,14 @@ var mcpTokenListEntrySchema = external_exports.object({
44268
44275
  var mcpTokenListOutputSchema = external_exports.object({
44269
44276
  tokens: external_exports.array(mcpTokenListEntrySchema)
44270
44277
  }).passthrough();
44278
+ var approveViaSchema = external_exports.object({
44279
+ webUrl: external_exports.string().min(1).optional(),
44280
+ cliCommand: external_exports.string().min(1).optional()
44281
+ }).passthrough();
44271
44282
  var pendingConfirmationSchema = external_exports.object({
44272
44283
  confirmationId: external_exports.string().min(1),
44273
- commandId: external_exports.string().min(1)
44284
+ commandId: external_exports.string().min(1),
44285
+ approveVia: approveViaSchema.optional().catch(void 0)
44274
44286
  }).passthrough();
44275
44287
  var confirmationApprovalOutputSchema = external_exports.object({
44276
44288
  confirmation_id: external_exports.string().min(1),
@@ -44286,6 +44298,7 @@ function parseMcpInstallOptions(args) {
44286
44298
  let expiresInDays;
44287
44299
  let noExpiry = false;
44288
44300
  let rotateTokenId;
44301
+ let skipPermissions = false;
44289
44302
  for (let index = 0; index < args.length; index += 1) {
44290
44303
  const arg = args[index];
44291
44304
  if (arg === "--client") {
@@ -44308,6 +44321,8 @@ function parseMcpInstallOptions(args) {
44308
44321
  index += 1;
44309
44322
  } else if (arg === "--json") {
44310
44323
  json2 = true;
44324
+ } else if (arg === "--skip-permissions") {
44325
+ skipPermissions = true;
44311
44326
  } else {
44312
44327
  throw new Error(`Unknown mcp install option: ${arg}`);
44313
44328
  }
@@ -44328,24 +44343,71 @@ function parseMcpInstallOptions(args) {
44328
44343
  ...seatId === void 0 ? {} : { seatId },
44329
44344
  json: json2,
44330
44345
  expiry,
44331
- ...rotateTokenId === void 0 ? {} : { rotateTokenId }
44346
+ ...rotateTokenId === void 0 ? {} : { rotateTokenId },
44347
+ skipPermissions
44332
44348
  };
44333
44349
  }
44334
44350
  var MISSING_SCOPE_MESSAGE = `${cliBrand.binName} mcp install requires an explicit --scope. Choose: --scope seat --seat-id <id> (narrower \u2014 limited to one seat's Charter and permission manifest; prefer this for day-to-day operation), or --scope tenant-admin (can administer the whole company \u2014 reserve it for initial setup). Find a seat id with: ${cliBrand.binName} command graph.get --json '{}'.`;
44335
44351
  var MCP_TOKEN_CAUTION = "Security: this minted MCP token is a live credential that lands in the client's plaintext config \u2014 prefer the narrowest scope (--scope seat --seat-id <id>) and revoke it immediately if it leaks.";
44336
44352
  var NO_EXPIRY_WARNING = "Warning: --no-expiry mints a token with no practical expiry (a ~100-year TTL). This is a long-lived credential by choice \u2014 rotate it deliberately and revoke immediately if it leaks.";
44353
+ var PendingConfirmationError = class extends Error {
44354
+ confirmationId;
44355
+ commandId;
44356
+ approveCommand;
44357
+ approveUrl;
44358
+ constructor(input) {
44359
+ super(`Pending human approval for ${input.commandId} (confirmation ${input.confirmationId}).`);
44360
+ this.name = "PendingConfirmationError";
44361
+ this.confirmationId = input.confirmationId;
44362
+ this.commandId = input.commandId;
44363
+ this.approveCommand = input.approveCommand;
44364
+ if (input.approveUrl !== void 0) {
44365
+ this.approveUrl = input.approveUrl;
44366
+ }
44367
+ }
44368
+ // The multi-line human-handoff message rendered on stderr by the caller. It
44369
+ // names the gated command, the confirmation id, the exact approve command, and
44370
+ // the approveVia URL when the server provided one.
44371
+ toHandoffMessage() {
44372
+ const isRevoke = this.commandId === "mcp_token.revoke";
44373
+ const lines = isRevoke ? [
44374
+ `Pending human approval: revoking the old token (${this.commandId}) requires a human to approve confirmation ${this.confirmationId}.`,
44375
+ "The new token was minted and registered, but the OLD token is still live until its revocation is approved.",
44376
+ `Approve the revocation: ${this.approveCommand}`
44377
+ ] : [
44378
+ `Pending human approval: ${this.commandId} requires a human to approve confirmation ${this.confirmationId} before the MCP token is minted.`,
44379
+ "This is a non-interactive session and --skip-permissions is not set, so nothing was minted yet.",
44380
+ // confirmation.approve EXECUTES the deferred mint and returns the token in
44381
+ // its own output (shown once) — it does not just unlock a re-run. So the
44382
+ // approver registers the token from that output; re-running mcp install
44383
+ // would start a SECOND mint and orphan the first.
44384
+ `A human approves with: ${this.approveCommand} \u2014 this mints the token and returns it in that command's output (shown once). Register it with your client from there; do not re-run mcp install afterward (that starts a new mint).`
44385
+ ];
44386
+ if (this.approveUrl !== void 0) {
44387
+ lines.push(`Or approve in a browser: ${this.approveUrl}`);
44388
+ }
44389
+ lines.push(
44390
+ `To auto-approve inline in a headless session instead, pass --skip-permissions or set ${brandEnvKey3("CLI_SKIP_PERMISSIONS")}=1 (a deliberate loosening).`
44391
+ );
44392
+ return lines.join("\n");
44393
+ }
44394
+ };
44395
+ function brandEnvKey3(suffix) {
44396
+ return `${cliBrand.envPrefix}_${suffix}`;
44397
+ }
44337
44398
  async function renderMcpInstall(input) {
44338
44399
  const stderrLines = [];
44400
+ const canAutoApprove = input.canAutoApprove ?? false;
44339
44401
  if (input.options.rotateTokenId === void 0 && input.options.scope === void 0) {
44340
44402
  throw new Error(MISSING_SCOPE_MESSAGE);
44341
44403
  }
44342
- const mintScope = input.options.rotateTokenId === void 0 ? { scope: input.options.scope, ...input.options.seatId === void 0 ? {} : { seatId: input.options.seatId } } : await resolveRotationScope(input.client, input.options);
44343
- const token = await createMcpToken(input.client, mcpTokenCreateBody(mintScope, input.options.expiry));
44404
+ const mintScope = input.options.rotateTokenId === void 0 ? { scope: input.options.scope, ...input.options.seatId === void 0 ? {} : { seatId: input.options.seatId } } : await resolveRotationScope(input.client, input.options, canAutoApprove);
44405
+ const token = await createMcpToken(input.client, mcpTokenCreateBody(mintScope, input.options.expiry), canAutoApprove);
44344
44406
  let rotationOldRevoked = null;
44345
44407
  if (input.options.rotateTokenId !== void 0) {
44346
44408
  const oldTokenId = input.options.rotateTokenId;
44347
44409
  try {
44348
- const output = await executeWithConfirmation(input.client, "mcp_token.revoke", { token_id: oldTokenId });
44410
+ const output = await executeWithConfirmation(input.client, "mcp_token.revoke", { token_id: oldTokenId }, canAutoApprove);
44349
44411
  const revoke = mcpTokenRevokeOutputSchema.safeParse(output);
44350
44412
  rotationOldRevoked = revoke.success && revoke.data.revoked === true;
44351
44413
  if (!rotationOldRevoked) {
@@ -44355,6 +44417,9 @@ async function renderMcpInstall(input) {
44355
44417
  );
44356
44418
  }
44357
44419
  } catch (error51) {
44420
+ if (error51 instanceof PendingConfirmationError) {
44421
+ throw error51;
44422
+ }
44358
44423
  rotationOldRevoked = false;
44359
44424
  stderrLines.push(
44360
44425
  `Warning: the new token (${token.token_id}) was minted, but revoking the old token (${oldTokenId}) failed: ${revokeFailureReason(error51)}. It is still live. Revoke it by hand: ${cliBrand.binName} command mcp_token.revoke --json '{"token_id":"${oldTokenId}"}'`
@@ -44423,9 +44488,9 @@ function mcpTokenCreateBody(mint, expiry) {
44423
44488
  }
44424
44489
  return base;
44425
44490
  }
44426
- async function resolveRotationScope(client, options) {
44491
+ async function resolveRotationScope(client, options, canAutoApprove) {
44427
44492
  const oldTokenId = options.rotateTokenId;
44428
- const listOutput = await executeWithConfirmation(client, "mcp_token.list", { include_revoked: true });
44493
+ const listOutput = await executeWithConfirmation(client, "mcp_token.list", { include_revoked: true }, canAutoApprove);
44429
44494
  const parsed = mcpTokenListOutputSchema.safeParse(listOutput);
44430
44495
  if (!parsed.success) {
44431
44496
  throw new Error("Could not read the token list to rotate \u2014 mcp_token.list returned an unexpected shape.");
@@ -44488,11 +44553,11 @@ function revokeFailureReason(error51) {
44488
44553
  }
44489
44554
  return "unknown error";
44490
44555
  }
44491
- async function createMcpToken(client, body) {
44492
- const output = await executeWithConfirmation(client, "mcp_token.create", body);
44556
+ async function createMcpToken(client, body, canAutoApprove) {
44557
+ const output = await executeWithConfirmation(client, "mcp_token.create", body, canAutoApprove);
44493
44558
  return mcpTokenOutputSchema.parse(output);
44494
44559
  }
44495
- async function executeWithConfirmation(client, commandId, body) {
44560
+ async function executeWithConfirmation(client, commandId, body, canAutoApprove) {
44496
44561
  try {
44497
44562
  const result = await client.execute(commandId, body);
44498
44563
  return result.output;
@@ -44501,6 +44566,14 @@ async function executeWithConfirmation(client, commandId, body) {
44501
44566
  if (!pending) {
44502
44567
  throw error51;
44503
44568
  }
44569
+ if (!canAutoApprove) {
44570
+ throw new PendingConfirmationError({
44571
+ confirmationId: pending.confirmationId,
44572
+ commandId: pending.commandId,
44573
+ approveCommand: `${cliBrand.binName} command confirmation.approve --json '{"confirmation_id":"${pending.confirmationId}"}'`,
44574
+ ...pending.approveVia?.webUrl === void 0 ? {} : { approveUrl: pending.approveVia.webUrl }
44575
+ });
44576
+ }
44504
44577
  const approved = await client.execute("confirmation.approve", {
44505
44578
  confirmation_id: pending.confirmationId
44506
44579
  });
@@ -45865,7 +45938,15 @@ function ensureTrailingSlash2(value) {
45865
45938
 
45866
45939
  // src/index.ts
45867
45940
  async function main(argv = process.argv.slice(2), options = {}) {
45868
- const io = options.io ?? { stdout: process.stdout, stderr: process.stderr };
45941
+ const io = options.io ?? {
45942
+ stdout: process.stdout,
45943
+ stderr: process.stderr,
45944
+ // DER-832: an interactive session is a human at a real terminal — BOTH stdin
45945
+ // and stdout must be TTYs. A piped/headless/agent session fails this and so
45946
+ // will not auto-approve its own mint/revoke confirmation unless skip-
45947
+ // permissions is explicitly enabled.
45948
+ interactive: process.stdin.isTTY === true && process.stdout.isTTY === true
45949
+ };
45869
45950
  const login = options.login ?? loginWithBrowser;
45870
45951
  const deviceLogin = options.deviceLogin ?? loginWithDeviceCode;
45871
45952
  const [rawCommand, ...args] = argv;
@@ -46152,23 +46233,28 @@ async function executeOnboard(io, client, args) {
46152
46233
  `);
46153
46234
  return 1;
46154
46235
  }
46155
- async function executeMcp(io, client, appUrl2, args) {
46236
+ async function executeMcp(io, client, appUrl2, args, env = process.env) {
46156
46237
  if (args[0] !== "install") {
46157
46238
  io.stderr.write(
46158
46239
  `Usage:
46159
- ${cliBrand.binName} mcp install --client claude-code|codex|cursor --scope tenant-admin|seat [--seat-id <id>] [--expires-in <days>|--no-expiry]
46240
+ ${cliBrand.binName} mcp install --client claude-code|codex|cursor --scope tenant-admin|seat [--seat-id <id>] [--expires-in <days>|--no-expiry] [--skip-permissions]
46160
46241
  Direct install \u2014 --scope is required (seat is narrower; prefer it for day-to-day).
46161
- ${cliBrand.binName} mcp install --client claude-code|codex|cursor --rotate <old-token-id>
46242
+ ${cliBrand.binName} mcp install --client claude-code|codex|cursor --rotate <old-token-id> [--skip-permissions]
46162
46243
  Rotate in place \u2014 inherits the old token's scope, so do not pass --scope.
46244
+ --skip-permissions (or ${cliBrand.envPrefix}_CLI_SKIP_PERMISSIONS=1) auto-approves the token-mint confirmation in a non-interactive session.
46163
46245
  `
46164
46246
  );
46165
46247
  return 1;
46166
46248
  }
46167
46249
  try {
46250
+ const options = parseMcpInstallOptions(args.slice(1));
46251
+ const envSkipPermissions = env[`${cliBrand.envPrefix}_CLI_SKIP_PERMISSIONS`] === "1";
46252
+ const canAutoApprove = io.interactive === true || options.skipPermissions || envSkipPermissions;
46168
46253
  const rendered = await renderMcpInstall({
46169
46254
  client,
46170
46255
  appUrl: appUrl2,
46171
- options: parseMcpInstallOptions(args.slice(1))
46256
+ options,
46257
+ canAutoApprove
46172
46258
  });
46173
46259
  io.stdout.write(rendered.stdout);
46174
46260
  if (rendered.stderr) {
@@ -46176,6 +46262,11 @@ async function executeMcp(io, client, appUrl2, args) {
46176
46262
  }
46177
46263
  return 0;
46178
46264
  } catch (error51) {
46265
+ if (error51 instanceof PendingConfirmationError) {
46266
+ io.stderr.write(`${redactForLog(error51.toHandoffMessage())}
46267
+ `);
46268
+ return 1;
46269
+ }
46179
46270
  if (error51 instanceof CommandClientError) {
46180
46271
  return printCommandError(io, error51);
46181
46272
  }
@@ -46289,8 +46380,9 @@ function printUsage(io) {
46289
46380
  ...operationUsageLines(cliBrand.binName),
46290
46381
  `${cliBrand.binName} onboard status`,
46291
46382
  `${cliBrand.binName} onboard run`,
46292
- `${cliBrand.binName} mcp install --client claude-code|codex|cursor --scope tenant-admin|seat [--seat-id <id>] [--expires-in <days>|--no-expiry]`,
46383
+ `${cliBrand.binName} mcp install --client claude-code|codex|cursor --scope tenant-admin|seat [--seat-id <id>] [--expires-in <days>|--no-expiry] [--skip-permissions]`,
46293
46384
  `${cliBrand.binName} mcp install --client claude-code|codex|cursor --rotate <old-token-id> (inherits the old token's scope; no --scope)`,
46385
+ `${cliBrand.binName} mcp install ... --skip-permissions (or ${cliBrand.envPrefix}_CLI_SKIP_PERMISSIONS=1 \u2014 auto-approves the token-mint confirmation in a non-interactive session)`,
46294
46386
  `${cliBrand.binName} init [--client claude-code|codex|cursor] (defaults --scope tenant-admin)`,
46295
46387
  `${cliBrand.binName} docs`,
46296
46388
  `${cliBrand.binName} reference <list|search|get> [options]`,