@tencent-ai/cloud-agent-sdk 0.2.12 → 0.2.13-next.8f136b6.20260204

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.cjs CHANGED
@@ -2411,7 +2411,7 @@ var CloudAgentConnection = class {
2411
2411
  }
2412
2412
  async createSession(params) {
2413
2413
  return {
2414
- ...await this.client.loadSession(this.agentId, this.cwd),
2414
+ ...await this.client.createSession(this.cwd),
2415
2415
  sessionId: this.agentId
2416
2416
  };
2417
2417
  }
@@ -16212,6 +16212,7 @@ var AccountService = class {
16212
16212
  this.initPromise = null;
16213
16213
  this.initResolve = null;
16214
16214
  this.requestInterceptorId = null;
16215
+ this.crossTabBroadcaster = null;
16215
16216
  this.initPromise = new Promise((resolve) => {
16216
16217
  this.initResolve = resolve;
16217
16218
  });
@@ -16260,15 +16261,34 @@ var AccountService = class {
16260
16261
  this.initialized = true;
16261
16262
  this.initResolve?.(account);
16262
16263
  }
16263
- if (!wasInitialized || prev?.uid !== account?.uid) this.notifyListeners();
16264
+ if (!wasInitialized || prev?.uid !== account?.uid) {
16265
+ this.notifyListeners();
16266
+ if (account && this.crossTabBroadcaster) this.crossTabBroadcaster.broadcastLogin();
16267
+ }
16264
16268
  }
16265
16269
  /**
16266
16270
  * 清除账号(登出)
16271
+ * 先广播登出消息,再清除本地账号
16267
16272
  */
16268
16273
  clearAccount() {
16274
+ if (this.crossTabBroadcaster) this.crossTabBroadcaster.broadcastLogout();
16275
+ this.setAccount(null);
16276
+ }
16277
+ /**
16278
+ * 静默清除账号(不广播)
16279
+ * 用于收到其他标签页 logout 消息时,避免循环广播
16280
+ */
16281
+ clearAccountSilently() {
16269
16282
  this.setAccount(null);
16270
16283
  }
16271
16284
  /**
16285
+ * 设置跨标签页认证同步广播器
16286
+ * 应在应用初始化时由上层(如 agent-ui)调用
16287
+ */
16288
+ setCrossTabBroadcaster(broadcaster) {
16289
+ this.crossTabBroadcaster = broadcaster;
16290
+ }
16291
+ /**
16272
16292
  * 订阅账号变化
16273
16293
  * @param callback 变化时的回调函数
16274
16294
  * @returns 取消订阅函数
@@ -16333,6 +16353,11 @@ var AccountService = class {
16333
16353
  * 导出单例实例
16334
16354
  */
16335
16355
  const accountService = new AccountService();
16356
+ /**
16357
+ * 暴露给全局,供 Agent Manager 直接调用 setAccount 刷新 Widget 状态
16358
+ * 这是为了解决 IDE 环境中 IPC 事件无法直接触发 Widget 账号刷新的问题
16359
+ */
16360
+ if (typeof window !== "undefined") window.__genieAccountService = accountService;
16336
16361
 
16337
16362
  //#endregion
16338
16363
  //#region ../agent-provider/src/common/utils/concurrency.ts
@@ -16940,13 +16965,19 @@ var CloudAgentProvider = class CloudAgentProvider {
16940
16965
  /**
16941
16966
  * Create a new conversation
16942
16967
  * POST {endpoint}/console/as/conversations
16968
+ * @param params - Optional session params containing _meta with tags
16943
16969
  */
16944
- async create() {
16970
+ async create(params) {
16945
16971
  try {
16946
- const apiResponse = await httpService.post("/console/as/conversations/", {
16972
+ const tagsObj = (params?._meta?.["codebuddy.ai"])?.tags;
16973
+ const tagsArray = tagsObj ? Object.entries(tagsObj).map(([key, value]) => `${key}:${value}`) : void 0;
16974
+ const createPayload = {
16947
16975
  prompt: "",
16948
- model: "deepseek-r1"
16949
- });
16976
+ model: "deepseek-r1",
16977
+ ...tagsArray && tagsArray.length > 0 ? { tags: tagsArray } : {}
16978
+ };
16979
+ console.log("[CloudAgentProvider] Creating conversation with payload:", createPayload);
16980
+ const apiResponse = await httpService.post("/console/as/conversations/", createPayload);
16950
16981
  if (!apiResponse.data) throw new Error("No data in API response");
16951
16982
  this.logger?.info(`Created conversation: ${apiResponse.data.id}`);
16952
16983
  return apiResponse.data.id;
@@ -17643,8 +17674,8 @@ var ActiveSessionImpl = class {
17643
17674
  * await session.setMode('architect');
17644
17675
  * ```
17645
17676
  */
17646
- async setMode(modeId) {
17647
- if (this._availableModes) {
17677
+ async setMode(modeId, skipAvailableChecker) {
17678
+ if (this._availableModes && !skipAvailableChecker) {
17648
17679
  if (!this._availableModes.some((m) => m.id === modeId)) {
17649
17680
  const availableIds = this._availableModes.map((m) => m.id).join(", ");
17650
17681
  throw new Error(`Invalid modeId: "${modeId}". Available modes: ${availableIds}`);
@@ -17835,14 +17866,6 @@ var ActiveSessionImpl = class {
17835
17866
  //#endregion
17836
17867
  //#region ../agent-provider/src/common/client/session-manager.ts
17837
17868
  /**
17838
- * SessionManager - Manages session lifecycle and connections
17839
- *
17840
- * Provides the core implementation for session-centric API operations:
17841
- * - list() - Lists sessions (mapped from agents)
17842
- * - createSession() - Creates new session (auto-creates agent)
17843
- * - loadSession() - Loads existing session (finds agent by sessionId)
17844
- */
17845
- /**
17846
17869
  * SessionManager - Session lifecycle management
17847
17870
  *
17848
17871
  * This class manages the relationship between sessions and agents.
@@ -17938,14 +17961,8 @@ var SessionManager = class {
17938
17961
  connectionInfo
17939
17962
  });
17940
17963
  session.setModes(response.modes?.availableModes, response.modes?.currentModeId);
17941
- if (response.models?.availableModels) {
17942
- const localModels = response.models.availableModels.map((m) => ({
17943
- id: m.modelId,
17944
- name: m.name,
17945
- description: m.description ?? void 0
17946
- }));
17947
- session.setModels(localModels, response.models?.currentModelId);
17948
- }
17964
+ const availableModels = this.extractAvailableModels(response);
17965
+ if (availableModels) session.setModels(availableModels, response.models?.currentModelId);
17949
17966
  this.logger?.info(`Session created: ${response.sessionId}`);
17950
17967
  return session;
17951
17968
  }
@@ -17981,17 +17998,31 @@ var SessionManager = class {
17981
17998
  mcpServers: params.mcpServers
17982
17999
  });
17983
18000
  session.setModes(response.modes?.availableModes, response.modes?.currentModeId);
17984
- if (response.models?.availableModels) {
17985
- const localModels = response.models.availableModels.map((m) => ({
17986
- id: m.modelId,
17987
- name: m.name,
17988
- description: m.description ?? void 0
17989
- }));
17990
- session.setModels(localModels, response.models?.currentModelId);
17991
- }
18001
+ const availableModels = this.extractAvailableModels(response);
18002
+ if (availableModels) session.setModels(availableModels, response.models?.currentModelId);
17992
18003
  this.logger?.info(`Session loaded: ${params.sessionId}`);
17993
18004
  return session;
17994
18005
  }
18006
+ /**
18007
+ * 从 ACP response 中提取可用模型列表
18008
+ *
18009
+ * 优先级:
18010
+ * 1. response.models._meta?.['codebuddy.ai']?.availableModels - 包含完整的模型信息(字段名为 'id')
18011
+ * 2. response.models?.availableModels - 只包含基本信息(字段名为 'modelId')
18012
+ * 3. undefined - 都没有时返回 undefined
18013
+ *
18014
+ * @param response - ACP 响应对象
18015
+ * @returns ModelInfo[] | undefined
18016
+ */
18017
+ extractAvailableModels(response) {
18018
+ const metaModels = (response.models?._meta?.["codebuddy.ai"])?.availableModels;
18019
+ if (metaModels && Array.isArray(metaModels) && metaModels.length > 0) return metaModels;
18020
+ const availableModels = response.models?.availableModels;
18021
+ if (availableModels && Array.isArray(availableModels) && availableModels.length > 0) return availableModels.map((model) => ({
18022
+ ...model,
18023
+ ...model._meta?.["codebuddy.ai"] || {}
18024
+ }));
18025
+ }
17995
18026
  };
17996
18027
 
17997
18028
  //#endregion
@@ -18264,6 +18295,28 @@ var AgentClient = class {
18264
18295
  };
18265
18296
  }
18266
18297
  },
18298
+ getSubagentList: async (params) => {
18299
+ try {
18300
+ if (this.provider && this.provider.getSubagentList) {
18301
+ const result = await this.provider.getSubagentList(params);
18302
+ this.logger?.info("Subagent list retrieved", {
18303
+ resultCount: result.results.length,
18304
+ hasError: !!result.error
18305
+ });
18306
+ return result;
18307
+ }
18308
+ return {
18309
+ results: [],
18310
+ error: "Provider does not support getSubagentList"
18311
+ };
18312
+ } catch (error) {
18313
+ this.logger?.error("Failed to get subagent list", error);
18314
+ return {
18315
+ results: [],
18316
+ error: error instanceof Error ? error.message : "Unknown error"
18317
+ };
18318
+ }
18319
+ },
18267
18320
  batchTogglePlugins: async (request) => {
18268
18321
  try {
18269
18322
  if (this.provider && this.provider.batchTogglePlugins) {
@@ -18308,10 +18361,10 @@ var AgentClient = class {
18308
18361
  return [];
18309
18362
  }
18310
18363
  },
18311
- installPlugins: async (pluginNames, marketplaceName, installScope) => {
18364
+ installPlugins: async (pluginNames, marketplaceName, installScope, marketplaceSource) => {
18312
18365
  try {
18313
18366
  if (this.provider && "installPlugins" in this.provider && typeof this.provider.installPlugins === "function") {
18314
- const result = await this.provider.installPlugins(pluginNames, marketplaceName, installScope);
18367
+ const result = await this.provider.installPlugins(pluginNames, marketplaceName, installScope, marketplaceSource);
18315
18368
  this.logger?.info("Install plugins", {
18316
18369
  pluginNames,
18317
18370
  marketplaceName,
@@ -18346,6 +18399,23 @@ var AgentClient = class {
18346
18399
  return [];
18347
18400
  }
18348
18401
  },
18402
+ getAvailableCommands: async (sessionId) => {
18403
+ try {
18404
+ if (this.provider && "getAvailableCommands" in this.provider && typeof this.provider.getAvailableCommands === "function") {
18405
+ const result = await this.provider.getAvailableCommands(sessionId);
18406
+ this.logger?.info("Got available commands from provider", {
18407
+ sessionId: sessionId ?? "(default)",
18408
+ count: result?.length ?? 0
18409
+ });
18410
+ return result;
18411
+ }
18412
+ this.logger?.warn("Provider does not support getAvailableCommands", { sessionId });
18413
+ return [];
18414
+ } catch (error) {
18415
+ this.logger?.error("Failed to get available commands", error);
18416
+ return [];
18417
+ }
18418
+ },
18349
18419
  models: this.createModelsResource()
18350
18420
  };
18351
18421
  }
@@ -18412,6 +18482,154 @@ let AccountStatus = /* @__PURE__ */ function(AccountStatus) {
18412
18482
  return AccountStatus;
18413
18483
  }({});
18414
18484
 
18485
+ //#endregion
18486
+ //#region ../agent-provider/src/backend/service/oauth-repository-service.ts
18487
+ /**
18488
+ * OAuth Repository Service
18489
+ *
18490
+ * 封装 OAuth 连接器相关的仓库和分支操作
18491
+ */
18492
+ /**
18493
+ * OAuth Repository Service
18494
+ *
18495
+ * 提供仓库和分支的查询操作
18496
+ */
18497
+ var OAuthRepositoryService = class {
18498
+ /**
18499
+ * 获取仓库分支列表
18500
+ * API 端点: GET /console/as/connector/oauth/{name}/branches
18501
+ *
18502
+ * @param connector 连接器名称 ('github' | 'gongfeng' | 'cnb')
18503
+ * @param params 平台特定的查询参数
18504
+ * @param page 页码,从1开始,0表示不分页获取全部
18505
+ * @param perPage 每页数量,最大100
18506
+ * @returns Promise<OauthBranch[]> 分支列表
18507
+ *
18508
+ * @example
18509
+ * ```typescript
18510
+ * // GitHub
18511
+ * const branches = await service.getBranches('github', {
18512
+ * owner: 'CodeBuddy-Official-Account',
18513
+ * repo: 'CodeBuddyIDE'
18514
+ * });
18515
+ *
18516
+ * // Gongfeng
18517
+ * const branches = await service.getBranches('gongfeng', {
18518
+ * project_id: '1611499'
18519
+ * });
18520
+ *
18521
+ * // CNB
18522
+ * const branches = await service.getBranches('cnb', {
18523
+ * repo: 'genie/genie-ide'
18524
+ * });
18525
+ * ```
18526
+ */
18527
+ async getBranches(connector, params, page = 0, perPage = 100) {
18528
+ try {
18529
+ const url = `/console/as/connector/oauth/${connector}/branches?${this.buildBranchQueryParams(connector, params, page, perPage).toString()}`;
18530
+ console.log(`[OAuthRepositoryService] GET ${url}`);
18531
+ const apiResponse = await httpService.get(url);
18532
+ if (!apiResponse.data) {
18533
+ console.warn(`[OAuthRepositoryService] No data in branches response for ${connector}`);
18534
+ return [];
18535
+ }
18536
+ const branches = apiResponse.data.branches || [];
18537
+ console.log(`[OAuthRepositoryService] Retrieved ${branches.length} branches from ${connector}`);
18538
+ return branches;
18539
+ } catch (error) {
18540
+ console.error(`[OAuthRepositoryService] Failed to get branches from ${connector}:`, error);
18541
+ throw error;
18542
+ }
18543
+ }
18544
+ /**
18545
+ * 获取仓库列表
18546
+ * API 端点: GET /console/as/connector/oauth/{name}/repos
18547
+ *
18548
+ * Note: 由于工蜂原生支持的 Search 能力会匹配 path/name/description 部分,
18549
+ * 且不支持定制,不满足产品要求(只按 name 匹配),因此前端拉取全量数据后做筛选。
18550
+ *
18551
+ * @param connector 连接器名称 ('github' | 'gongfeng' | 'cnb')
18552
+ * @param page 页码,从1开始,0表示不分页获取全部
18553
+ * - GitHub 只支持全量数据,必须传 0
18554
+ * - 工蜂和 CNB 依据前端逻辑而定
18555
+ * @param perPage 每页数量,最大100
18556
+ * @returns Promise<ListReposResponse> 仓库列表响应
18557
+ *
18558
+ * @example
18559
+ * ```typescript
18560
+ * // GitHub - 必须传 page=0 获取全量数据
18561
+ * const response = await service.getRepositories('github', 0, 100);
18562
+ * // response.github_repos 是 map: installation_id => repo[]
18563
+ *
18564
+ * // Gongfeng
18565
+ * const response = await service.getRepositories('gongfeng', 0, 100);
18566
+ * // response.gongfeng_repos 是数组
18567
+ *
18568
+ * // CNB
18569
+ * const response = await service.getRepositories('cnb', 0, 100);
18570
+ * // response.cnb_repos 是数组
18571
+ * ```
18572
+ */
18573
+ async getRepositories(connector, page = 0, perPage = 100) {
18574
+ try {
18575
+ const queryParams = new URLSearchParams();
18576
+ queryParams.append("page", String(page));
18577
+ queryParams.append("per_page", String(Math.min(perPage, 100)));
18578
+ const url = `/console/as/connector/oauth/${connector}/repos?${queryParams.toString()}`;
18579
+ console.log(`[OAuthRepositoryService] GET ${url}`);
18580
+ const apiResponse = await httpService.get(url);
18581
+ if (!apiResponse.data) {
18582
+ console.warn(`[OAuthRepositoryService] No data in repos response for ${connector}`);
18583
+ return {};
18584
+ }
18585
+ const response = apiResponse.data;
18586
+ this.logRepositoryCounts(response);
18587
+ return response;
18588
+ } catch (error) {
18589
+ console.error(`[OAuthRepositoryService] Failed to get repos from ${connector}:`, error);
18590
+ throw error;
18591
+ }
18592
+ }
18593
+ /**
18594
+ * 构建分支查询参数
18595
+ */
18596
+ buildBranchQueryParams(connector, params, page, perPage) {
18597
+ const queryParams = new URLSearchParams();
18598
+ queryParams.append("page", String(page));
18599
+ queryParams.append("per_page", String(Math.min(perPage, 100)));
18600
+ if (connector === "github") {
18601
+ const githubParams = params;
18602
+ if (!githubParams.owner || !githubParams.repo) throw new Error("GitHub requires owner and repo parameters");
18603
+ queryParams.append("owner", githubParams.owner);
18604
+ queryParams.append("repo", githubParams.repo);
18605
+ } else if (connector === "gongfeng") {
18606
+ const gongfengParams = params;
18607
+ if (!gongfengParams.project_id) throw new Error("Gongfeng requires project_id parameter");
18608
+ queryParams.append("project_id", gongfengParams.project_id);
18609
+ } else if (connector === "cnb") {
18610
+ const cnbParams = params;
18611
+ if (!cnbParams.repo) throw new Error("CNB requires repo parameter");
18612
+ queryParams.append("repo", cnbParams.repo);
18613
+ } else throw new Error(`Unknown connector: ${connector}`);
18614
+ return queryParams;
18615
+ }
18616
+ /**
18617
+ * 记录仓库数量日志
18618
+ */
18619
+ logRepositoryCounts(response) {
18620
+ if (response.github_repos) {
18621
+ const totalCount = Object.values(response.github_repos).reduce((sum, repos) => sum + repos.length, 0);
18622
+ console.log(`[OAuthRepositoryService] Retrieved ${totalCount} GitHub repos across ${Object.keys(response.github_repos).length} installations`);
18623
+ }
18624
+ if (response.gongfeng_repos) console.log(`[OAuthRepositoryService] Retrieved ${response.gongfeng_repos.length} Gongfeng repos`);
18625
+ if (response.cnb_repos) console.log(`[OAuthRepositoryService] Retrieved ${response.cnb_repos.length} CNB repos`);
18626
+ }
18627
+ };
18628
+ /**
18629
+ * OAuth Repository Service 单例实例
18630
+ */
18631
+ const oauthRepositoryService = new OAuthRepositoryService();
18632
+
18415
18633
  //#endregion
18416
18634
  //#region ../agent-provider/src/backend/backend-provider.ts
18417
18635
  /**
@@ -18420,27 +18638,29 @@ let AccountStatus = /* @__PURE__ */ function(AccountStatus) {
18420
18638
  * 封装与后端 API 的 HTTP 通信
18421
18639
  */
18422
18640
  /**
18423
- * 判断当前是否在 SSO 域名下
18424
- * SSO 域名格式: xxx.sso.copilot.tencent.com xxx.sso.codebuddy.cn
18641
+ * 判断当前账号是否是 SSO 账号
18642
+ * 通过 account.accountType === 'sso' 来判断,这种不行,因为未登录之前account 为空
18425
18643
  */
18426
18644
  const isSSODomain = () => {
18427
18645
  const { hostname } = window.location;
18428
18646
  return hostname.includes(".sso.copilot") || hostname.includes("sso.codebuddy.cn") || hostname.includes(".sso.copilot-staging") || hostname.includes(".staging-sso.codebuddy.cn");
18429
18647
  };
18430
18648
  /**
18431
- * 获取登录页面 URL
18432
- * - SSO 域名下需要跳转到对应的预发/生产域名
18433
- * - 非 SSO 域名直接使用当前域名
18649
+ * 根据路径获取完整 URL
18650
+ * - SSO 账号需要跳转到对应的预发/生产域名
18651
+ * - 非 SSO 账号直接使用当前域名
18652
+ * @param path 路径,如 '/login'、'/logout'、'/home' 等
18653
+ * @returns 完整的 URL 地址
18434
18654
  */
18435
- const getLoginUrl = () => {
18655
+ const getFullUrl = (path) => {
18436
18656
  const { hostname, protocol } = window.location;
18437
18657
  if (isSSODomain()) {
18438
18658
  const isCodebuddy = hostname.includes("codebuddy.cn");
18439
18659
  const isStaging = hostname.includes("staging");
18440
- if (isCodebuddy) return isStaging ? `${protocol}//staging.codebuddy.cn/login` : `${protocol}//www.codebuddy.cn/login`;
18441
- else return isStaging ? `${protocol}//staging-copilot.tencent.com/login` : `${protocol}//copilot.tencent.com/login`;
18660
+ if (isCodebuddy) return isStaging ? `${protocol}//staging.codebuddy.cn${path}` : `${protocol}//www.codebuddy.cn${path}`;
18661
+ else return isStaging ? `${protocol}//staging-copilot.tencent.com${path}` : `${protocol}//copilot.tencent.com${path}`;
18442
18662
  }
18443
- return `${window.location.origin}/login`;
18663
+ return `${window.location.origin}${path}`;
18444
18664
  };
18445
18665
  /** 获取当前域名的账号选择页面 URL */
18446
18666
  const getSelectAccountUrl = () => `${window.location.origin}/login/select`;
@@ -18528,7 +18748,7 @@ var BackendProvider = class {
18528
18748
  return account;
18529
18749
  }
18530
18750
  const redirectUrl = encodeURIComponent(window.location.href);
18531
- window.location.href = `${getSelectAccountUrl()}?platform=website&state=0&redirect_uri=${redirectUrl}`;
18751
+ window.location.href = `${getSelectAccountUrl()}?platform=agents&state=0&redirect_uri=${redirectUrl}`;
18532
18752
  accountService.setAccount(null);
18533
18753
  return null;
18534
18754
  } catch (error) {
@@ -18551,7 +18771,8 @@ var BackendProvider = class {
18551
18771
  activeStatus: connector.active_status,
18552
18772
  displayName: connector.display_name,
18553
18773
  oauthClientId: connector.oauth_client_id,
18554
- oauthRedirectUrl: connector.oauth_redirect_url
18774
+ oauthRedirectUrl: connector.oauth_redirect_url,
18775
+ oauthAppName: connector.oauth_app_name
18555
18776
  })) };
18556
18777
  }
18557
18778
  throw result;
@@ -18633,7 +18854,8 @@ var BackendProvider = class {
18633
18854
  connectStatus: connector.connect_status,
18634
18855
  displayName: connector.display_name,
18635
18856
  oauthClientId: connector.oauth_client_id,
18636
- oauthRedirectUrl: connector.oauth_redirect_url
18857
+ oauthRedirectUrl: connector.oauth_redirect_url,
18858
+ oauthAppName: connector.oauth_app_name
18637
18859
  })) };
18638
18860
  }
18639
18861
  throw result;
@@ -18890,7 +19112,7 @@ var BackendProvider = class {
18890
19112
  */
18891
19113
  async login() {
18892
19114
  const redirectUrl = encodeURIComponent(window.location.href);
18893
- window.location.href = `${getLoginUrl()}?platform=website&state=0&redirect_uri=${redirectUrl}`;
19115
+ window.location.href = `${getFullUrl("/login")}?platform=agents&state=0&redirect_uri=${redirectUrl}`;
18894
19116
  }
18895
19117
  /**
18896
19118
  * 登出账号
@@ -18953,6 +19175,52 @@ var BackendProvider = class {
18953
19175
  return null;
18954
19176
  }
18955
19177
  }
19178
+ /**
19179
+ * 刷新 Token
19180
+ * 通过调用 getAccount 刷新 cookie,适用于 Cloud 场景下页面切换回来时刷新登录态
19181
+ * @returns Promise<Account | null> 刷新后的账号信息
19182
+ */
19183
+ async refreshToken() {
19184
+ console.log("[BackendProvider] Refreshing token...");
19185
+ try {
19186
+ const account = await this.getAccount();
19187
+ console.log("[BackendProvider] Token refreshed, account:", account?.uid);
19188
+ return account;
19189
+ } catch (error) {
19190
+ console.error("[BackendProvider] refreshToken failed:", error);
19191
+ return null;
19192
+ }
19193
+ }
19194
+ /**
19195
+ * 获取仓库分支列表
19196
+ * API 端点: GET /console/as/connector/oauth/{name}/branches
19197
+ *
19198
+ * @param connector 连接器名称 ('github' | 'gongfeng' | 'cnb')
19199
+ * @param params 平台特定的查询参数
19200
+ * @param page 页码,从1开始,0表示不分页获取全部
19201
+ * @param perPage 每页数量,最大100
19202
+ * @returns Promise<OauthBranch[]> 分支列表
19203
+ */
19204
+ async getBranches(connector, params, page = 0, perPage = 100) {
19205
+ return oauthRepositoryService.getBranches(connector, params, page, perPage);
19206
+ }
19207
+ /**
19208
+ * 获取仓库列表
19209
+ * API 端点: GET /console/as/connector/oauth/{name}/repos
19210
+ *
19211
+ * Note: 由于工蜂原生支持的 Search 能力会匹配 path/name/description 部分,
19212
+ * 且不支持定制,不满足产品要求(只按 name 匹配),因此前端拉取全量数据后做筛选。
19213
+ *
19214
+ * @param connector 连接器名称 ('github' | 'gongfeng' | 'cnb')
19215
+ * @param page 页码,从1开始,0表示不分页获取全部
19216
+ * - GitHub 只支持全量数据,必须传 0
19217
+ * - 工蜂和 CNB 依据前端逻辑而定
19218
+ * @param perPage 每页数量,最大100
19219
+ * @returns Promise<ListReposResponse> 仓库列表响应
19220
+ */
19221
+ async getRepositories(connector, page = 0, perPage = 100) {
19222
+ return oauthRepositoryService.getRepositories(connector, page, perPage);
19223
+ }
18956
19224
  };
18957
19225
  /**
18958
19226
  * 创建 BackendProvider 实例
@@ -18992,6 +19260,7 @@ const BACKEND_REQUEST_TYPES = {
18992
19260
  GET_FILE: "backend:get-file",
18993
19261
  RELOAD_WINDOW: "backend:reload-window",
18994
19262
  CLOSE_AGENT_MANAGER: "backend:close-agent-manager",
19263
+ OPEN_EXTERNAL: "backend:open-external",
18995
19264
  BATCH_TOGGLE_PLUGINS: "backend:batch-toggle-plugins",
18996
19265
  GET_SUPPORT_SCENES: "backend:get-support-scenes"
18997
19266
  };
@@ -19287,6 +19556,20 @@ var IPCBackendProvider = class {
19287
19556
  }
19288
19557
  }
19289
19558
  /**
19559
+ * 在外部浏览器中打开链接
19560
+ * IDE 环境: 通过 IPC 通知 IDE 使用 vscode.env.openExternal 打开 URL
19561
+ * @param url 要打开的 URL
19562
+ */
19563
+ async openExternal(url) {
19564
+ this.log("Opening external URL via IPC:", url);
19565
+ try {
19566
+ await this.sendBackendRequest(BACKEND_REQUEST_TYPES.OPEN_EXTERNAL, { url });
19567
+ } catch (error) {
19568
+ this.log("Open external request failed:", error);
19569
+ throw error;
19570
+ }
19571
+ }
19572
+ /**
19290
19573
  * 批量切换插件状态
19291
19574
  * IDE 环境: 通过 IPC 调用 Extension Host 的 PluginService
19292
19575
  */