@dosu/cli 0.33.0 → 0.33.2

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.
Files changed (2) hide show
  1. package/bin/dosu.js +433 -222
  2. package/package.json +1 -1
package/bin/dosu.js CHANGED
@@ -2097,9 +2097,96 @@ var init_commander = __esm(() => {
2097
2097
  program = new Command;
2098
2098
  });
2099
2099
 
2100
+ // src/config/identity.ts
2101
+ function getAccessTokenUserID(accessToken) {
2102
+ try {
2103
+ const payload = accessToken.split(".")[1];
2104
+ if (!payload)
2105
+ return;
2106
+ const decoded = JSON.parse(Buffer.from(payload, "base64url").toString("utf8"));
2107
+ return typeof decoded.sub === "string" && decoded.sub.length > 0 ? decoded.sub : undefined;
2108
+ } catch {
2109
+ return;
2110
+ }
2111
+ }
2112
+
2113
+ // src/config/schema.ts
2114
+ var MODE_OSS = "oss", CONFIG_SCHEMA_VERSION = 2;
2115
+
2116
+ // src/config/config-v1-migration.ts
2117
+ function migrateLegacyConfig(value) {
2118
+ if (!isRecord(value))
2119
+ return { schema_version: CONFIG_SCHEMA_VERSION };
2120
+ const accessToken = stringValue(value.access_token) ?? "";
2121
+ const refreshToken = stringValue(value.refresh_token) ?? "";
2122
+ const expiresAt = numberValue(value.expires_at) ?? 0;
2123
+ const hasSession = Boolean(accessToken || refreshToken || expiresAt);
2124
+ const userID = stringValue(value.user_id) ?? getAccessTokenUserID(accessToken);
2125
+ return {
2126
+ schema_version: CONFIG_SCHEMA_VERSION,
2127
+ mode: value.mode === MODE_OSS ? MODE_OSS : undefined,
2128
+ active_account: hasSession ? {
2129
+ user_id: userID,
2130
+ session: {
2131
+ access_token: accessToken,
2132
+ refresh_token: refreshToken,
2133
+ expires_at: expiresAt
2134
+ },
2135
+ target: userID ? legacyTarget(value) : undefined
2136
+ } : undefined
2137
+ };
2138
+ }
2139
+ function legacyTarget(value) {
2140
+ const target = {
2141
+ deployment_id: stringValue(value.deployment_id),
2142
+ deployment_name: stringValue(value.deployment_name),
2143
+ api_key: stringValue(value.api_key),
2144
+ org_id: stringValue(value.org_id),
2145
+ space_id: stringValue(value.space_id)
2146
+ };
2147
+ return Object.values(target).some((field) => field !== undefined) ? target : undefined;
2148
+ }
2149
+ function isRecord(value) {
2150
+ return typeof value === "object" && value !== null && !Array.isArray(value);
2151
+ }
2152
+ function stringValue(value) {
2153
+ return typeof value === "string" ? value : undefined;
2154
+ }
2155
+ function numberValue(value) {
2156
+ return typeof value === "number" && Number.isFinite(value) ? value : undefined;
2157
+ }
2158
+ var init_config_v1_migration = () => {};
2159
+
2100
2160
  // src/config/config.ts
2101
2161
  import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
2102
2162
  import { join } from "node:path";
2163
+ function getConfigUserID(cfg) {
2164
+ return cfg.active_account?.user_id ?? getAccessTokenUserID(cfg.active_account?.session.access_token ?? "");
2165
+ }
2166
+ function replaceLoginSession(cfg, session) {
2167
+ const previousUserID = getConfigUserID(cfg);
2168
+ const nextUserID = session.user_id ?? getAccessTokenUserID(session.access_token);
2169
+ const preserveTarget = Boolean(previousUserID && nextUserID && previousUserID === nextUserID);
2170
+ cfg.active_account = {
2171
+ user_id: nextUserID,
2172
+ session: sessionWithoutIdentity(session),
2173
+ target: preserveTarget ? cloneTarget(cfg.active_account?.target) : undefined
2174
+ };
2175
+ }
2176
+ function bindAccountIdentity(cfg, userID) {
2177
+ const account = cfg.active_account;
2178
+ if (!account)
2179
+ throw new Error("cannot bind an identity without an authenticated session");
2180
+ if (account.user_id && account.user_id !== userID)
2181
+ account.target = undefined;
2182
+ account.user_id = userID;
2183
+ }
2184
+ function updateTarget(cfg, target) {
2185
+ if (!cfg.active_account?.user_id) {
2186
+ throw new Error("cannot bind a target without a verified account identity");
2187
+ }
2188
+ cfg.active_account.target = { ...cfg.active_account.target, ...target };
2189
+ }
2103
2190
  function getConfigDir() {
2104
2191
  const dirName = process.env.DOSU_DEV === "true" ? "dosu-cli-dev" : "dosu-cli";
2105
2192
  const xdgConfig = process.env.XDG_CONFIG_HOME;
@@ -2117,43 +2204,113 @@ function getConfigPath() {
2117
2204
  }
2118
2205
  function loadConfig() {
2119
2206
  const path2 = getConfigPath();
2120
- if (!existsSync(path2)) {
2207
+ if (!existsSync(path2))
2121
2208
  return emptyConfig();
2122
- }
2209
+ let raw;
2123
2210
  try {
2124
- const data = readFileSync(path2, "utf-8");
2125
- return JSON.parse(data);
2211
+ raw = JSON.parse(readFileSync(path2, "utf-8"));
2126
2212
  } catch {
2127
2213
  return emptyConfig();
2128
2214
  }
2215
+ if (isConfigV2(raw))
2216
+ return normalizeV2(raw);
2217
+ if (isRecord2(raw) && "schema_version" in raw)
2218
+ return emptyConfig();
2219
+ const migrated = migrateLegacyConfig(raw);
2220
+ try {
2221
+ writeConfig(path2, migrated);
2222
+ } catch {}
2223
+ return migrated;
2129
2224
  }
2130
2225
  function saveConfig(cfg) {
2131
- const path2 = getConfigPath();
2132
- const dir = getConfigDir();
2133
- if (!existsSync(dir)) {
2134
- mkdirSync(dir, { recursive: true, mode: 448 });
2135
- }
2136
- const tmp = `${path2}.${process.pid}.tmp`;
2137
- writeFileSync(tmp, JSON.stringify(cfg, null, 2), { mode: 384 });
2138
- renameSync(tmp, path2);
2226
+ writeConfig(getConfigPath(), cfg);
2139
2227
  }
2140
2228
  function isAuthenticated(cfg) {
2141
- return cfg.access_token !== "";
2229
+ return Boolean(cfg.active_account?.session.access_token);
2142
2230
  }
2143
2231
  function isTokenExpired(cfg) {
2144
- if (cfg.expires_at === 0)
2232
+ const expiresAt = cfg.active_account?.session.expires_at ?? 0;
2233
+ if (expiresAt === 0)
2145
2234
  return false;
2146
- return Math.floor(Date.now() / 1000) > cfg.expires_at - 300;
2235
+ return Math.floor(Date.now() / 1000) > expiresAt - 300;
2236
+ }
2237
+ function clearConfigInPlace(cfg) {
2238
+ cfg.mode = undefined;
2239
+ cfg.active_account = undefined;
2147
2240
  }
2148
2241
  function emptyConfig() {
2242
+ return { schema_version: CONFIG_SCHEMA_VERSION };
2243
+ }
2244
+ function sessionWithoutIdentity(session) {
2149
2245
  return {
2150
- access_token: "",
2151
- refresh_token: "",
2152
- expires_at: 0
2246
+ access_token: session.access_token,
2247
+ refresh_token: session.refresh_token,
2248
+ expires_at: session.expires_at
2153
2249
  };
2154
2250
  }
2155
- var MODE_OSS = "oss";
2156
- var init_config = () => {};
2251
+ function cloneTarget(target) {
2252
+ return target ? { ...target } : undefined;
2253
+ }
2254
+ function isConfigV2(value) {
2255
+ return isRecord2(value) && value.schema_version === CONFIG_SCHEMA_VERSION;
2256
+ }
2257
+ function normalizeV2(value) {
2258
+ const active = isRecord2(value.active_account) ? value.active_account : undefined;
2259
+ const session = active && isRecord2(active.session) ? active.session : undefined;
2260
+ if (!active || !session) {
2261
+ return {
2262
+ schema_version: CONFIG_SCHEMA_VERSION,
2263
+ mode: value.mode === MODE_OSS ? MODE_OSS : undefined
2264
+ };
2265
+ }
2266
+ const accessToken = stringValue2(session.access_token) ?? "";
2267
+ const userID = stringValue2(active.user_id) ?? getAccessTokenUserID(accessToken);
2268
+ return {
2269
+ schema_version: CONFIG_SCHEMA_VERSION,
2270
+ mode: value.mode === MODE_OSS ? MODE_OSS : undefined,
2271
+ active_account: {
2272
+ user_id: userID,
2273
+ session: {
2274
+ access_token: accessToken,
2275
+ refresh_token: stringValue2(session.refresh_token) ?? "",
2276
+ expires_at: numberValue2(session.expires_at) ?? 0
2277
+ },
2278
+ target: userID ? normalizeTarget(active.target) : undefined
2279
+ }
2280
+ };
2281
+ }
2282
+ function normalizeTarget(value) {
2283
+ if (!isRecord2(value))
2284
+ return;
2285
+ const target = {
2286
+ deployment_id: stringValue2(value.deployment_id),
2287
+ deployment_name: stringValue2(value.deployment_name),
2288
+ api_key: stringValue2(value.api_key),
2289
+ org_id: stringValue2(value.org_id),
2290
+ space_id: stringValue2(value.space_id)
2291
+ };
2292
+ return Object.values(target).some((field) => field !== undefined) ? target : undefined;
2293
+ }
2294
+ function writeConfig(path2, config) {
2295
+ const dir = getConfigDir();
2296
+ if (!existsSync(dir))
2297
+ mkdirSync(dir, { recursive: true, mode: 448 });
2298
+ const tmp = `${path2}.${process.pid}.tmp`;
2299
+ writeFileSync(tmp, JSON.stringify(config, null, 2), { mode: 384 });
2300
+ renameSync(tmp, path2);
2301
+ }
2302
+ function isRecord2(value) {
2303
+ return typeof value === "object" && value !== null && !Array.isArray(value);
2304
+ }
2305
+ function stringValue2(value) {
2306
+ return typeof value === "string" ? value : undefined;
2307
+ }
2308
+ function numberValue2(value) {
2309
+ return typeof value === "number" && Number.isFinite(value) ? value : undefined;
2310
+ }
2311
+ var init_config = __esm(() => {
2312
+ init_config_v1_migration();
2313
+ });
2157
2314
 
2158
2315
  // src/config/constants.ts
2159
2316
  function getWebAppURL() {
@@ -2208,7 +2365,7 @@ class Client {
2208
2365
  const url = this.baseURL + path2;
2209
2366
  const headers = {
2210
2367
  "Content-Type": "application/json",
2211
- "Supabase-Access-Token": this.config.access_token
2368
+ "Supabase-Access-Token": this.config.active_account?.session.access_token ?? ""
2212
2369
  };
2213
2370
  const options = { method, headers };
2214
2371
  if (body !== undefined) {
@@ -2242,13 +2399,13 @@ class Client {
2242
2399
  return this.apiKeyRequest("POST", path2, body);
2243
2400
  }
2244
2401
  async apiKeyRequest(method, path2, body) {
2245
- if (!this.config.api_key) {
2402
+ if (!this.config.active_account?.target?.api_key) {
2246
2403
  throw new Error("no API key available");
2247
2404
  }
2248
2405
  const url = this.baseURL + path2;
2249
2406
  const headers = {
2250
2407
  "Content-Type": "application/json",
2251
- "X-Dosu-API-Key": this.config.api_key
2408
+ "X-Dosu-API-Key": this.config.active_account?.target?.api_key
2252
2409
  };
2253
2410
  const options = { method, headers };
2254
2411
  if (body !== undefined) {
@@ -2265,7 +2422,7 @@ class Client {
2265
2422
  }
2266
2423
  async refreshToken() {
2267
2424
  this.adoptNewerDiskTokens();
2268
- if (!this.config.refresh_token) {
2425
+ if (!this.config.active_account?.session.refresh_token) {
2269
2426
  throw new Error("no refresh token available");
2270
2427
  }
2271
2428
  try {
@@ -2279,15 +2436,21 @@ class Client {
2279
2436
  }
2280
2437
  adoptNewerDiskTokens() {
2281
2438
  const disk = loadConfig();
2282
- if (!disk.refresh_token || disk.refresh_token === this.config.refresh_token) {
2439
+ this.assertSameActiveAccount(disk);
2440
+ const diskSession = disk.active_account?.session;
2441
+ const memorySession = this.config.active_account?.session;
2442
+ if (!diskSession?.refresh_token || !memorySession || diskSession.refresh_token === memorySession.refresh_token) {
2283
2443
  return false;
2284
2444
  }
2285
- this.config.access_token = disk.access_token;
2286
- this.config.refresh_token = disk.refresh_token;
2287
- this.config.expires_at = disk.expires_at;
2445
+ memorySession.access_token = diskSession.access_token;
2446
+ memorySession.refresh_token = diskSession.refresh_token;
2447
+ memorySession.expires_at = diskSession.expires_at;
2288
2448
  return true;
2289
2449
  }
2290
2450
  async refreshTokenOnce() {
2451
+ const session = this.config.active_account?.session;
2452
+ if (!session?.refresh_token)
2453
+ throw new Error("no refresh token available");
2291
2454
  const supabaseURL = getSupabaseURL();
2292
2455
  const endpoint = `${supabaseURL}/auth/v1/token?grant_type=refresh_token`;
2293
2456
  const resp = await fetch(endpoint, {
@@ -2296,17 +2459,25 @@ class Client {
2296
2459
  "Content-Type": "application/json",
2297
2460
  apikey: getSupabaseAnonKey()
2298
2461
  },
2299
- body: JSON.stringify({ refresh_token: this.config.refresh_token })
2462
+ body: JSON.stringify({ refresh_token: session.refresh_token })
2300
2463
  });
2301
2464
  if (resp.status !== 200) {
2302
2465
  throw new Error(`refresh failed with status ${resp.status}`);
2303
2466
  }
2304
2467
  const data = await resp.json();
2305
- this.config.access_token = data.access_token;
2306
- this.config.refresh_token = data.refresh_token;
2307
- this.config.expires_at = Math.floor(Date.now() / 1000) + data.expires_in;
2468
+ this.assertSameActiveAccount(loadConfig());
2469
+ session.access_token = data.access_token;
2470
+ session.refresh_token = data.refresh_token;
2471
+ session.expires_at = Math.floor(Date.now() / 1000) + data.expires_in;
2308
2472
  saveConfig(this.config);
2309
2473
  }
2474
+ assertSameActiveAccount(disk) {
2475
+ const memoryUserID = getConfigUserID(this.config);
2476
+ const diskUserID = getConfigUserID(disk);
2477
+ if (memoryUserID && diskUserID && memoryUserID !== diskUserID) {
2478
+ throw new Error("authenticated account changed while this command was running; retry it");
2479
+ }
2480
+ }
2310
2481
  async getDeployments() {
2311
2482
  const resp = await this.get("/v1/mcp/deployments");
2312
2483
  if (resp.status !== 200) {
@@ -4577,7 +4748,7 @@ var init_dist4 = __esm(() => {
4577
4748
  function getVersionString() {
4578
4749
  return `v${VERSION}`;
4579
4750
  }
4580
- var VERSION = "0.33.0", INSTALL_CHANNEL = "npm";
4751
+ var VERSION = "0.33.2", INSTALL_CHANNEL = "npm";
4581
4752
 
4582
4753
  // src/debug/logger.ts
4583
4754
  import {
@@ -4723,7 +4894,7 @@ function createTypedClient(config) {
4723
4894
  if (!webAppURL) {
4724
4895
  throw new Error("Web app URL not configured");
4725
4896
  }
4726
- if (!config.access_token) {
4897
+ if (!config.active_account?.session.access_token) {
4727
4898
  throw new Error("Not authenticated. Run 'dosu login' first.");
4728
4899
  }
4729
4900
  const httpClient = new Client(config);
@@ -4742,7 +4913,7 @@ function createTypedClient(config) {
4742
4913
  }
4743
4914
  }
4744
4915
  return {
4745
- "Supabase-Access-Token": config.access_token,
4916
+ "Supabase-Access-Token": config.active_account?.session.access_token ?? "",
4746
4917
  "x-dosu-cli-contract": CLI_CONTRACT_HASH
4747
4918
  };
4748
4919
  },
@@ -4759,7 +4930,7 @@ function createTypedClient(config) {
4759
4930
  ...options,
4760
4931
  headers: {
4761
4932
  ...options?.headers,
4762
- "Supabase-Access-Token": config.access_token,
4933
+ "Supabase-Access-Token": config.active_account?.session.access_token ?? "",
4763
4934
  "x-dosu-cli-contract": CLI_CONTRACT_HASH
4764
4935
  }
4765
4936
  });
@@ -7853,12 +8024,12 @@ async function deleteOrphanDeployment(trpc, deploymentID, slug) {
7853
8024
  }
7854
8025
  async function stepConnectGitHubRepo(cfg, detected = detectGitRepo(), opts = {}) {
7855
8026
  logger.info("setup", "Step: connect GitHub repo(s)");
7856
- if (!cfg.org_id || !cfg.space_id) {
8027
+ if (!cfg.active_account?.target?.org_id || !cfg.active_account?.target?.space_id) {
7857
8028
  log.warn("Cannot connect GitHub: your Dosu workspace is missing org/space context. Re-run `dosu setup` from a fresh state.");
7858
8029
  return { advance: false, has_connected_repo: false };
7859
8030
  }
7860
- const orgID = cfg.org_id;
7861
- const spaceID = cfg.space_id;
8031
+ const orgID = cfg.active_account?.target?.org_id;
8032
+ const spaceID = cfg.active_account?.target?.space_id;
7862
8033
  if (detected) {
7863
8034
  log.info(`Connecting GitHub repos (detected local repo: ${detected.slug})`);
7864
8035
  }
@@ -7962,7 +8133,7 @@ ${dim(`deployment ${deployment_id}`)}`);
7962
8133
  advance: true,
7963
8134
  has_connected_repo: true,
7964
8135
  deployment_id: primary.deployment_id,
7965
- space_id: cfg.space_id,
8136
+ space_id: cfg.active_account?.target?.space_id,
7966
8137
  created_data_source_ids: survived.map((c3) => c3.data_source_id),
7967
8138
  created_repository_slugs: survived.map((c3) => c3.slug)
7968
8139
  };
@@ -9095,10 +9266,10 @@ async function buildInsights({
9095
9266
  now = () => new Date,
9096
9267
  onProgress
9097
9268
  }) {
9098
- if (!cfg.space_id) {
9269
+ if (!cfg.active_account?.target?.space_id) {
9099
9270
  throw new Error("space_id missing. Run 'dosu setup' first");
9100
9271
  }
9101
- const spaceId = cfg.space_id;
9272
+ const spaceId = cfg.active_account?.target?.space_id;
9102
9273
  onProgress?.("stats");
9103
9274
  const [currentRaw, combinedRaw] = await Promise.all([
9104
9275
  client.analytics.getUsageStats.query({ spaceId, days: windowDays }),
@@ -9117,7 +9288,7 @@ async function buildInsights({
9117
9288
  return {
9118
9289
  generatedAt: now().toISOString(),
9119
9290
  windowDays,
9120
- spaceName: cfg.deployment_name ?? "your space",
9291
+ spaceName: cfg.active_account?.target?.deployment_name ?? "your space",
9121
9292
  current,
9122
9293
  previous,
9123
9294
  derived,
@@ -10389,13 +10560,13 @@ var init_detect = () => {};
10389
10560
  function createJSONProvider(opts) {
10390
10561
  const defaultBuildServer = (cfg) => ({
10391
10562
  type: "http",
10392
- url: mcpURL(cfg.deployment_id),
10393
- headers: mcpHeaders(cfg.api_key)
10563
+ url: mcpURL(cfg.active_account.target.deployment_id),
10564
+ headers: mcpHeaders(cfg.active_account?.target?.api_key)
10394
10565
  });
10395
10566
  const defaultBuildOSSServer = (cfg) => ({
10396
10567
  type: "http",
10397
10568
  url: mcpBaseURL(),
10398
- headers: mcpHeaders(cfg.api_key)
10569
+ headers: mcpHeaders(cfg.active_account?.target?.api_key)
10399
10570
  });
10400
10571
  const buildServer = opts.buildServer ?? defaultBuildServer;
10401
10572
  return {
@@ -10408,7 +10579,7 @@ function createJSONProvider(opts) {
10408
10579
  globalConfigPath: () => expandHome(opts.globalPath),
10409
10580
  isConfigured: () => isJSONKeyConfigured(expandHome(opts.globalPath), opts.topKey),
10410
10581
  install(cfg, global) {
10411
- if (cfg.mode !== MODE_OSS && !cfg.deployment_id)
10582
+ if (cfg.mode !== MODE_OSS && !cfg.active_account?.target?.deployment_id)
10412
10583
  throw new Error("deployment ID is required");
10413
10584
  let configPath;
10414
10585
  if (global) {
@@ -10450,8 +10621,8 @@ var AntigravityProvider = () => createJSONProvider({
10450
10621
  globalPath: "~/.gemini/antigravity/mcp_config.json",
10451
10622
  topKey: "mcpServers",
10452
10623
  buildServer: (cfg) => ({
10453
- serverUrl: mcpURL(cfg.deployment_id),
10454
- headers: mcpHeaders(cfg.api_key)
10624
+ serverUrl: mcpURL(cfg.active_account.target.deployment_id),
10625
+ headers: mcpHeaders(cfg.active_account.target.api_key)
10455
10626
  })
10456
10627
  });
10457
10628
  var init_antigravity = __esm(() => {
@@ -10508,10 +10679,10 @@ var extensionDir = () => join14(appSupportDir(), "Code", "User", "globalStorage"
10508
10679
  globalPath: join14(extensionDir(), "settings", "cline_mcp_settings.json"),
10509
10680
  topKey: "mcpServers",
10510
10681
  buildServer: (cfg) => ({
10511
- url: mcpURL(cfg.deployment_id),
10682
+ url: mcpURL(cfg.active_account.target.deployment_id),
10512
10683
  type: "streamableHttp",
10513
10684
  disabled: false,
10514
- headers: mcpHeaders(cfg.api_key)
10685
+ headers: mcpHeaders(cfg.active_account.target.api_key)
10515
10686
  })
10516
10687
  });
10517
10688
  var init_cline = __esm(() => {
@@ -10534,10 +10705,10 @@ var ClineCliProvider = () => createJSONProvider({
10534
10705
  globalPath: join15(clineDir(), "data", "settings", "cline_mcp_settings.json"),
10535
10706
  topKey: "mcpServers",
10536
10707
  buildServer: (cfg) => ({
10537
- url: mcpURL(cfg.deployment_id),
10708
+ url: mcpURL(cfg.active_account.target.deployment_id),
10538
10709
  type: "streamableHttp",
10539
10710
  disabled: false,
10540
- headers: mcpHeaders(cfg.api_key)
10711
+ headers: mcpHeaders(cfg.active_account.target.api_key)
10541
10712
  })
10542
10713
  });
10543
10714
  var init_cline_cli = __esm(() => {
@@ -10568,15 +10739,15 @@ function writeTOML(path3, content) {
10568
10739
  function mcpEndpoint(cfg) {
10569
10740
  if (cfg.mode === MODE_OSS)
10570
10741
  return mcpBaseURL();
10571
- if (!cfg.deployment_id)
10742
+ if (!cfg.active_account?.target?.deployment_id)
10572
10743
  throw new Error("deployment ID is required");
10573
- return mcpURL(cfg.deployment_id);
10744
+ return mcpURL(cfg.active_account?.target?.deployment_id);
10574
10745
  }
10575
10746
  function installDosuToTOML(path3, cfg) {
10576
10747
  let content = readTOML(path3);
10577
10748
  content = removeDosuFromTOML(content);
10578
10749
  const url = mcpEndpoint(cfg);
10579
- const headers = mcpHeaders(cfg.api_key);
10750
+ const headers = mcpHeaders(cfg.active_account?.target?.api_key);
10580
10751
  const headerEntries = Object.entries(headers).map(([k, v]) => `${k} = "${v}"`).join(`
10581
10752
  `);
10582
10753
  const section = `
@@ -10624,7 +10795,7 @@ var CodexProvider = () => ({
10624
10795
  return content.includes("[mcp_servers.dosu]");
10625
10796
  },
10626
10797
  install(cfg, global) {
10627
- if (cfg.mode !== MODE_OSS && !cfg.deployment_id)
10798
+ if (cfg.mode !== MODE_OSS && !cfg.active_account?.target?.deployment_id)
10628
10799
  throw new Error("deployment ID is required");
10629
10800
  installDosuToTOML(getConfigPath2(global), cfg);
10630
10801
  },
@@ -10652,9 +10823,9 @@ function globalPath() {
10652
10823
  function mcpEndpoint2(cfg) {
10653
10824
  if (cfg.mode === MODE_OSS)
10654
10825
  return mcpBaseURL();
10655
- if (!cfg.deployment_id)
10826
+ if (!cfg.active_account?.target?.deployment_id)
10656
10827
  throw new Error("deployment ID is required");
10657
- return mcpURL(cfg.deployment_id);
10828
+ return mcpURL(cfg.active_account?.target?.deployment_id);
10658
10829
  }
10659
10830
  var CopilotProvider = () => ({
10660
10831
  name: () => "GitHub Copilot CLI",
@@ -10672,7 +10843,7 @@ var CopilotProvider = () => ({
10672
10843
  type: "http",
10673
10844
  url,
10674
10845
  tools: ["*"],
10675
- headers: mcpHeaders(cfg.api_key)
10846
+ headers: mcpHeaders(cfg.active_account.target.api_key)
10676
10847
  };
10677
10848
  installJSONServer(globalPath(), "mcpServers", server);
10678
10849
  } else {
@@ -10680,7 +10851,7 @@ var CopilotProvider = () => ({
10680
10851
  const server = {
10681
10852
  type: "http",
10682
10853
  url,
10683
- headers: mcpHeaders(cfg.api_key)
10854
+ headers: mcpHeaders(cfg.active_account.target.api_key)
10684
10855
  };
10685
10856
  installJSONServer(configPath, "servers", server);
10686
10857
  }
@@ -10711,8 +10882,8 @@ var CursorProvider = () => createJSONProvider({
10711
10882
  globalPath: "~/.cursor/mcp.json",
10712
10883
  topKey: "mcpServers",
10713
10884
  buildServer: (cfg) => ({
10714
- url: mcpURL(cfg.deployment_id),
10715
- headers: mcpHeaders(cfg.api_key)
10885
+ url: mcpURL(cfg.active_account.target.deployment_id),
10886
+ headers: mcpHeaders(cfg.active_account.target.api_key)
10716
10887
  }),
10717
10888
  localConfigPath: (cwd) => join18(cwd, ".cursor", "mcp.json")
10718
10889
  });
@@ -10757,9 +10928,9 @@ var init_gemini = __esm(() => {
10757
10928
  function mcpEndpoint3(cfg) {
10758
10929
  if (cfg.mode === MODE_OSS)
10759
10930
  return mcpBaseURL();
10760
- if (!cfg.deployment_id)
10931
+ if (!cfg.active_account?.target?.deployment_id)
10761
10932
  throw new Error("deployment ID is required");
10762
- return mcpURL(cfg.deployment_id);
10933
+ return mcpURL(cfg.active_account?.target?.deployment_id);
10763
10934
  }
10764
10935
  function maskSecret(secret) {
10765
10936
  if (secret.length <= 8)
@@ -10773,7 +10944,7 @@ var ManualProvider = () => ({
10773
10944
  supportsLocal: () => false,
10774
10945
  install(cfg, _global, opts = {}) {
10775
10946
  const url = mcpEndpoint3(cfg);
10776
- const apiKey = mcpHeaders(cfg.api_key)["X-Dosu-API-Key"];
10947
+ const apiKey = mcpHeaders(cfg.active_account?.target?.api_key)["X-Dosu-API-Key"];
10777
10948
  const headerValue = opts.showSecret ? apiKey : maskSecret(apiKey);
10778
10949
  console.log("Use these details to configure the Dosu MCP server in your client:");
10779
10950
  console.log();
@@ -10811,9 +10982,9 @@ function resolveGlobalConfigPath() {
10811
10982
  function mcpEndpoint4(cfg) {
10812
10983
  if (cfg.mode === MODE_OSS)
10813
10984
  return mcpBaseURL();
10814
- if (!cfg.deployment_id)
10985
+ if (!cfg.active_account?.target?.deployment_id)
10815
10986
  throw new Error("deployment ID is required");
10816
- return mcpURL(cfg.deployment_id);
10987
+ return mcpURL(cfg.active_account?.target?.deployment_id);
10817
10988
  }
10818
10989
  var MCPorterProvider = () => ({
10819
10990
  name: () => "MCPorter",
@@ -10829,7 +11000,7 @@ var MCPorterProvider = () => ({
10829
11000
  const server = {
10830
11001
  type: "http",
10831
11002
  url: mcpEndpoint4(cfg),
10832
- headers: mcpHeaders(cfg.api_key)
11003
+ headers: mcpHeaders(cfg.active_account.target.api_key)
10833
11004
  };
10834
11005
  installJSONServer(configPath, "mcpServers", server);
10835
11006
  },
@@ -10856,9 +11027,9 @@ var OpenCodeProvider = () => createJSONProvider({
10856
11027
  topKey: "mcp",
10857
11028
  buildServer: (cfg) => ({
10858
11029
  type: "remote",
10859
- url: mcpURL(cfg.deployment_id),
11030
+ url: mcpURL(cfg.active_account.target.deployment_id),
10860
11031
  enabled: true,
10861
- headers: mcpHeaders(cfg.api_key)
11032
+ headers: mcpHeaders(cfg.active_account.target.api_key)
10862
11033
  }),
10863
11034
  localConfigPath: (cwd) => join22(cwd, "opencode.json")
10864
11035
  });
@@ -10920,8 +11091,8 @@ var ZedProvider = () => createJSONProvider({
10920
11091
  buildServer: (cfg) => ({
10921
11092
  source: "custom",
10922
11093
  type: "http",
10923
- url: mcpURL(cfg.deployment_id),
10924
- headers: mcpHeaders(cfg.api_key)
11094
+ url: mcpURL(cfg.active_account.target.deployment_id),
11095
+ headers: mcpHeaders(cfg.active_account.target.api_key)
10925
11096
  }),
10926
11097
  localConfigPath: (cwd) => join25(cwd, ".zed", "settings.json")
10927
11098
  });
@@ -11137,7 +11308,7 @@ var init_agents_md_step = __esm(() => {
11137
11308
 
11138
11309
  // src/setup/analytics.ts
11139
11310
  async function trackCliOnboardingEvent(cfg, onboardingRunID, event, properties = {}) {
11140
- if (!cfg.access_token)
11311
+ if (!cfg.active_account?.session.access_token)
11141
11312
  return;
11142
11313
  try {
11143
11314
  const trpc = createTypedClient(cfg);
@@ -11161,7 +11332,7 @@ async function trackCliOnboardingPreAuthEvent(onboardingRunID, event, properties
11161
11332
  event,
11162
11333
  onboarding_run_id: onboardingRunID,
11163
11334
  properties: {
11164
- ...baseProperties({ access_token: "", refresh_token: "", expires_at: 0 }),
11335
+ ...baseProperties(emptyConfig()),
11165
11336
  ...properties
11166
11337
  }
11167
11338
  }), TRACKING_TIMEOUT_MS);
@@ -11176,9 +11347,9 @@ function baseProperties(cfg) {
11176
11347
  platform: process.platform,
11177
11348
  arch: process.arch,
11178
11349
  mode: cfg.mode ?? "cloud",
11179
- org_id: cfg.org_id,
11180
- deployment_id: cfg.deployment_id,
11181
- space_id: cfg.space_id
11350
+ org_id: cfg.active_account?.target?.org_id,
11351
+ deployment_id: cfg.active_account?.target?.deployment_id,
11352
+ space_id: cfg.active_account?.target?.space_id
11182
11353
  };
11183
11354
  }
11184
11355
  function createAnonymousClient() {
@@ -11217,6 +11388,7 @@ var init_analytics = __esm(() => {
11217
11388
  init_dist();
11218
11389
  init_dist4();
11219
11390
  init_trpc();
11391
+ init_config();
11220
11392
  init_logger();
11221
11393
  });
11222
11394
 
@@ -11748,7 +11920,7 @@ async function runSetup(opts = {}) {
11748
11920
  authTab?.close();
11749
11921
  };
11750
11922
  await trackCliOnboardingEvent(cfg, onboardingRunID, "cli_onboarding_auth_completed");
11751
- const apiClient = new Client(cfg);
11923
+ let apiClient = new Client(cfg);
11752
11924
  let cloudSetupContext = null;
11753
11925
  if (cfg.mode !== MODE_OSS) {
11754
11926
  const s = spinner();
@@ -11779,14 +11951,16 @@ async function runSetup(opts = {}) {
11779
11951
  });
11780
11952
  return;
11781
11953
  }
11782
- const ok = await bindOnboardingDeployment(apiClient, cfg, cloudSetupContext.targetOrg ?? null);
11954
+ apiClient = new Client(cfg);
11955
+ const targetOrg = await resolveCurrentOnboardingTargetOrg(cfg);
11956
+ const ok = await bindOnboardingDeployment(apiClient, cfg, targetOrg);
11783
11957
  if (!ok) {
11784
11958
  await trackCliOnboardingEvent(cfg, onboardingRunID, "cli_onboarding_failed", {
11785
11959
  reason: "onboarding_deployment_failed"
11786
11960
  });
11787
11961
  return;
11788
11962
  }
11789
- } else if (!cfg.deployment_id || opts.deploymentID) {
11963
+ } else if (!cfg.active_account?.target?.deployment_id || opts.deploymentID) {
11790
11964
  const ok = await resolveDeployment(apiClient, cfg, opts);
11791
11965
  if (!ok) {
11792
11966
  await trackCliOnboardingEvent(cfg, onboardingRunID, "cli_onboarding_failed", {
@@ -11802,7 +11976,7 @@ async function runSetup(opts = {}) {
11802
11976
  });
11803
11977
  return;
11804
11978
  }
11805
- cfg.api_key = apiKey;
11979
+ updateTarget(cfg, { api_key: apiKey });
11806
11980
  saveConfig(cfg);
11807
11981
  const choices = await stepOneShotConfirm(inGitWorkTree());
11808
11982
  if (!choices) {
@@ -11868,10 +12042,12 @@ async function runSetup(opts = {}) {
11868
12042
  }
11869
12043
  }
11870
12044
  function applyDeployment(cfg, d) {
11871
- cfg.deployment_id = d.deployment_id;
11872
- cfg.deployment_name = d.name;
11873
- cfg.org_id = d.org_id;
11874
- cfg.space_id = d.space_id;
12045
+ updateTarget(cfg, {
12046
+ deployment_id: d.deployment_id,
12047
+ deployment_name: d.name,
12048
+ org_id: d.org_id,
12049
+ space_id: d.space_id
12050
+ });
11875
12051
  }
11876
12052
  function applyModeOverride(cfg, opts) {
11877
12053
  if (!opts.mode)
@@ -11944,7 +12120,7 @@ async function runInstallSkill() {
11944
12120
  async function stepAuthenticate(existingCfg, onboardingRunID) {
11945
12121
  logger.info("setup", "Step: authenticate");
11946
12122
  const cfg = existingCfg ?? loadConfig();
11947
- if (cfg.access_token) {
12123
+ if (cfg.active_account?.session.access_token) {
11948
12124
  const s = spinner();
11949
12125
  s.start("Verifying session...");
11950
12126
  try {
@@ -11995,9 +12171,11 @@ async function openBrowserForSetup(cfg, onboardingRunID) {
11995
12171
  const token = result.token;
11996
12172
  s.stop("Authenticated");
11997
12173
  logger.info("setup", "Browser auth completed");
11998
- cfg.access_token = token.access_token;
11999
- cfg.refresh_token = token.refresh_token;
12000
- cfg.expires_at = Math.floor(Date.now() / 1000) + token.expires_in;
12174
+ replaceLoginSession(cfg, {
12175
+ access_token: token.access_token,
12176
+ refresh_token: token.refresh_token,
12177
+ expires_at: Math.floor(Date.now() / 1000) + token.expires_in
12178
+ });
12001
12179
  saveConfig(cfg);
12002
12180
  return { cfg, authTab: result.server };
12003
12181
  } catch (err) {
@@ -12042,9 +12220,11 @@ async function stepWebOnboarding(cfg, onboardingRunID, authTab) {
12042
12220
  s.stop("Could not open a browser");
12043
12221
  return false;
12044
12222
  }
12045
- cfg.access_token = result.token.access_token;
12046
- cfg.refresh_token = result.token.refresh_token;
12047
- cfg.expires_at = Math.floor(Date.now() / 1000) + result.token.expires_in;
12223
+ replaceLoginSession(cfg, {
12224
+ access_token: result.token.access_token,
12225
+ refresh_token: result.token.refresh_token,
12226
+ expires_at: Math.floor(Date.now() / 1000) + result.token.expires_in
12227
+ });
12048
12228
  saveConfig(cfg);
12049
12229
  s.stop("Onboarding finished in the browser");
12050
12230
  logger.info("setup", "Web onboarding handoff completed");
@@ -12068,6 +12248,8 @@ async function resolveCloudSetupContext(cfg) {
12068
12248
  log.error("Could not load your profile.");
12069
12249
  return null;
12070
12250
  }
12251
+ bindAccountIdentity(cfg, profile.user_id);
12252
+ saveConfig(cfg);
12071
12253
  if (profile.finished_onboarding === true) {
12072
12254
  return {
12073
12255
  kind: "setup",
@@ -12100,6 +12282,23 @@ async function resolveOnboardingTargetOrg(trpc) {
12100
12282
  }
12101
12283
  return accessibleOrgs[0] ?? null;
12102
12284
  }
12285
+ async function resolveCurrentOnboardingTargetOrg(cfg) {
12286
+ try {
12287
+ const { createTypedClient: createTypedClient2 } = await Promise.resolve().then(() => (init_trpc(), exports_trpc));
12288
+ const trpc = createTypedClient2(cfg);
12289
+ const profile = await trpc.user.getCliOnboardingContext.query();
12290
+ if (!profile?.user_id)
12291
+ return null;
12292
+ bindAccountIdentity(cfg, profile.user_id);
12293
+ saveConfig(cfg);
12294
+ return await resolveOnboardingTargetOrg(trpc);
12295
+ } catch (err) {
12296
+ const msg = err instanceof Error ? err.message : String(err);
12297
+ logger.error("setup", `Failed to resolve post-onboarding organization: ${msg}`);
12298
+ log.error(`Could not determine your onboarding organization: ${msg}`);
12299
+ return null;
12300
+ }
12301
+ }
12103
12302
  async function bindOnboardingDeployment(apiClient, cfg, targetOrg) {
12104
12303
  if (!targetOrg) {
12105
12304
  log.error("Could not determine your onboarding organization.");
@@ -12235,22 +12434,24 @@ ${dim(deployments[0].name)}`);
12235
12434
  }
12236
12435
  }
12237
12436
  async function stepMintAPIKey(apiClient, cfg) {
12238
- if (!cfg.deployment_id) {
12437
+ const target = cfg.active_account?.target;
12438
+ const deploymentID = target?.deployment_id;
12439
+ if (!deploymentID) {
12239
12440
  log.error("No MCP available for API key creation");
12240
12441
  return null;
12241
12442
  }
12242
- if (cfg.api_key) {
12243
- const valid = await apiClient.validateAPIKey(cfg.api_key, cfg.deployment_id);
12443
+ if (target.api_key) {
12444
+ const valid = await apiClient.validateAPIKey(target.api_key, deploymentID);
12244
12445
  logger.debug("setup", `Existing API key valid=${valid}`);
12245
12446
  if (valid) {
12246
12447
  log.success(`API key
12247
12448
  ${dim("using existing")}`);
12248
- return cfg.api_key;
12449
+ return target.api_key;
12249
12450
  }
12250
12451
  log.warn("Existing API key is invalid, creating a new one...");
12251
12452
  }
12252
12453
  try {
12253
- const resp = await apiClient.createAPIKey(cfg.deployment_id, "dosu-cli");
12454
+ const resp = await apiClient.createAPIKey(deploymentID, "dosu-cli");
12254
12455
  logger.info("setup", "API key created");
12255
12456
  log.success(`API key
12256
12457
  ${dim("created")}`);
@@ -12416,13 +12617,13 @@ function createDotsSpinner() {
12416
12617
  };
12417
12618
  }
12418
12619
  function isFullConfig(cfg) {
12419
- return Boolean(cfg.access_token && cfg.api_key && cfg.space_id && cfg.deployment_id);
12620
+ return Boolean(cfg.active_account?.session.access_token && cfg.active_account?.target?.api_key && cfg.active_account?.target?.space_id && cfg.active_account?.target?.deployment_id);
12420
12621
  }
12421
12622
  async function ensureFullConfig() {
12422
12623
  let cfg = loadConfig();
12423
12624
  if (isFullConfig(cfg))
12424
12625
  return cfg;
12425
- const reason = !cfg.access_token ? "Insights needs you to log in first." : "Insights needs a configured Dosu deployment.";
12626
+ const reason = !cfg.active_account?.session.access_token ? "Insights needs you to log in first." : "Insights needs a configured Dosu deployment.";
12426
12627
  log.warn(reason);
12427
12628
  const shouldSetup = await confirm({
12428
12629
  message: "Run setup now?",
@@ -12448,10 +12649,10 @@ function makeAskFn(cfg) {
12448
12649
  method: "POST",
12449
12650
  headers: {
12450
12651
  "Content-Type": "application/json",
12451
- "X-Dosu-API-Key": cfg.api_key
12652
+ "X-Dosu-API-Key": cfg.active_account.target.api_key
12452
12653
  },
12453
12654
  body: JSON.stringify({
12454
- deployment_id: cfg.deployment_id,
12655
+ deployment_id: cfg.active_account.target.deployment_id,
12455
12656
  question
12456
12657
  }),
12457
12658
  signal: controller.signal
@@ -12640,7 +12841,7 @@ async function runTUI() {
12640
12841
  console.log(import_picocolors25.default.magenta(LOGO));
12641
12842
  const cfg = loadConfig();
12642
12843
  while (true) {
12643
- const insightsReady = Boolean(cfg.space_id && cfg.deployment_id && cfg.api_key);
12844
+ const insightsReady = Boolean(cfg.active_account?.target?.space_id && cfg.active_account?.target?.deployment_id && cfg.active_account?.target?.api_key);
12644
12845
  const options = [
12645
12846
  {
12646
12847
  label: "Setup",
@@ -12673,7 +12874,11 @@ async function runTUI() {
12673
12874
  break;
12674
12875
  case "setup":
12675
12876
  await runSetup();
12676
- Object.assign(cfg, loadConfig());
12877
+ {
12878
+ const fresh = loadConfig();
12879
+ cfg.mode = fresh.mode;
12880
+ cfg.active_account = fresh.active_account;
12881
+ }
12677
12882
  break;
12678
12883
  case "insights":
12679
12884
  await executeInsights(cfg);
@@ -12686,7 +12891,7 @@ async function runTUI() {
12686
12891
  outro("Goodbye!");
12687
12892
  }
12688
12893
  async function handleAuthenticate(cfg) {
12689
- if (cfg.access_token) {
12894
+ if (cfg.active_account?.session.access_token) {
12690
12895
  const s = spinner();
12691
12896
  s.start("Verifying session...");
12692
12897
  try {
@@ -12723,9 +12928,11 @@ async function handleAuthenticate(cfg) {
12723
12928
  }
12724
12929
  const token = result.token;
12725
12930
  s.stop("Authenticated");
12726
- cfg.access_token = token.access_token;
12727
- cfg.refresh_token = token.refresh_token;
12728
- cfg.expires_at = Math.floor(Date.now() / 1000) + token.expires_in;
12931
+ replaceLoginSession(cfg, {
12932
+ access_token: token.access_token,
12933
+ refresh_token: token.refresh_token,
12934
+ expires_at: Math.floor(Date.now() / 1000) + token.expires_in
12935
+ });
12729
12936
  saveConfig(cfg);
12730
12937
  } catch (err) {
12731
12938
  const { OAuthCallbackError: OAuthCallbackError2 } = await Promise.resolve().then(() => (init_errors(), exports_errors));
@@ -12741,13 +12948,7 @@ function handleLogout(cfg) {
12741
12948
  log.warn("You are not logged in.");
12742
12949
  return;
12743
12950
  }
12744
- cfg.access_token = "";
12745
- cfg.refresh_token = "";
12746
- cfg.expires_at = 0;
12747
- cfg.mode = undefined;
12748
- cfg.deployment_id = undefined;
12749
- cfg.deployment_name = undefined;
12750
- cfg.api_key = undefined;
12951
+ clearConfigInPlace(cfg);
12751
12952
  saveConfig(cfg);
12752
12953
  log.success("Credentials cleared.");
12753
12954
  }
@@ -12892,9 +13093,11 @@ async function runLoginCheck(opts) {
12892
13093
  }
12893
13094
  if (result.status === "authenticated") {
12894
13095
  const cfg = loadConfig();
12895
- cfg.access_token = result.access_token ?? "";
12896
- cfg.refresh_token = result.refresh_token ?? "";
12897
- cfg.expires_at = Math.floor(Date.now() / 1000) + (result.expires_in ?? 3600);
13096
+ replaceLoginSession(cfg, {
13097
+ access_token: result.access_token ?? "",
13098
+ refresh_token: result.refresh_token ?? "",
13099
+ expires_at: Math.floor(Date.now() / 1000) + (result.expires_in ?? 3600)
13100
+ });
12898
13101
  saveConfig(cfg);
12899
13102
  logger.info("auth.ticket", "Ticket redeemed via dosu login --check");
12900
13103
  if (opts.json) {
@@ -13085,9 +13288,11 @@ async function redeemTicket(ticket, cfg) {
13085
13288
  });
13086
13289
  return { code: 0, cfg, exit: true };
13087
13290
  }
13088
- cfg.access_token = result.access_token ?? "";
13089
- cfg.refresh_token = result.refresh_token ?? "";
13090
- cfg.expires_at = Math.floor(Date.now() / 1000) + (result.expires_in ?? 3600);
13291
+ replaceLoginSession(cfg, {
13292
+ access_token: result.access_token ?? "",
13293
+ refresh_token: result.refresh_token ?? "",
13294
+ expires_at: Math.floor(Date.now() / 1000) + (result.expires_in ?? 3600)
13295
+ });
13091
13296
  saveConfig(cfg);
13092
13297
  logger.info("agent.flow", "Ticket redeemed; session saved");
13093
13298
  emitStep({ step: "auth", email: result.email });
@@ -13102,7 +13307,7 @@ async function redeemTicket(ticket, cfg) {
13102
13307
  }
13103
13308
  }
13104
13309
  async function verifyOrMint(cfg, opts) {
13105
- if (cfg.access_token) {
13310
+ if (cfg.active_account?.session.access_token) {
13106
13311
  try {
13107
13312
  const client = new Client(cfg);
13108
13313
  const resp = await client.doRequestRaw("GET", "/v1/mcp/deployments");
@@ -13151,10 +13356,12 @@ async function resolveDeployment2(client, cfg, opts) {
13151
13356
  });
13152
13357
  return { code: 1, cfg };
13153
13358
  }
13154
- cfg.deployment_id = d.deployment_id;
13155
- cfg.deployment_name = d.name;
13156
- cfg.org_id = d.org_id;
13157
- cfg.space_id = d.space_id;
13359
+ updateTarget(cfg, {
13360
+ deployment_id: d.deployment_id,
13361
+ deployment_name: d.name,
13362
+ org_id: d.org_id,
13363
+ space_id: d.space_id
13364
+ });
13158
13365
  cfg.mode = undefined;
13159
13366
  saveConfig(cfg);
13160
13367
  emitStep({
@@ -13172,11 +13379,11 @@ async function resolveDeployment2(client, cfg, opts) {
13172
13379
  return { code: 1, cfg };
13173
13380
  }
13174
13381
  }
13175
- if (cfg.deployment_id) {
13382
+ if (cfg.active_account?.target?.deployment_id) {
13176
13383
  emitStep({
13177
13384
  step: "deployment",
13178
- deployment_id: cfg.deployment_id,
13179
- name: cfg.deployment_name
13385
+ deployment_id: cfg.active_account?.target?.deployment_id,
13386
+ name: cfg.active_account?.target?.deployment_name
13180
13387
  });
13181
13388
  return { code: 0, cfg };
13182
13389
  }
@@ -13201,10 +13408,12 @@ async function resolveDeployment2(client, cfg, opts) {
13201
13408
  }
13202
13409
  if (mcpDeployments.length === 1) {
13203
13410
  const d = mcpDeployments[0];
13204
- cfg.deployment_id = d.deployment_id;
13205
- cfg.deployment_name = d.name;
13206
- cfg.org_id = d.org_id;
13207
- cfg.space_id = d.space_id;
13411
+ updateTarget(cfg, {
13412
+ deployment_id: d.deployment_id,
13413
+ deployment_name: d.name,
13414
+ org_id: d.org_id,
13415
+ space_id: d.space_id
13416
+ });
13208
13417
  cfg.mode = undefined;
13209
13418
  saveConfig(cfg);
13210
13419
  emitStep({
@@ -13242,7 +13451,9 @@ function formatCandidates(deployments) {
13242
13451
  `);
13243
13452
  }
13244
13453
  async function ensureAPIKey(client, cfg) {
13245
- if (!cfg.deployment_id) {
13454
+ const target = cfg.active_account?.target;
13455
+ const deploymentID = target?.deployment_id;
13456
+ if (!deploymentID) {
13246
13457
  emitError({
13247
13458
  step: "api_key",
13248
13459
  reason: "no_deployment",
@@ -13251,15 +13462,15 @@ async function ensureAPIKey(client, cfg) {
13251
13462
  return { code: 1, cfg };
13252
13463
  }
13253
13464
  try {
13254
- if (cfg.api_key) {
13255
- const valid = await client.validateAPIKey(cfg.api_key, cfg.deployment_id);
13465
+ if (target.api_key) {
13466
+ const valid = await client.validateAPIKey(target.api_key, deploymentID);
13256
13467
  if (valid) {
13257
13468
  emitStep({ step: "api_key", reused: true });
13258
13469
  return { code: 0, cfg };
13259
13470
  }
13260
13471
  }
13261
- const resp = await client.createAPIKey(cfg.deployment_id, "dosu-cli");
13262
- cfg.api_key = resp.api_key;
13472
+ const resp = await client.createAPIKey(deploymentID, "dosu-cli");
13473
+ updateTarget(cfg, { api_key: resp.api_key });
13263
13474
  saveConfig(cfg);
13264
13475
  emitStep({ step: "api_key", reused: false });
13265
13476
  return { code: 0, cfg };
@@ -13307,18 +13518,18 @@ init_config();
13307
13518
  var import_picocolors2 = __toESM(require_picocolors(), 1);
13308
13519
  function requireLoginConfig() {
13309
13520
  const cfg = loadConfig();
13310
- if (!cfg.access_token) {
13521
+ if (!cfg.active_account?.session.access_token) {
13311
13522
  console.error(import_picocolors2.default.red("Not logged in. Run 'dosu login' first."));
13312
13523
  process.exit(1);
13313
13524
  }
13314
13525
  return cfg;
13315
13526
  }
13316
13527
  function requireAPIKey(cfg) {
13317
- if (!cfg.api_key) {
13528
+ if (!cfg.active_account?.target?.api_key) {
13318
13529
  console.error(import_picocolors2.default.red("API key not configured. Run 'dosu setup' first."));
13319
13530
  process.exit(1);
13320
13531
  }
13321
- return cfg.api_key;
13532
+ return cfg.active_account?.target?.api_key;
13322
13533
  }
13323
13534
 
13324
13535
  // src/commands/output.ts
@@ -13383,7 +13594,7 @@ function formatDate(dateStr) {
13383
13594
  // src/commands/analytics.ts
13384
13595
  function requireConfig() {
13385
13596
  const cfg = requireLoginConfig();
13386
- if (!cfg.space_id) {
13597
+ if (!cfg.active_account?.target?.space_id) {
13387
13598
  console.error(import_picocolors4.default.red("Missing space config. Run 'dosu setup' to reconfigure."));
13388
13599
  process.exit(1);
13389
13600
  }
@@ -13394,7 +13605,7 @@ function analyticsCommand() {
13394
13605
  const cfg = requireConfig();
13395
13606
  const client = createTypedClient(cfg);
13396
13607
  const stats = await client.analytics.getUsageStats.query({
13397
- spaceId: cfg.space_id,
13608
+ spaceId: cfg.active_account.target.space_id,
13398
13609
  days: Number.parseInt(opts.days ?? "30", 10)
13399
13610
  });
13400
13611
  if (opts.json) {
@@ -13424,11 +13635,11 @@ init_logger();
13424
13635
  var import_picocolors5 = __toESM(require_picocolors(), 1);
13425
13636
  function requireConfig2() {
13426
13637
  const cfg = loadConfig();
13427
- if (!cfg.api_key) {
13638
+ if (!cfg.active_account?.target?.api_key) {
13428
13639
  console.error(import_picocolors5.default.red("Not configured. Run 'dosu setup' first."));
13429
13640
  process.exit(1);
13430
13641
  }
13431
- if (!cfg.deployment_id || !cfg.space_id) {
13642
+ if (!cfg.active_account?.target?.deployment_id || !cfg.active_account?.target?.space_id) {
13432
13643
  console.error(import_picocolors5.default.red("Missing deployment config. Run 'dosu setup' to reconfigure."));
13433
13644
  process.exit(1);
13434
13645
  }
@@ -13450,10 +13661,10 @@ function askCommand() {
13450
13661
  method: "POST",
13451
13662
  headers: {
13452
13663
  "Content-Type": "application/json",
13453
- "X-Dosu-API-Key": cfg.api_key
13664
+ "X-Dosu-API-Key": cfg.active_account.target.api_key
13454
13665
  },
13455
13666
  body: JSON.stringify({
13456
- deployment_id: cfg.deployment_id,
13667
+ deployment_id: cfg.active_account.target.deployment_id,
13457
13668
  question,
13458
13669
  session_id: opts.session ?? undefined
13459
13670
  }),
@@ -13609,7 +13820,7 @@ function checkForReadyTasks() {
13609
13820
  }
13610
13821
  const cfg = loadConfig();
13611
13822
  const backendURL = getBackendURL();
13612
- const apiKey = cfg.api_key;
13823
+ const apiKey = cfg.active_account?.target?.api_key;
13613
13824
  if (backendURL && apiKey) {
13614
13825
  const now = Date.now();
13615
13826
  for (const task of cache.tasks) {
@@ -13650,11 +13861,11 @@ var INDEX_POLL_INTERVAL_MS = 2000;
13650
13861
  var INDEX_POLL_TIMEOUT_MS = 120000;
13651
13862
  function requireConfig3() {
13652
13863
  const cfg = requireLoginConfig();
13653
- if (!cfg.api_key) {
13864
+ if (!cfg.active_account?.target?.api_key) {
13654
13865
  console.error(import_picocolors9.default.red("API key not configured. Run 'dosu setup' first."));
13655
13866
  process.exit(1);
13656
13867
  }
13657
- if (!cfg.org_id) {
13868
+ if (!cfg.active_account?.target?.org_id) {
13658
13869
  console.error(import_picocolors9.default.red("Missing org config. Run 'dosu setup' to reconfigure."));
13659
13870
  process.exit(1);
13660
13871
  }
@@ -13732,7 +13943,10 @@ async function ensureSyncedRepo(cfg, client, detected, explicitDataSourceId, non
13732
13943
  if (explicitDataSourceId) {
13733
13944
  return explicitDataSourceId;
13734
13945
  }
13735
- let sources = await listDataSources(client, cfg.org_id);
13946
+ const orgID = cfg.active_account?.target?.org_id;
13947
+ if (!orgID)
13948
+ throw new Error("missing org config");
13949
+ let sources = await listDataSources(client, orgID);
13736
13950
  let match = findMatch(sources, detected);
13737
13951
  if (!match) {
13738
13952
  if (nonInteractive) {
@@ -13751,7 +13965,7 @@ async function ensureSyncedRepo(cfg, client, detected, explicitDataSourceId, non
13751
13965
  console.error(import_picocolors9.default.red(`Could not connect ${detected.slug}. Run 'dosu setup' and retry.`));
13752
13966
  process.exit(1);
13753
13967
  }
13754
- sources = await listDataSources(client, cfg.org_id);
13968
+ sources = await listDataSources(client, orgID);
13755
13969
  match = findMatch(sources, detected);
13756
13970
  if (!match) {
13757
13971
  console.error(import_picocolors9.default.red(`Could not find ${detected.slug} after connecting. Retry shortly.`));
@@ -13759,7 +13973,7 @@ async function ensureSyncedRepo(cfg, client, detected, explicitDataSourceId, non
13759
13973
  }
13760
13974
  }
13761
13975
  if (match.is_indexed !== true) {
13762
- const indexed = await waitForIndexed(client, cfg.org_id, detected, nonInteractive);
13976
+ const indexed = await waitForIndexed(client, orgID, detected, nonInteractive);
13763
13977
  if (!indexed) {
13764
13978
  if (nonInteractive) {
13765
13979
  console.error(import_picocolors9.default.red(`${detected.slug} is still indexing. Re-run once indexing finishes.`));
@@ -13950,7 +14164,7 @@ function deploymentsCommand() {
13950
14164
  cmd.command("list").description("List all deployments").option("--json", "Output as JSON").action(async (opts) => {
13951
14165
  const cfg = requireConfig4();
13952
14166
  const client = createTypedClient(cfg);
13953
- const deployments = cfg.org_id ? await client.workspaces.listForOrg.query(cfg.org_id) : await client.workspaces.listAll.query({});
14167
+ const deployments = cfg.active_account?.target?.org_id ? await client.workspaces.listForOrg.query(cfg.active_account?.target?.org_id) : await client.workspaces.listAll.query({});
13954
14168
  if (opts.json) {
13955
14169
  printResult(deployments, opts);
13956
14170
  return;
@@ -13965,21 +14179,21 @@ function deploymentsCommand() {
13965
14179
  d.org_id ? d.org_id.slice(0, 8) : "—",
13966
14180
  d.enabled ? import_picocolors10.default.green("active") : import_picocolors10.default.dim("disabled")
13967
14181
  ]), { rawData: deployments });
13968
- if (cfg.deployment_id) {
14182
+ if (cfg.active_account?.target?.deployment_id) {
13969
14183
  console.log(`
13970
- ${import_picocolors10.default.dim(`Current: ${cfg.deployment_name ?? cfg.deployment_id}`)}`);
14184
+ ${import_picocolors10.default.dim(`Current: ${cfg.active_account?.target?.deployment_name ?? cfg.active_account?.target?.deployment_id}`)}`);
13971
14185
  }
13972
14186
  });
13973
14187
  cmd.command("info").description("Show current deployment details").option("--json", "Output as JSON").action(async (opts) => {
13974
14188
  const cfg = requireConfig4();
13975
- if (!cfg.deployment_id) {
14189
+ if (!cfg.active_account?.target?.deployment_id) {
13976
14190
  console.error(import_picocolors10.default.red("No deployment selected. Run 'dosu setup' or 'dosu deployments switch'."));
13977
14191
  process.exit(1);
13978
14192
  }
13979
14193
  const client = createTypedClient(cfg);
13980
- const deployment = await client.workspaces.get.query(cfg.deployment_id);
14194
+ const deployment = await client.workspaces.get.query(cfg.active_account?.target?.deployment_id);
13981
14195
  if (!deployment) {
13982
- console.error(import_picocolors10.default.red(`Deployment not found: ${cfg.deployment_id}`));
14196
+ console.error(import_picocolors10.default.red(`Deployment not found: ${cfg.active_account?.target?.deployment_id}`));
13983
14197
  process.exit(1);
13984
14198
  }
13985
14199
  if (opts.json) {
@@ -14005,10 +14219,12 @@ ${import_picocolors10.default.dim(`Current: ${cfg.deployment_name ?? cfg.deploym
14005
14219
  console.error(import_picocolors10.default.red(`Deployment not found: ${id}`));
14006
14220
  process.exit(1);
14007
14221
  }
14008
- cfg.deployment_id = deployment.deployment_id;
14009
- cfg.deployment_name = deployment.name;
14010
- cfg.org_id = deployment.org_id;
14011
- cfg.space_id = deployment.space_id;
14222
+ updateTarget(cfg, {
14223
+ deployment_id: deployment.deployment_id,
14224
+ deployment_name: deployment.name,
14225
+ org_id: deployment.org_id,
14226
+ space_id: deployment.space_id
14227
+ });
14012
14228
  saveConfig(cfg);
14013
14229
  if (opts.json) {
14014
14230
  printResult({ success: true, deployment_id: deployment.deployment_id, name: deployment.name }, opts);
@@ -14029,7 +14245,7 @@ var import_picocolors11 = __toESM(require_picocolors(), 1);
14029
14245
  import { readFileSync as readFileSync5 } from "node:fs";
14030
14246
  function requireConfig5() {
14031
14247
  const cfg = requireLoginConfig();
14032
- if (!cfg.space_id) {
14248
+ if (!cfg.active_account?.target?.space_id) {
14033
14249
  console.error(import_picocolors11.default.red("Missing space config. Run 'dosu setup' to reconfigure."));
14034
14250
  process.exit(1);
14035
14251
  }
@@ -14131,7 +14347,7 @@ function docsCommand() {
14131
14347
  cmd.command("list").description("List documents").option("--search <query>", "Search documents").option("--tag <id>", "Filter by tag ID").option("--limit <n>", "Maximum results", "20").option("--json", "Output as JSON").action(async (opts) => {
14132
14348
  const cfg = requireConfig5();
14133
14349
  const client = createTypedClient(cfg);
14134
- const ksId = await getKnowledgeStoreId(client, cfg.space_id);
14350
+ const ksId = await getKnowledgeStoreId(client, cfg.active_account.target.space_id);
14135
14351
  const result = await client.page.listWithTags.query({
14136
14352
  knowledge_store_id: ksId,
14137
14353
  searchTerm: opts.search,
@@ -14183,7 +14399,7 @@ ${page.body}`);
14183
14399
  cmd.command("create").description("Create a new document").requiredOption("--title <title>", "Document title").option("--body <markdown>", "Document body (markdown)").option("--body-file <path>", "Read body from file").option("--json", "Output as JSON").action(async (opts) => {
14184
14400
  const cfg = requireConfig5();
14185
14401
  const client = createTypedClient(cfg);
14186
- const ksId = await getKnowledgeStoreId(client, cfg.space_id);
14402
+ const ksId = await getKnowledgeStoreId(client, cfg.active_account.target.space_id);
14187
14403
  const body = readBody(opts);
14188
14404
  const result = await client.page.create.mutate({
14189
14405
  knowledge_store_id: ksId,
@@ -14199,7 +14415,7 @@ ${page.body}`);
14199
14415
  cmd.command("update").description("Update a document").argument("<id>", "Page ID").option("--title <title>", "New title").option("--body <markdown>", "New body (markdown)").option("--body-file <path>", "Read body from file").option("--json", "Output as JSON").action(async (id, opts) => {
14200
14416
  const cfg = requireConfig5();
14201
14417
  const client = createTypedClient(cfg);
14202
- const ksId = await getKnowledgeStoreId(client, cfg.space_id);
14418
+ const ksId = await getKnowledgeStoreId(client, cfg.active_account.target.space_id);
14203
14419
  const body = readBody(opts);
14204
14420
  const result = await client.page.update.mutate({
14205
14421
  id,
@@ -14269,7 +14485,7 @@ ${page.body}`);
14269
14485
  cmd.command("generate").description("Generate a document using AI").requiredOption("--title <title>", "Document title").option("--instructions <text>", "Custom generation instructions").option("--json", "Output as JSON").action(async (opts) => {
14270
14486
  const cfg = requireConfig5();
14271
14487
  const client = createTypedClient(cfg);
14272
- const ksId = await getKnowledgeStoreId(client, cfg.space_id);
14488
+ const ksId = await getKnowledgeStoreId(client, cfg.active_account.target.space_id);
14273
14489
  const result = await backendPost2("/doc/generate", requireAPIKey(cfg), {
14274
14490
  knowledge_store_id: ksId,
14275
14491
  title: opts.title,
@@ -14293,7 +14509,7 @@ ${page.body}`);
14293
14509
  cmd.command("import").description("Import documents from an external platform").argument("<platform>", "Platform: github, gitlab, confluence, notion, coda").requiredOption("--files <ids>", "Comma-separated file/page IDs to import").option("--json", "Output as JSON").action(async (platform2, opts) => {
14294
14510
  const cfg = requireConfig5();
14295
14511
  const client = createTypedClient(cfg);
14296
- const ksId = await getKnowledgeStoreId(client, cfg.space_id);
14512
+ const ksId = await getKnowledgeStoreId(client, cfg.active_account.target.space_id);
14297
14513
  const fileIds = opts.files.split(",").map((id) => id.trim());
14298
14514
  const importFn = {
14299
14515
  github: (input) => client.docImports.importGithubFiles.mutate(input),
@@ -14311,7 +14527,7 @@ ${page.body}`);
14311
14527
  try {
14312
14528
  const result = await fn({
14313
14529
  knowledge_store_id: ksId,
14314
- space_id: cfg.space_id,
14530
+ space_id: cfg.active_account.target.space_id,
14315
14531
  [idField]: fileIds
14316
14532
  });
14317
14533
  if (opts.json) {
@@ -14514,7 +14730,7 @@ async function runUserPromptSubmit(input, now = Date.now(), agent = DEFAULT_AGEN
14514
14730
  return;
14515
14731
  }
14516
14732
  const cfg = loadConfig();
14517
- if (!cfg.api_key || !cfg.deployment_id) {
14733
+ if (!cfg.active_account?.target?.api_key || !cfg.active_account?.target?.deployment_id) {
14518
14734
  logger.debug("hooks", "submit skipped reason=not-configured");
14519
14735
  return;
14520
14736
  }
@@ -14523,7 +14739,7 @@ async function runUserPromptSubmit(input, now = Date.now(), agent = DEFAULT_AGEN
14523
14739
  let resp;
14524
14740
  try {
14525
14741
  resp = await tc.requestCreateTicket(cfg, {
14526
- deployment_id: cfg.deployment_id,
14742
+ deployment_id: cfg.active_account?.target?.deployment_id,
14527
14743
  agent,
14528
14744
  session_id: sessionId,
14529
14745
  turn_id: input.turn_id ?? String(now),
@@ -14568,7 +14784,7 @@ async function runPostToolUse(input, now = Date.now()) {
14568
14784
  return;
14569
14785
  }
14570
14786
  const cfg = loadConfig();
14571
- if (!cfg.api_key || !cfg.deployment_id) {
14787
+ if (!cfg.active_account?.target?.api_key || !cfg.active_account?.target?.deployment_id) {
14572
14788
  saveState({ ...state, lastCheckedAt: now });
14573
14789
  return;
14574
14790
  }
@@ -14620,7 +14836,7 @@ async function runStop(input, now = Date.now()) {
14620
14836
  if (state.status !== "pending" || now > state.expiresAt)
14621
14837
  return printContinue();
14622
14838
  const cfg = loadConfig();
14623
- if (!cfg.api_key || !cfg.deployment_id)
14839
+ if (!cfg.active_account?.target?.api_key || !cfg.active_account?.target?.deployment_id)
14624
14840
  return printContinue();
14625
14841
  const tc = await Promise.resolve().then(() => (init_ticket_client(), exports_ticket_client));
14626
14842
  const pollMs = stopPollMs();
@@ -14914,11 +15130,11 @@ async function collectDoctorChecks(opts) {
14914
15130
  } else {
14915
15131
  checks.push({ name: "auth", status: "fail", detail: "not logged in (run 'dosu login')" });
14916
15132
  }
14917
- if (cfg.deployment_id || cfg.mode === MODE_OSS) {
15133
+ if (cfg.active_account?.target?.deployment_id || cfg.mode === MODE_OSS) {
14918
15134
  checks.push({
14919
15135
  name: "deployment",
14920
15136
  status: "ok",
14921
- detail: cfg.deployment_name ?? cfg.deployment_id ?? "oss"
15137
+ detail: cfg.active_account?.target?.deployment_name ?? cfg.active_account?.target?.deployment_id ?? "oss"
14922
15138
  });
14923
15139
  } else {
14924
15140
  checks.push({
@@ -14927,9 +15143,9 @@ async function collectDoctorChecks(opts) {
14927
15143
  detail: "no deployment selected (run 'dosu setup')"
14928
15144
  });
14929
15145
  }
14930
- if (cfg.api_key && cfg.deployment_id) {
15146
+ if (cfg.active_account?.target?.api_key && cfg.active_account?.target?.deployment_id) {
14931
15147
  const { Client: Client2 } = await Promise.resolve().then(() => (init_client(), exports_client));
14932
- const ok = await new Client2(cfg).validateAPIKey(cfg.api_key, cfg.deployment_id);
15148
+ const ok = await new Client2(cfg).validateAPIKey(cfg.active_account?.target?.api_key, cfg.active_account?.target?.deployment_id);
14933
15149
  checks.push({
14934
15150
  name: "backend",
14935
15151
  status: ok ? "ok" : "fail",
@@ -15020,7 +15236,7 @@ init_trpc();
15020
15236
  var import_picocolors15 = __toESM(require_picocolors(), 1);
15021
15237
  function requireConfig6() {
15022
15238
  const cfg = requireLoginConfig();
15023
- if (!cfg.org_id) {
15239
+ if (!cfg.active_account?.target?.org_id) {
15024
15240
  console.error(import_picocolors15.default.red("Missing org config. Run 'dosu setup' to reconfigure."));
15025
15241
  process.exit(1);
15026
15242
  }
@@ -15056,7 +15272,7 @@ function integrationsCommand() {
15056
15272
  const conn = await client.nango.getConnection.query({
15057
15273
  provider: nangoProvider,
15058
15274
  providerConfigKey: nangoProvider,
15059
- orgId: cfg.org_id
15275
+ orgId: cfg.active_account.target.org_id
15060
15276
  });
15061
15277
  results.push({ platform: platform4, connected: conn !== null });
15062
15278
  } catch {
@@ -15091,7 +15307,7 @@ function integrationsCommand() {
15091
15307
  const conn = await client.nango.getConnection.query({
15092
15308
  provider: nangoProvider,
15093
15309
  providerConfigKey: nangoProvider,
15094
- orgId: cfg.org_id
15310
+ orgId: cfg.active_account.target.org_id
15095
15311
  });
15096
15312
  const connected = conn !== null;
15097
15313
  if (opts.json) {
@@ -15110,7 +15326,7 @@ function integrationsCommand() {
15110
15326
  cmd.command("slack-channels").description("List Slack channels").option("--json", "Output as JSON").action(async (opts) => {
15111
15327
  const cfg = requireConfig6();
15112
15328
  const client = createTypedClient(cfg);
15113
- const channels = await client.slackChannel.getAll.query(cfg.org_id);
15329
+ const channels = await client.slackChannel.getAll.query(cfg.active_account.target.org_id);
15114
15330
  if (opts.json) {
15115
15331
  printResult(channels, opts);
15116
15332
  return;
@@ -15157,7 +15373,7 @@ init_trpc();
15157
15373
  var import_picocolors16 = __toESM(require_picocolors(), 1);
15158
15374
  function requireConfig7() {
15159
15375
  const cfg = requireLoginConfig();
15160
- if (!cfg.org_id || !cfg.space_id) {
15376
+ if (!cfg.active_account?.target?.org_id || !cfg.active_account?.target?.space_id) {
15161
15377
  console.error(import_picocolors16.default.red("Missing org/space config. Run 'dosu setup' to reconfigure."));
15162
15378
  process.exit(1);
15163
15379
  }
@@ -15169,7 +15385,7 @@ function knowledgeCommand() {
15169
15385
  const cfg = requireConfig7();
15170
15386
  const client = createTypedClient(cfg);
15171
15387
  const dataSources = await client.dataSource.list.query({
15172
- org_id: cfg.org_id,
15388
+ org_id: cfg.active_account.target.org_id,
15173
15389
  excluded_provider_slugs: []
15174
15390
  });
15175
15391
  const dataSourceIds = dataSources.map((ds) => ds.id).filter((id) => id !== null);
@@ -15205,7 +15421,7 @@ ${results.length - limit} more results not shown.`));
15205
15421
  cmd.command("list").description("Show knowledge store information").option("--json", "Output as JSON").action(async (opts) => {
15206
15422
  const cfg = requireConfig7();
15207
15423
  const client = createTypedClient(cfg);
15208
- const store = await client.knowledgeStore.getBySpaceId.query({ space_id: cfg.space_id });
15424
+ const store = await client.knowledgeStore.getBySpaceId.query({ space_id: cfg.active_account.target.space_id });
15209
15425
  if (opts.json) {
15210
15426
  printResult(store, opts);
15211
15427
  return;
@@ -15227,7 +15443,7 @@ init_trpc();
15227
15443
  var import_picocolors17 = __toESM(require_picocolors(), 1);
15228
15444
  function requireConfig8() {
15229
15445
  const cfg = requireLoginConfig();
15230
- if (!cfg.org_id) {
15446
+ if (!cfg.active_account?.target?.org_id) {
15231
15447
  console.error(import_picocolors17.default.red("Missing org config. Run 'dosu setup' to reconfigure."));
15232
15448
  process.exit(1);
15233
15449
  }
@@ -15257,7 +15473,7 @@ function membersCommand() {
15257
15473
  const client = createTypedClient(cfg);
15258
15474
  const role = opts.role.toUpperCase() === "ADMIN" ? "ADMIN" : "MEMBER";
15259
15475
  await client.invitations.invite.mutate({
15260
- orgId: cfg.org_id,
15476
+ orgId: cfg.active_account.target.org_id,
15261
15477
  email,
15262
15478
  role
15263
15479
  });
@@ -15288,7 +15504,7 @@ function membersCommand() {
15288
15504
  const cfg = requireConfig8();
15289
15505
  const client = createTypedClient(cfg);
15290
15506
  await client.invitations.acceptInvitation.mutate({
15291
- orgId: cfg.org_id,
15507
+ orgId: cfg.active_account.target.org_id,
15292
15508
  email
15293
15509
  });
15294
15510
  if (opts.json) {
@@ -15301,7 +15517,7 @@ function membersCommand() {
15301
15517
  const cfg = requireConfig8();
15302
15518
  const client = createTypedClient(cfg);
15303
15519
  await client.invitations.rejectInvitation.mutate({
15304
- orgId: cfg.org_id,
15520
+ orgId: cfg.active_account.target.org_id,
15305
15521
  email
15306
15522
  });
15307
15523
  if (opts.json) {
@@ -15343,9 +15559,9 @@ function orgCommand() {
15343
15559
  return;
15344
15560
  }
15345
15561
  printTable(["ID", "Name"], orgs.map((o2) => [o2.org_id.slice(0, 8), o2.name]), { rawData: orgs });
15346
- if (cfg.org_id) {
15562
+ if (cfg.active_account?.target?.org_id) {
15347
15563
  console.log(`
15348
- ${import_picocolors18.default.dim(`Current: ${cfg.org_id}`)}`);
15564
+ ${import_picocolors18.default.dim(`Current: ${cfg.active_account?.target?.org_id}`)}`);
15349
15565
  }
15350
15566
  });
15351
15567
  return cmd;
@@ -15459,15 +15675,15 @@ function reviewCommand() {
15459
15675
  const cmd = new Command("review").description("Review workflow (doc changes and draft replies)");
15460
15676
  cmd.command("list").description("List pending review items (doc changes and draft replies)").option("--json", "Output as JSON").action(async (opts) => {
15461
15677
  const cfg = requireConfig10();
15462
- if (!cfg.space_id) {
15678
+ if (!cfg.active_account?.target?.space_id) {
15463
15679
  console.error(import_picocolors19.default.red("Missing space config. Run 'dosu setup' to reconfigure."));
15464
15680
  process.exit(1);
15465
15681
  }
15466
15682
  const client = createTypedClient(cfg);
15467
- const ksId = await getKnowledgeStoreId2(client, cfg.space_id);
15683
+ const ksId = await getKnowledgeStoreId2(client, cfg.active_account?.target?.space_id);
15468
15684
  const result = await client.review.listPending.query({
15469
15685
  knowledgeStoreId: ksId,
15470
- deploymentId: cfg.deployment_id
15686
+ deploymentId: cfg.active_account?.target?.deployment_id
15471
15687
  });
15472
15688
  const { items, truncated, total } = result;
15473
15689
  if (opts.json) {
@@ -15683,7 +15899,7 @@ init_trpc();
15683
15899
  var import_picocolors20 = __toESM(require_picocolors(), 1);
15684
15900
  function requireConfig11() {
15685
15901
  const cfg = requireLoginConfig();
15686
- if (!cfg.org_id) {
15902
+ if (!cfg.active_account?.target?.org_id) {
15687
15903
  console.error(import_picocolors20.default.red("Missing org config. Run 'dosu setup' to reconfigure."));
15688
15904
  process.exit(1);
15689
15905
  }
@@ -15695,7 +15911,7 @@ function sourcesCommand() {
15695
15911
  const cfg = requireConfig11();
15696
15912
  const client = createTypedClient(cfg);
15697
15913
  const dataSources = await client.dataSource.list.query({
15698
- org_id: cfg.org_id,
15914
+ org_id: cfg.active_account.target.org_id,
15699
15915
  excluded_provider_slugs: []
15700
15916
  });
15701
15917
  if (opts.json) {
@@ -15777,7 +15993,7 @@ init_trpc();
15777
15993
  var import_picocolors21 = __toESM(require_picocolors(), 1);
15778
15994
  function requireConfig12() {
15779
15995
  const cfg = requireLoginConfig();
15780
- if (!cfg.space_id) {
15996
+ if (!cfg.active_account?.target?.space_id) {
15781
15997
  console.error(import_picocolors21.default.red("Missing space config. Run 'dosu setup' to reconfigure."));
15782
15998
  process.exit(1);
15783
15999
  }
@@ -15798,7 +16014,7 @@ function suggestCommand() {
15798
16014
  cmd.command("list").description("List pending document suggestions").option("--json", "Output as JSON").action(async (opts) => {
15799
16015
  const cfg = requireConfig12();
15800
16016
  const client = createTypedClient(cfg);
15801
- const ksId = await getKnowledgeStoreId3(client, cfg.space_id);
16017
+ const ksId = await getKnowledgeStoreId3(client, cfg.active_account.target.space_id);
15802
16018
  const suggestions = await client.suggestedDoc.listForKnowledgeStore.query({
15803
16019
  knowledgeStoreId: ksId
15804
16020
  });
@@ -15818,13 +16034,13 @@ function suggestCommand() {
15818
16034
  cmd.command("generate").description("Generate new document suggestions from data sources").option("--json", "Output as JSON").action(async (opts) => {
15819
16035
  const cfg = requireConfig12();
15820
16036
  const client = createTypedClient(cfg);
15821
- const ksId = await getKnowledgeStoreId3(client, cfg.space_id);
15822
- if (!cfg.org_id) {
16037
+ const ksId = await getKnowledgeStoreId3(client, cfg.active_account.target.space_id);
16038
+ if (!cfg.active_account?.target?.org_id) {
15823
16039
  console.error(import_picocolors21.default.red("Missing org config. Run 'dosu setup' to reconfigure."));
15824
16040
  process.exit(1);
15825
16041
  }
15826
16042
  const dataSources = await client.dataSource.list.query({
15827
- org_id: cfg.org_id,
16043
+ org_id: cfg.active_account?.target?.org_id,
15828
16044
  excluded_provider_slugs: []
15829
16045
  });
15830
16046
  const dataSourceIds = dataSources.map((ds) => ds.id).filter((id) => id !== null);
@@ -15857,7 +16073,7 @@ init_trpc();
15857
16073
  var import_picocolors22 = __toESM(require_picocolors(), 1);
15858
16074
  function requireConfig13() {
15859
16075
  const cfg = requireLoginConfig();
15860
- if (!cfg.space_id) {
16076
+ if (!cfg.active_account?.target?.space_id) {
15861
16077
  console.error(import_picocolors22.default.red("Missing space config. Run 'dosu setup' to reconfigure."));
15862
16078
  process.exit(1);
15863
16079
  }
@@ -15881,7 +16097,7 @@ function threadsCommand() {
15881
16097
  read: undefined,
15882
16098
  resolved: undefined,
15883
16099
  search: undefined,
15884
- space_id: cfg.space_id,
16100
+ space_id: cfg.active_account.target.space_id,
15885
16101
  workspaces: undefined,
15886
16102
  limit: Math.min(Number.parseInt(opts.limit ?? "20", 10), 100)
15887
16103
  };
@@ -15976,7 +16192,7 @@ init_trpc();
15976
16192
  var import_picocolors23 = __toESM(require_picocolors(), 1);
15977
16193
  function requireConfig14() {
15978
16194
  const cfg = requireLoginConfig();
15979
- if (!cfg.space_id) {
16195
+ if (!cfg.active_account?.target?.space_id) {
15980
16196
  console.error(import_picocolors23.default.red("Missing space config. Run 'dosu setup' to reconfigure."));
15981
16197
  process.exit(1);
15982
16198
  }
@@ -15997,7 +16213,7 @@ function topicsCommand() {
15997
16213
  cmd.command("list").description("List all topics").option("--json", "Output as JSON").action(async (opts) => {
15998
16214
  const cfg = requireConfig14();
15999
16215
  const client = createTypedClient(cfg);
16000
- const ksId = await getKnowledgeStoreId4(client, cfg.space_id);
16216
+ const ksId = await getKnowledgeStoreId4(client, cfg.active_account.target.space_id);
16001
16217
  const topics = await client.topic.listTopicsByKnowledgeStore.query({
16002
16218
  knowledge_store_id: ksId
16003
16219
  });
@@ -16018,7 +16234,7 @@ function topicsCommand() {
16018
16234
  cmd.command("pages").description("List pages with a specific topic").argument("<topic-id>", "Topic ID").option("--search <query>", "Search within the topic's pages").option("--limit <n>", "Maximum results", "10").option("--json", "Output as JSON").action(async (topicId, opts) => {
16019
16235
  const cfg = requireConfig14();
16020
16236
  const client = createTypedClient(cfg);
16021
- const ksId = await getKnowledgeStoreId4(client, cfg.space_id);
16237
+ const ksId = await getKnowledgeStoreId4(client, cfg.active_account.target.space_id);
16022
16238
  const result = await client.topic.getPagesByTopicId.query({
16023
16239
  knowledge_store_id: ksId,
16024
16240
  topic_id: topicId,
@@ -16291,9 +16507,11 @@ Run 'dosu --help' to see available commands.`;
16291
16507
  token = result.token;
16292
16508
  }
16293
16509
  }
16294
- cfg.access_token = token.access_token;
16295
- cfg.refresh_token = token.refresh_token;
16296
- cfg.expires_at = Math.floor(Date.now() / 1000) + token.expires_in;
16510
+ replaceLoginSession(cfg, {
16511
+ access_token: token.access_token,
16512
+ refresh_token: token.refresh_token,
16513
+ expires_at: Math.floor(Date.now() / 1000) + token.expires_in
16514
+ });
16297
16515
  saveConfig(cfg);
16298
16516
  console.log("Successfully authenticated!");
16299
16517
  console.log(`Credentials saved to ${getConfigPath()}`);
@@ -16304,14 +16522,7 @@ Run 'dosu --help' to see available commands.`;
16304
16522
  console.log("You are not logged in.");
16305
16523
  return;
16306
16524
  }
16307
- cfg.access_token = "";
16308
- cfg.refresh_token = "";
16309
- cfg.expires_at = 0;
16310
- cfg.deployment_id = undefined;
16311
- cfg.deployment_name = undefined;
16312
- cfg.api_key = undefined;
16313
- cfg.org_id = undefined;
16314
- cfg.space_id = undefined;
16525
+ clearConfigInPlace(cfg);
16315
16526
  saveConfig(cfg);
16316
16527
  console.log("Successfully logged out.");
16317
16528
  });
@@ -16331,9 +16542,9 @@ Run 'dosu --help' to see available commands.`;
16331
16542
  if (cfg.mode === MODE_OSS) {
16332
16543
  console.log("Mode: OSS");
16333
16544
  console.log("MCP: Public libraries only");
16334
- } else if (cfg.deployment_id) {
16335
- console.log(`MCP: ${cfg.deployment_name}`);
16336
- console.log(`MCP ID: ${cfg.deployment_id}`);
16545
+ } else if (cfg.active_account?.target?.deployment_id) {
16546
+ console.log(`MCP: ${cfg.active_account?.target?.deployment_name}`);
16547
+ console.log(`MCP ID: ${cfg.active_account?.target?.deployment_id}`);
16337
16548
  } else {
16338
16549
  console.log("MCP: None selected");
16339
16550
  console.log("Run 'dosu deployments list' to see available MCPs, then 'dosu deployments switch <id>' to select one.");
@@ -16354,10 +16565,10 @@ Run 'dosu --help' to see available commands.`;
16354
16565
  if (isTokenExpired(cfg) && !await ensureFreshSession(cfg)) {
16355
16566
  throw new Error("session expired. Run 'dosu login' to re-authenticate");
16356
16567
  }
16357
- if (cfg.mode !== MODE_OSS && !cfg.deployment_id) {
16568
+ if (cfg.mode !== MODE_OSS && !cfg.active_account?.target?.deployment_id) {
16358
16569
  throw new Error("no MCP selected. Run 'dosu' to open the TUI and select an MCP");
16359
16570
  }
16360
- if (!cfg.api_key) {
16571
+ if (!cfg.active_account?.target?.api_key) {
16361
16572
  throw new Error("no API key available. Run 'dosu setup' to create one");
16362
16573
  }
16363
16574
  if (provider.id() === "manual") {