switchroom 0.13.12 → 0.13.14

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.
@@ -26509,17 +26509,34 @@ var init_wait = __esm(() => {
26509
26509
  // src/cli/drive.ts
26510
26510
  var exports_drive = {};
26511
26511
  __export(exports_drive, {
26512
+ workspaceScopesForTier: () => workspaceScopesForTier,
26513
+ selectGoogleWorkspaceScopes: () => selectGoogleWorkspaceScopes,
26512
26514
  selectDriveAccountScopes: () => selectDriveAccountScopes,
26513
26515
  runDriveOAuthFlow: () => runDriveOAuthFlow,
26514
26516
  registerDriveCommand: () => registerDriveCommand,
26515
26517
  __test: () => __test,
26518
+ GOOGLE_SLIDES_SCOPE: () => GOOGLE_SLIDES_SCOPE,
26519
+ GOOGLE_SHEETS_SCOPE: () => GOOGLE_SHEETS_SCOPE,
26520
+ GOOGLE_DOCS_SCOPE: () => GOOGLE_DOCS_SCOPE,
26516
26521
  DRIVE_WRITE_SCOPES: () => DRIVE_WRITE_SCOPES,
26517
26522
  DRIVE_READONLY_SCOPES: () => DRIVE_READONLY_SCOPES
26518
26523
  });
26519
26524
  import { createInterface as createInterface2 } from "node:readline";
26525
+ function workspaceScopesForTier(tier) {
26526
+ const docScopes = [GOOGLE_DOCS_SCOPE, GOOGLE_SHEETS_SCOPE];
26527
+ if (tier === "extended" || tier === "complete") {
26528
+ return [...docScopes, GOOGLE_SLIDES_SCOPE];
26529
+ }
26530
+ return docScopes;
26531
+ }
26520
26532
  function selectDriveAccountScopes(write) {
26521
26533
  return write ? DRIVE_WRITE_SCOPES : DRIVE_READONLY_SCOPES;
26522
26534
  }
26535
+ function selectGoogleWorkspaceScopes(opts) {
26536
+ const base = selectDriveAccountScopes(opts.write);
26537
+ const workspace = workspaceScopesForTier(opts.tier ?? "core");
26538
+ return [...new Set([...base, ...workspace])];
26539
+ }
26523
26540
  function getVaultPath(configPath) {
26524
26541
  try {
26525
26542
  const config = loadConfig(configPath);
@@ -26932,7 +26949,7 @@ function registerDriveCommand(program3, deps = {}) {
26932
26949
  await runDisconnect({ agentName: agent }, deps);
26933
26950
  });
26934
26951
  }
26935
- var EXIT_OK = 0, EXIT_DENIED = 1, EXIT_TIMEOUT = 2, EXIT_RATE_LIMITED = 3, EXIT_ERROR = 4, EXIT_ABORTED = 130, DRIVE_READONLY_SCOPES, DRIVE_WRITE_SCOPES, DEFAULT_SCOPES, __test;
26952
+ var EXIT_OK = 0, EXIT_DENIED = 1, EXIT_TIMEOUT = 2, EXIT_RATE_LIMITED = 3, EXIT_ERROR = 4, EXIT_ABORTED = 130, DRIVE_READONLY_SCOPES, DRIVE_WRITE_SCOPES, DEFAULT_SCOPES, GOOGLE_DOCS_SCOPE = "https://www.googleapis.com/auth/documents", GOOGLE_SHEETS_SCOPE = "https://www.googleapis.com/auth/spreadsheets", GOOGLE_SLIDES_SCOPE = "https://www.googleapis.com/auth/presentations", __test;
26936
26953
  var init_drive = __esm(() => {
26937
26954
  init_source();
26938
26955
  init_loader();
@@ -47314,8 +47331,8 @@ var {
47314
47331
  } = import__.default;
47315
47332
 
47316
47333
  // src/build-info.ts
47317
- var VERSION = "0.13.12";
47318
- var COMMIT_SHA = "18363dfb";
47334
+ var VERSION = "0.13.14";
47335
+ var COMMIT_SHA = "0cf961a6";
47319
47336
 
47320
47337
  // src/cli/agent.ts
47321
47338
  init_source();
@@ -54578,7 +54595,7 @@ function registerAccountAdd(accountParent) {
54578
54595
  accountParent.command("add <account>").description("Mint a Google OAuth refresh token for <account> and register it with the auth-broker. For Drive scopes the effective flow is desktop-loopback (device-code returns invalid_scope for Drive; OOB is retired) \u2014 use a Desktop OAuth client; on a headless host complete the browser step over an SSH port-forward. Add --write for create/edit (drive.file); default is read-only.").option("--replace", "Overwrite existing credentials for <account> (default refuses if account already registered)", false).option("--write", "Request Drive WRITE scope (drive.file: create + edit app-created files) in addition to read. Default is read-only \u2014 a read grant never silently becomes a write grant. Re-consent an existing account with `--replace --write`.", false).action(withConfigError(async (account, opts) => {
54579
54596
  const normalizedAccount = validateAndNormalizeAccountEmail(account);
54580
54597
  const [
54581
- { runDriveOAuthFlow: runDriveOAuthFlow2, selectDriveAccountScopes: selectDriveAccountScopes2 },
54598
+ { runDriveOAuthFlow: runDriveOAuthFlow2, selectGoogleWorkspaceScopes: selectGoogleWorkspaceScopes2 },
54582
54599
  { selectInitialTier: selectInitialTier2 },
54583
54600
  { brokerCall: brokerCall2 },
54584
54601
  { loadConfig: loadConfig2, resolvePath: resolvePath2 },
@@ -54647,7 +54664,11 @@ function registerAccountAdd(accountParent) {
54647
54664
  clientIdRaw = await resolveRef(clientIdRaw, "google_client_id");
54648
54665
  clientSecretRaw = await resolveRef(clientSecretRaw, "google_client_secret");
54649
54666
  }
54650
- const accountScopes = selectDriveAccountScopes2(opts.write ?? false);
54667
+ const tier = gw.tier ?? "core";
54668
+ const accountScopes = selectGoogleWorkspaceScopes2({
54669
+ write: opts.write ?? false,
54670
+ tier
54671
+ });
54651
54672
  const oauthCfg = {
54652
54673
  client_id: clientIdRaw,
54653
54674
  client_secret: clientSecretRaw,
@@ -54656,6 +54677,9 @@ function registerAccountAdd(accountParent) {
54656
54677
  if (opts.write) {
54657
54678
  console.log(source_default.yellow(" Requesting Drive WRITE scope (drive.file \u2014 create/edit app-created files)."));
54658
54679
  }
54680
+ console.log(source_default.gray(` Workspace tier: ${tier} \u2014 requesting Docs + Sheets` + (tier === "extended" || tier === "complete" ? " + Slides" : "") + " API scopes so the tier's tools can authenticate."));
54681
+ console.log(source_default.gray(` Changing the tier later requires re-running this command
54682
+ ` + " (`--replace`) \u2014 OAuth scopes are fixed at consent time."));
54659
54683
  const oauthEnv = {
54660
54684
  DISPLAY: process.env.DISPLAY,
54661
54685
  WAYLAND_DISPLAY: process.env.WAYLAND_DISPLAY,
@@ -73048,6 +73072,29 @@ function buildSeedCredentials(input) {
73048
73072
  }
73049
73073
  var AIOFILE_PIN = "aiofile==3.10.2";
73050
73074
  var AIOFILE_PKG = AIOFILE_PIN.split("==")[0];
73075
+ function requiredWorkspaceScopesForTier(tier) {
73076
+ const docs = [
73077
+ "https://www.googleapis.com/auth/documents",
73078
+ "https://www.googleapis.com/auth/spreadsheets"
73079
+ ];
73080
+ if (tier === "extended" || tier === "complete") {
73081
+ return [...docs, "https://www.googleapis.com/auth/presentations"];
73082
+ }
73083
+ return docs;
73084
+ }
73085
+ function findMissingWorkspaceScopes(seedScope, tier) {
73086
+ const have = new Set(seedScope.split(/\s+/).map((s) => s.trim()).filter((s) => s.length > 0));
73087
+ return requiredWorkspaceScopesForTier(tier).filter((s) => !have.has(s));
73088
+ }
73089
+ var DRIVE_FILE_SCOPE = "https://www.googleapis.com/auth/drive.file";
73090
+ function buildMissingScopeWarning(missing, tier, accountEmail, hasWriteScope) {
73091
+ const short = missing.map((s) => s.replace(/^https:\/\/www\.googleapis\.com\/auth\//, "")).join(", ");
73092
+ return `drive-mcp-launcher: WARNING \u2014 the Google account '${accountEmail}' was ` + `consented WITHOUT the scope(s) needed for tier '${tier ?? "core"}': ` + `${short}.
73093
+ ` + ` The matching MCP tools (Docs / Sheets / Slides create+edit) will FAIL ` + `to authenticate. OAuth scopes are fixed at consent time \u2014 re-run on the ` + `host to re-mint the token with the correct scopes:
73094
+ ` + ` switchroom auth google account add ${accountEmail} --replace` + `${hasWriteScope ? " --write" : ""}
73095
+ ` + ` (scopes are derived from \`google_workspace.tier\` \u2014 set the tier ` + `before re-running${hasWriteScope ? "; --write preserves the existing " + "Drive write capability" : ""}). Drive read/file tools are unaffected.
73096
+ `;
73097
+ }
73051
73098
  function buildUvxArgs(tier) {
73052
73099
  const args = [
73053
73100
  "--from",
@@ -73072,6 +73119,9 @@ function buildChildEnv(baseEnv, credentialsDir, accountEmail) {
73072
73119
  delete env2.WORKSPACE_MCP_STATELESS_MODE;
73073
73120
  delete env2.GOOGLE_APPLICATION_CREDENTIALS;
73074
73121
  delete env2.WORKSPACE_MCP_SERVICE_ACCOUNT_FILE;
73122
+ if (!env2.WORKSPACE_MCP_PORT) {
73123
+ env2.WORKSPACE_MCP_PORT = env2.SWITCHROOM_GDRIVE_MCP_PORT ?? "8631";
73124
+ }
73075
73125
  return env2;
73076
73126
  }
73077
73127
  function classifyRootSchema(schema) {
@@ -73288,6 +73338,11 @@ async function runDriveMcpLauncher(opts) {
73288
73338
  process.exit(1);
73289
73339
  }
73290
73340
  const tier = opts.tier ?? configSecrets.tier;
73341
+ const missingScopes = findMissingWorkspaceScopes(brokerCreds.scope, tier);
73342
+ if (missingScopes.length > 0) {
73343
+ const hasWriteScope = brokerCreds.scope.split(/\s+/).map((s) => s.trim()).includes(DRIVE_FILE_SCOPE);
73344
+ process.stderr.write(buildMissingScopeWarning(missingScopes, tier, brokerCreds.accountEmail, hasWriteScope));
73345
+ }
73291
73346
  const args = buildUvxArgs(tier);
73292
73347
  const env2 = buildChildEnv(process.env, credentialsDir, brokerCreds.accountEmail);
73293
73348
  const { spawn: spawn5 } = await import("node:child_process");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "switchroom",
3
- "version": "0.13.12",
3
+ "version": "0.13.14",
4
4
  "description": "Run Claude Code 24/7 on your Claude Pro/Max subscription over Telegram. Open-source alternative to OpenClaw and NanoClaw — no API keys.",
5
5
  "type": "module",
6
6
  "bin": {