@tencent-ai/cloud-agent-sdk 0.2.12 → 0.2.13-next.bb9822d.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 +336 -57
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +413 -88
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +413 -88
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +336 -57
- package/dist/index.mjs.map +1 -1
- package/dist/tencent-ai-cloud-agent-sdk-0.2.13-next.bb9822d.20260204.tgz +0 -0
- package/package.json +4 -3
- package/dist/tencent-ai-cloud-agent-sdk-0.2.12.tgz +0 -0
package/dist/index.mjs
CHANGED
|
@@ -2372,7 +2372,7 @@ var CloudAgentConnection = class {
|
|
|
2372
2372
|
}
|
|
2373
2373
|
async createSession(params) {
|
|
2374
2374
|
return {
|
|
2375
|
-
...await this.client.
|
|
2375
|
+
...await this.client.createSession(this.cwd),
|
|
2376
2376
|
sessionId: this.agentId
|
|
2377
2377
|
};
|
|
2378
2378
|
}
|
|
@@ -5542,6 +5542,7 @@ var AccountService = class {
|
|
|
5542
5542
|
this.initPromise = null;
|
|
5543
5543
|
this.initResolve = null;
|
|
5544
5544
|
this.requestInterceptorId = null;
|
|
5545
|
+
this.crossTabBroadcaster = null;
|
|
5545
5546
|
this.initPromise = new Promise((resolve) => {
|
|
5546
5547
|
this.initResolve = resolve;
|
|
5547
5548
|
});
|
|
@@ -5590,15 +5591,34 @@ var AccountService = class {
|
|
|
5590
5591
|
this.initialized = true;
|
|
5591
5592
|
this.initResolve?.(account);
|
|
5592
5593
|
}
|
|
5593
|
-
if (!wasInitialized || prev?.uid !== account?.uid)
|
|
5594
|
+
if (!wasInitialized || prev?.uid !== account?.uid) {
|
|
5595
|
+
this.notifyListeners();
|
|
5596
|
+
if (account && this.crossTabBroadcaster) this.crossTabBroadcaster.broadcastLogin();
|
|
5597
|
+
}
|
|
5594
5598
|
}
|
|
5595
5599
|
/**
|
|
5596
5600
|
* 清除账号(登出)
|
|
5601
|
+
* 先广播登出消息,再清除本地账号
|
|
5597
5602
|
*/
|
|
5598
5603
|
clearAccount() {
|
|
5604
|
+
if (this.crossTabBroadcaster) this.crossTabBroadcaster.broadcastLogout();
|
|
5605
|
+
this.setAccount(null);
|
|
5606
|
+
}
|
|
5607
|
+
/**
|
|
5608
|
+
* 静默清除账号(不广播)
|
|
5609
|
+
* 用于收到其他标签页 logout 消息时,避免循环广播
|
|
5610
|
+
*/
|
|
5611
|
+
clearAccountSilently() {
|
|
5599
5612
|
this.setAccount(null);
|
|
5600
5613
|
}
|
|
5601
5614
|
/**
|
|
5615
|
+
* 设置跨标签页认证同步广播器
|
|
5616
|
+
* 应在应用初始化时由上层(如 agent-ui)调用
|
|
5617
|
+
*/
|
|
5618
|
+
setCrossTabBroadcaster(broadcaster) {
|
|
5619
|
+
this.crossTabBroadcaster = broadcaster;
|
|
5620
|
+
}
|
|
5621
|
+
/**
|
|
5602
5622
|
* 订阅账号变化
|
|
5603
5623
|
* @param callback 变化时的回调函数
|
|
5604
5624
|
* @returns 取消订阅函数
|
|
@@ -5663,6 +5683,11 @@ var AccountService = class {
|
|
|
5663
5683
|
* 导出单例实例
|
|
5664
5684
|
*/
|
|
5665
5685
|
const accountService = new AccountService();
|
|
5686
|
+
/**
|
|
5687
|
+
* 暴露给全局,供 Agent Manager 直接调用 setAccount 刷新 Widget 状态
|
|
5688
|
+
* 这是为了解决 IDE 环境中 IPC 事件无法直接触发 Widget 账号刷新的问题
|
|
5689
|
+
*/
|
|
5690
|
+
if (typeof window !== "undefined") window.__genieAccountService = accountService;
|
|
5666
5691
|
|
|
5667
5692
|
//#endregion
|
|
5668
5693
|
//#region ../agent-provider/src/common/utils/concurrency.ts
|
|
@@ -6252,15 +6277,9 @@ var CloudAgentProvider = class CloudAgentProvider {
|
|
|
6252
6277
|
const url = this.buildGetUrl("/console/as/conversations/", params);
|
|
6253
6278
|
const apiResponse = await httpService.get(url);
|
|
6254
6279
|
if (!apiResponse.data) throw new Error("No data in API response");
|
|
6255
|
-
const agents = apiResponse.data.conversations.map((a) => this.toAgentState(a));
|
|
6256
|
-
const pagination = apiResponse.data.pagination;
|
|
6257
|
-
console.log("[CloudAgentProvider] API response:", {
|
|
6258
|
-
agentsCount: agents.length,
|
|
6259
|
-
pagination
|
|
6260
|
-
});
|
|
6261
6280
|
return {
|
|
6262
|
-
agents,
|
|
6263
|
-
pagination
|
|
6281
|
+
agents: apiResponse.data.conversations.map((a) => this.toAgentState(a)),
|
|
6282
|
+
pagination: apiResponse.data.pagination
|
|
6264
6283
|
};
|
|
6265
6284
|
} catch (error) {
|
|
6266
6285
|
this.logger?.error("Failed to list agents:", error);
|
|
@@ -6270,13 +6289,19 @@ var CloudAgentProvider = class CloudAgentProvider {
|
|
|
6270
6289
|
/**
|
|
6271
6290
|
* Create a new conversation
|
|
6272
6291
|
* POST {endpoint}/console/as/conversations
|
|
6292
|
+
* @param params - Optional session params containing _meta with tags
|
|
6273
6293
|
*/
|
|
6274
|
-
async create() {
|
|
6294
|
+
async create(params) {
|
|
6275
6295
|
try {
|
|
6276
|
-
const
|
|
6296
|
+
const tagsObj = (params?._meta?.["codebuddy.ai"])?.tags;
|
|
6297
|
+
const tagsArray = tagsObj ? Object.entries(tagsObj).map(([key, value]) => `${key}:${value}`) : void 0;
|
|
6298
|
+
const createPayload = {
|
|
6277
6299
|
prompt: "",
|
|
6278
|
-
model: "deepseek-r1"
|
|
6279
|
-
|
|
6300
|
+
model: "deepseek-r1",
|
|
6301
|
+
...tagsArray && tagsArray.length > 0 ? { tags: tagsArray } : {}
|
|
6302
|
+
};
|
|
6303
|
+
console.log("[CloudAgentProvider] Creating conversation with payload:", createPayload);
|
|
6304
|
+
const apiResponse = await httpService.post("/console/as/conversations/", createPayload);
|
|
6280
6305
|
if (!apiResponse.data) throw new Error("No data in API response");
|
|
6281
6306
|
this.logger?.info(`Created conversation: ${apiResponse.data.id}`);
|
|
6282
6307
|
return apiResponse.data.id;
|
|
@@ -6668,7 +6693,8 @@ var CloudAgentProvider = class CloudAgentProvider {
|
|
|
6668
6693
|
type: "cloud",
|
|
6669
6694
|
status,
|
|
6670
6695
|
createdAt: data.createdAt ? new Date(data.createdAt) : void 0,
|
|
6671
|
-
capabilities: this.options.clientCapabilities
|
|
6696
|
+
capabilities: this.options.clientCapabilities,
|
|
6697
|
+
isUserDefinedTitle: data.isUserDefinedTitle
|
|
6672
6698
|
};
|
|
6673
6699
|
}
|
|
6674
6700
|
/**
|
|
@@ -6963,8 +6989,8 @@ var ActiveSessionImpl = class {
|
|
|
6963
6989
|
* await session.setMode('architect');
|
|
6964
6990
|
* ```
|
|
6965
6991
|
*/
|
|
6966
|
-
async setMode(modeId) {
|
|
6967
|
-
if (this._availableModes) {
|
|
6992
|
+
async setMode(modeId, skipAvailableChecker) {
|
|
6993
|
+
if (this._availableModes && !skipAvailableChecker) {
|
|
6968
6994
|
if (!this._availableModes.some((m) => m.id === modeId)) {
|
|
6969
6995
|
const availableIds = this._availableModes.map((m) => m.id).join(", ");
|
|
6970
6996
|
throw new Error(`Invalid modeId: "${modeId}". Available modes: ${availableIds}`);
|
|
@@ -7155,14 +7181,6 @@ var ActiveSessionImpl = class {
|
|
|
7155
7181
|
//#endregion
|
|
7156
7182
|
//#region ../agent-provider/src/common/client/session-manager.ts
|
|
7157
7183
|
/**
|
|
7158
|
-
* SessionManager - Manages session lifecycle and connections
|
|
7159
|
-
*
|
|
7160
|
-
* Provides the core implementation for session-centric API operations:
|
|
7161
|
-
* - list() - Lists sessions (mapped from agents)
|
|
7162
|
-
* - createSession() - Creates new session (auto-creates agent)
|
|
7163
|
-
* - loadSession() - Loads existing session (finds agent by sessionId)
|
|
7164
|
-
*/
|
|
7165
|
-
/**
|
|
7166
7184
|
* SessionManager - Session lifecycle management
|
|
7167
7185
|
*
|
|
7168
7186
|
* This class manages the relationship between sessions and agents.
|
|
@@ -7212,7 +7230,8 @@ var SessionManager = class {
|
|
|
7212
7230
|
createdAt: agent.createdAt,
|
|
7213
7231
|
lastActivityAt: agent.updatedAt,
|
|
7214
7232
|
cwd: agent.type === "local" ? agent.cwd : void 0,
|
|
7215
|
-
isPlayground: agent.isPlayground
|
|
7233
|
+
isPlayground: agent.isPlayground,
|
|
7234
|
+
isUserDefinedTitle: agent.isUserDefinedTitle
|
|
7216
7235
|
}));
|
|
7217
7236
|
console.log("[SessionManager] Returning sessions:", {
|
|
7218
7237
|
count: sessions.length,
|
|
@@ -7258,14 +7277,8 @@ var SessionManager = class {
|
|
|
7258
7277
|
connectionInfo
|
|
7259
7278
|
});
|
|
7260
7279
|
session.setModes(response.modes?.availableModes, response.modes?.currentModeId);
|
|
7261
|
-
|
|
7262
|
-
|
|
7263
|
-
id: m.modelId,
|
|
7264
|
-
name: m.name,
|
|
7265
|
-
description: m.description ?? void 0
|
|
7266
|
-
}));
|
|
7267
|
-
session.setModels(localModels, response.models?.currentModelId);
|
|
7268
|
-
}
|
|
7280
|
+
const availableModels = this.extractAvailableModels(response);
|
|
7281
|
+
if (availableModels) session.setModels(availableModels, response.models?.currentModelId);
|
|
7269
7282
|
this.logger?.info(`Session created: ${response.sessionId}`);
|
|
7270
7283
|
return session;
|
|
7271
7284
|
}
|
|
@@ -7301,17 +7314,31 @@ var SessionManager = class {
|
|
|
7301
7314
|
mcpServers: params.mcpServers
|
|
7302
7315
|
});
|
|
7303
7316
|
session.setModes(response.modes?.availableModes, response.modes?.currentModeId);
|
|
7304
|
-
|
|
7305
|
-
|
|
7306
|
-
id: m.modelId,
|
|
7307
|
-
name: m.name,
|
|
7308
|
-
description: m.description ?? void 0
|
|
7309
|
-
}));
|
|
7310
|
-
session.setModels(localModels, response.models?.currentModelId);
|
|
7311
|
-
}
|
|
7317
|
+
const availableModels = this.extractAvailableModels(response);
|
|
7318
|
+
if (availableModels) session.setModels(availableModels, response.models?.currentModelId);
|
|
7312
7319
|
this.logger?.info(`Session loaded: ${params.sessionId}`);
|
|
7313
7320
|
return session;
|
|
7314
7321
|
}
|
|
7322
|
+
/**
|
|
7323
|
+
* 从 ACP response 中提取可用模型列表
|
|
7324
|
+
*
|
|
7325
|
+
* 优先级:
|
|
7326
|
+
* 1. response.models._meta?.['codebuddy.ai']?.availableModels - 包含完整的模型信息(字段名为 'id')
|
|
7327
|
+
* 2. response.models?.availableModels - 只包含基本信息(字段名为 'modelId')
|
|
7328
|
+
* 3. undefined - 都没有时返回 undefined
|
|
7329
|
+
*
|
|
7330
|
+
* @param response - ACP 响应对象
|
|
7331
|
+
* @returns ModelInfo[] | undefined
|
|
7332
|
+
*/
|
|
7333
|
+
extractAvailableModels(response) {
|
|
7334
|
+
const metaModels = (response.models?._meta?.["codebuddy.ai"])?.availableModels;
|
|
7335
|
+
if (metaModels && Array.isArray(metaModels) && metaModels.length > 0) return metaModels;
|
|
7336
|
+
const availableModels = response.models?.availableModels;
|
|
7337
|
+
if (availableModels && Array.isArray(availableModels) && availableModels.length > 0) return availableModels.map((model) => ({
|
|
7338
|
+
...model,
|
|
7339
|
+
...model._meta?.["codebuddy.ai"] || {}
|
|
7340
|
+
}));
|
|
7341
|
+
}
|
|
7315
7342
|
};
|
|
7316
7343
|
|
|
7317
7344
|
//#endregion
|
|
@@ -7584,6 +7611,28 @@ var AgentClient = class {
|
|
|
7584
7611
|
};
|
|
7585
7612
|
}
|
|
7586
7613
|
},
|
|
7614
|
+
getSubagentList: async (params) => {
|
|
7615
|
+
try {
|
|
7616
|
+
if (this.provider && this.provider.getSubagentList) {
|
|
7617
|
+
const result = await this.provider.getSubagentList(params);
|
|
7618
|
+
this.logger?.info("Subagent list retrieved", {
|
|
7619
|
+
resultCount: result.results.length,
|
|
7620
|
+
hasError: !!result.error
|
|
7621
|
+
});
|
|
7622
|
+
return result;
|
|
7623
|
+
}
|
|
7624
|
+
return {
|
|
7625
|
+
results: [],
|
|
7626
|
+
error: "Provider does not support getSubagentList"
|
|
7627
|
+
};
|
|
7628
|
+
} catch (error) {
|
|
7629
|
+
this.logger?.error("Failed to get subagent list", error);
|
|
7630
|
+
return {
|
|
7631
|
+
results: [],
|
|
7632
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
7633
|
+
};
|
|
7634
|
+
}
|
|
7635
|
+
},
|
|
7587
7636
|
batchTogglePlugins: async (request) => {
|
|
7588
7637
|
try {
|
|
7589
7638
|
if (this.provider && this.provider.batchTogglePlugins) {
|
|
@@ -7628,10 +7677,10 @@ var AgentClient = class {
|
|
|
7628
7677
|
return [];
|
|
7629
7678
|
}
|
|
7630
7679
|
},
|
|
7631
|
-
installPlugins: async (pluginNames, marketplaceName, installScope) => {
|
|
7680
|
+
installPlugins: async (pluginNames, marketplaceName, installScope, marketplaceSource) => {
|
|
7632
7681
|
try {
|
|
7633
7682
|
if (this.provider && "installPlugins" in this.provider && typeof this.provider.installPlugins === "function") {
|
|
7634
|
-
const result = await this.provider.installPlugins(pluginNames, marketplaceName, installScope);
|
|
7683
|
+
const result = await this.provider.installPlugins(pluginNames, marketplaceName, installScope, marketplaceSource);
|
|
7635
7684
|
this.logger?.info("Install plugins", {
|
|
7636
7685
|
pluginNames,
|
|
7637
7686
|
marketplaceName,
|
|
@@ -7666,6 +7715,23 @@ var AgentClient = class {
|
|
|
7666
7715
|
return [];
|
|
7667
7716
|
}
|
|
7668
7717
|
},
|
|
7718
|
+
getAvailableCommands: async (sessionId) => {
|
|
7719
|
+
try {
|
|
7720
|
+
if (this.provider && "getAvailableCommands" in this.provider && typeof this.provider.getAvailableCommands === "function") {
|
|
7721
|
+
const result = await this.provider.getAvailableCommands(sessionId);
|
|
7722
|
+
this.logger?.info("Got available commands from provider", {
|
|
7723
|
+
sessionId: sessionId ?? "(default)",
|
|
7724
|
+
count: result?.length ?? 0
|
|
7725
|
+
});
|
|
7726
|
+
return result;
|
|
7727
|
+
}
|
|
7728
|
+
this.logger?.warn("Provider does not support getAvailableCommands", { sessionId });
|
|
7729
|
+
return [];
|
|
7730
|
+
} catch (error) {
|
|
7731
|
+
this.logger?.error("Failed to get available commands", error);
|
|
7732
|
+
return [];
|
|
7733
|
+
}
|
|
7734
|
+
},
|
|
7669
7735
|
models: this.createModelsResource()
|
|
7670
7736
|
};
|
|
7671
7737
|
}
|
|
@@ -7732,6 +7798,154 @@ let AccountStatus = /* @__PURE__ */ function(AccountStatus) {
|
|
|
7732
7798
|
return AccountStatus;
|
|
7733
7799
|
}({});
|
|
7734
7800
|
|
|
7801
|
+
//#endregion
|
|
7802
|
+
//#region ../agent-provider/src/backend/service/oauth-repository-service.ts
|
|
7803
|
+
/**
|
|
7804
|
+
* OAuth Repository Service
|
|
7805
|
+
*
|
|
7806
|
+
* 封装 OAuth 连接器相关的仓库和分支操作
|
|
7807
|
+
*/
|
|
7808
|
+
/**
|
|
7809
|
+
* OAuth Repository Service
|
|
7810
|
+
*
|
|
7811
|
+
* 提供仓库和分支的查询操作
|
|
7812
|
+
*/
|
|
7813
|
+
var OAuthRepositoryService = class {
|
|
7814
|
+
/**
|
|
7815
|
+
* 获取仓库分支列表
|
|
7816
|
+
* API 端点: GET /console/as/connector/oauth/{name}/branches
|
|
7817
|
+
*
|
|
7818
|
+
* @param connector 连接器名称 ('github' | 'gongfeng' | 'cnb')
|
|
7819
|
+
* @param params 平台特定的查询参数
|
|
7820
|
+
* @param page 页码,从1开始,0表示不分页获取全部
|
|
7821
|
+
* @param perPage 每页数量,最大100
|
|
7822
|
+
* @returns Promise<OauthBranch[]> 分支列表
|
|
7823
|
+
*
|
|
7824
|
+
* @example
|
|
7825
|
+
* ```typescript
|
|
7826
|
+
* // GitHub
|
|
7827
|
+
* const branches = await service.getBranches('github', {
|
|
7828
|
+
* owner: 'CodeBuddy-Official-Account',
|
|
7829
|
+
* repo: 'CodeBuddyIDE'
|
|
7830
|
+
* });
|
|
7831
|
+
*
|
|
7832
|
+
* // Gongfeng
|
|
7833
|
+
* const branches = await service.getBranches('gongfeng', {
|
|
7834
|
+
* project_id: '1611499'
|
|
7835
|
+
* });
|
|
7836
|
+
*
|
|
7837
|
+
* // CNB
|
|
7838
|
+
* const branches = await service.getBranches('cnb', {
|
|
7839
|
+
* repo: 'genie/genie-ide'
|
|
7840
|
+
* });
|
|
7841
|
+
* ```
|
|
7842
|
+
*/
|
|
7843
|
+
async getBranches(connector, params, page = 0, perPage = 100) {
|
|
7844
|
+
try {
|
|
7845
|
+
const url = `/console/as/connector/oauth/${connector}/branches?${this.buildBranchQueryParams(connector, params, page, perPage).toString()}`;
|
|
7846
|
+
console.log(`[OAuthRepositoryService] GET ${url}`);
|
|
7847
|
+
const apiResponse = await httpService.get(url);
|
|
7848
|
+
if (!apiResponse.data) {
|
|
7849
|
+
console.warn(`[OAuthRepositoryService] No data in branches response for ${connector}`);
|
|
7850
|
+
return [];
|
|
7851
|
+
}
|
|
7852
|
+
const branches = apiResponse.data.branches || [];
|
|
7853
|
+
console.log(`[OAuthRepositoryService] Retrieved ${branches.length} branches from ${connector}`);
|
|
7854
|
+
return branches;
|
|
7855
|
+
} catch (error) {
|
|
7856
|
+
console.error(`[OAuthRepositoryService] Failed to get branches from ${connector}:`, error);
|
|
7857
|
+
throw error;
|
|
7858
|
+
}
|
|
7859
|
+
}
|
|
7860
|
+
/**
|
|
7861
|
+
* 获取仓库列表
|
|
7862
|
+
* API 端点: GET /console/as/connector/oauth/{name}/repos
|
|
7863
|
+
*
|
|
7864
|
+
* Note: 由于工蜂原生支持的 Search 能力会匹配 path/name/description 部分,
|
|
7865
|
+
* 且不支持定制,不满足产品要求(只按 name 匹配),因此前端拉取全量数据后做筛选。
|
|
7866
|
+
*
|
|
7867
|
+
* @param connector 连接器名称 ('github' | 'gongfeng' | 'cnb')
|
|
7868
|
+
* @param page 页码,从1开始,0表示不分页获取全部
|
|
7869
|
+
* - GitHub 只支持全量数据,必须传 0
|
|
7870
|
+
* - 工蜂和 CNB 依据前端逻辑而定
|
|
7871
|
+
* @param perPage 每页数量,最大100
|
|
7872
|
+
* @returns Promise<ListReposResponse> 仓库列表响应
|
|
7873
|
+
*
|
|
7874
|
+
* @example
|
|
7875
|
+
* ```typescript
|
|
7876
|
+
* // GitHub - 必须传 page=0 获取全量数据
|
|
7877
|
+
* const response = await service.getRepositories('github', 0, 100);
|
|
7878
|
+
* // response.github_repos 是 map: installation_id => repo[]
|
|
7879
|
+
*
|
|
7880
|
+
* // Gongfeng
|
|
7881
|
+
* const response = await service.getRepositories('gongfeng', 0, 100);
|
|
7882
|
+
* // response.gongfeng_repos 是数组
|
|
7883
|
+
*
|
|
7884
|
+
* // CNB
|
|
7885
|
+
* const response = await service.getRepositories('cnb', 0, 100);
|
|
7886
|
+
* // response.cnb_repos 是数组
|
|
7887
|
+
* ```
|
|
7888
|
+
*/
|
|
7889
|
+
async getRepositories(connector, page = 0, perPage = 100) {
|
|
7890
|
+
try {
|
|
7891
|
+
const queryParams = new URLSearchParams();
|
|
7892
|
+
queryParams.append("page", String(page));
|
|
7893
|
+
queryParams.append("per_page", String(Math.min(perPage, 100)));
|
|
7894
|
+
const url = `/console/as/connector/oauth/${connector}/repos?${queryParams.toString()}`;
|
|
7895
|
+
console.log(`[OAuthRepositoryService] GET ${url}`);
|
|
7896
|
+
const apiResponse = await httpService.get(url);
|
|
7897
|
+
if (!apiResponse.data) {
|
|
7898
|
+
console.warn(`[OAuthRepositoryService] No data in repos response for ${connector}`);
|
|
7899
|
+
return {};
|
|
7900
|
+
}
|
|
7901
|
+
const response = apiResponse.data;
|
|
7902
|
+
this.logRepositoryCounts(response);
|
|
7903
|
+
return response;
|
|
7904
|
+
} catch (error) {
|
|
7905
|
+
console.error(`[OAuthRepositoryService] Failed to get repos from ${connector}:`, error);
|
|
7906
|
+
throw error;
|
|
7907
|
+
}
|
|
7908
|
+
}
|
|
7909
|
+
/**
|
|
7910
|
+
* 构建分支查询参数
|
|
7911
|
+
*/
|
|
7912
|
+
buildBranchQueryParams(connector, params, page, perPage) {
|
|
7913
|
+
const queryParams = new URLSearchParams();
|
|
7914
|
+
queryParams.append("page", String(page));
|
|
7915
|
+
queryParams.append("per_page", String(Math.min(perPage, 100)));
|
|
7916
|
+
if (connector === "github") {
|
|
7917
|
+
const githubParams = params;
|
|
7918
|
+
if (!githubParams.owner || !githubParams.repo) throw new Error("GitHub requires owner and repo parameters");
|
|
7919
|
+
queryParams.append("owner", githubParams.owner);
|
|
7920
|
+
queryParams.append("repo", githubParams.repo);
|
|
7921
|
+
} else if (connector === "gongfeng") {
|
|
7922
|
+
const gongfengParams = params;
|
|
7923
|
+
if (!gongfengParams.project_id) throw new Error("Gongfeng requires project_id parameter");
|
|
7924
|
+
queryParams.append("project_id", gongfengParams.project_id);
|
|
7925
|
+
} else if (connector === "cnb") {
|
|
7926
|
+
const cnbParams = params;
|
|
7927
|
+
if (!cnbParams.repo) throw new Error("CNB requires repo parameter");
|
|
7928
|
+
queryParams.append("repo", cnbParams.repo);
|
|
7929
|
+
} else throw new Error(`Unknown connector: ${connector}`);
|
|
7930
|
+
return queryParams;
|
|
7931
|
+
}
|
|
7932
|
+
/**
|
|
7933
|
+
* 记录仓库数量日志
|
|
7934
|
+
*/
|
|
7935
|
+
logRepositoryCounts(response) {
|
|
7936
|
+
if (response.github_repos) {
|
|
7937
|
+
const totalCount = Object.values(response.github_repos).reduce((sum, repos) => sum + repos.length, 0);
|
|
7938
|
+
console.log(`[OAuthRepositoryService] Retrieved ${totalCount} GitHub repos across ${Object.keys(response.github_repos).length} installations`);
|
|
7939
|
+
}
|
|
7940
|
+
if (response.gongfeng_repos) console.log(`[OAuthRepositoryService] Retrieved ${response.gongfeng_repos.length} Gongfeng repos`);
|
|
7941
|
+
if (response.cnb_repos) console.log(`[OAuthRepositoryService] Retrieved ${response.cnb_repos.length} CNB repos`);
|
|
7942
|
+
}
|
|
7943
|
+
};
|
|
7944
|
+
/**
|
|
7945
|
+
* OAuth Repository Service 单例实例
|
|
7946
|
+
*/
|
|
7947
|
+
const oauthRepositoryService = new OAuthRepositoryService();
|
|
7948
|
+
|
|
7735
7949
|
//#endregion
|
|
7736
7950
|
//#region ../agent-provider/src/backend/backend-provider.ts
|
|
7737
7951
|
/**
|
|
@@ -7740,27 +7954,29 @@ let AccountStatus = /* @__PURE__ */ function(AccountStatus) {
|
|
|
7740
7954
|
* 封装与后端 API 的 HTTP 通信
|
|
7741
7955
|
*/
|
|
7742
7956
|
/**
|
|
7743
|
-
*
|
|
7744
|
-
*
|
|
7957
|
+
* 判断当前账号是否是 SSO 账号
|
|
7958
|
+
* 通过 account.accountType === 'sso' 来判断,这种不行,因为未登录之前account 为空
|
|
7745
7959
|
*/
|
|
7746
7960
|
const isSSODomain = () => {
|
|
7747
7961
|
const { hostname } = window.location;
|
|
7748
7962
|
return hostname.includes(".sso.copilot") || hostname.includes("sso.codebuddy.cn") || hostname.includes(".sso.copilot-staging") || hostname.includes(".staging-sso.codebuddy.cn");
|
|
7749
7963
|
};
|
|
7750
7964
|
/**
|
|
7751
|
-
*
|
|
7752
|
-
* - SSO
|
|
7753
|
-
* - 非 SSO
|
|
7965
|
+
* 根据路径获取完整 URL
|
|
7966
|
+
* - SSO 账号需要跳转到对应的预发/生产域名
|
|
7967
|
+
* - 非 SSO 账号直接使用当前域名
|
|
7968
|
+
* @param path 路径,如 '/login'、'/logout'、'/home' 等
|
|
7969
|
+
* @returns 完整的 URL 地址
|
|
7754
7970
|
*/
|
|
7755
|
-
const
|
|
7971
|
+
const getFullUrl = (path) => {
|
|
7756
7972
|
const { hostname, protocol } = window.location;
|
|
7757
7973
|
if (isSSODomain()) {
|
|
7758
7974
|
const isCodebuddy = hostname.includes("codebuddy.cn");
|
|
7759
7975
|
const isStaging = hostname.includes("staging");
|
|
7760
|
-
if (isCodebuddy) return isStaging ? `${protocol}//staging.codebuddy.cn
|
|
7761
|
-
else return isStaging ? `${protocol}//staging-copilot.tencent.com
|
|
7976
|
+
if (isCodebuddy) return isStaging ? `${protocol}//staging.codebuddy.cn${path}` : `${protocol}//www.codebuddy.cn${path}`;
|
|
7977
|
+
else return isStaging ? `${protocol}//staging-copilot.tencent.com${path}` : `${protocol}//copilot.tencent.com${path}`;
|
|
7762
7978
|
}
|
|
7763
|
-
return `${window.location.origin}
|
|
7979
|
+
return `${window.location.origin}${path}`;
|
|
7764
7980
|
};
|
|
7765
7981
|
/** 获取当前域名的账号选择页面 URL */
|
|
7766
7982
|
const getSelectAccountUrl = () => `${window.location.origin}/login/select`;
|
|
@@ -7848,7 +8064,7 @@ var BackendProvider = class {
|
|
|
7848
8064
|
return account;
|
|
7849
8065
|
}
|
|
7850
8066
|
const redirectUrl = encodeURIComponent(window.location.href);
|
|
7851
|
-
window.location.href = `${getSelectAccountUrl()}?platform=
|
|
8067
|
+
window.location.href = `${getSelectAccountUrl()}?platform=agents&state=0&redirect_uri=${redirectUrl}`;
|
|
7852
8068
|
accountService.setAccount(null);
|
|
7853
8069
|
return null;
|
|
7854
8070
|
} catch (error) {
|
|
@@ -7871,7 +8087,8 @@ var BackendProvider = class {
|
|
|
7871
8087
|
activeStatus: connector.active_status,
|
|
7872
8088
|
displayName: connector.display_name,
|
|
7873
8089
|
oauthClientId: connector.oauth_client_id,
|
|
7874
|
-
oauthRedirectUrl: connector.oauth_redirect_url
|
|
8090
|
+
oauthRedirectUrl: connector.oauth_redirect_url,
|
|
8091
|
+
oauthAppName: connector.oauth_app_name
|
|
7875
8092
|
})) };
|
|
7876
8093
|
}
|
|
7877
8094
|
throw result;
|
|
@@ -7953,7 +8170,8 @@ var BackendProvider = class {
|
|
|
7953
8170
|
connectStatus: connector.connect_status,
|
|
7954
8171
|
displayName: connector.display_name,
|
|
7955
8172
|
oauthClientId: connector.oauth_client_id,
|
|
7956
|
-
oauthRedirectUrl: connector.oauth_redirect_url
|
|
8173
|
+
oauthRedirectUrl: connector.oauth_redirect_url,
|
|
8174
|
+
oauthAppName: connector.oauth_app_name
|
|
7957
8175
|
})) };
|
|
7958
8176
|
}
|
|
7959
8177
|
throw result;
|
|
@@ -8210,7 +8428,7 @@ var BackendProvider = class {
|
|
|
8210
8428
|
*/
|
|
8211
8429
|
async login() {
|
|
8212
8430
|
const redirectUrl = encodeURIComponent(window.location.href);
|
|
8213
|
-
window.location.href = `${
|
|
8431
|
+
window.location.href = `${getFullUrl("/login")}?platform=agents&state=0&redirect_uri=${redirectUrl}`;
|
|
8214
8432
|
}
|
|
8215
8433
|
/**
|
|
8216
8434
|
* 登出账号
|
|
@@ -8273,6 +8491,52 @@ var BackendProvider = class {
|
|
|
8273
8491
|
return null;
|
|
8274
8492
|
}
|
|
8275
8493
|
}
|
|
8494
|
+
/**
|
|
8495
|
+
* 刷新 Token
|
|
8496
|
+
* 通过调用 getAccount 刷新 cookie,适用于 Cloud 场景下页面切换回来时刷新登录态
|
|
8497
|
+
* @returns Promise<Account | null> 刷新后的账号信息
|
|
8498
|
+
*/
|
|
8499
|
+
async refreshToken() {
|
|
8500
|
+
console.log("[BackendProvider] Refreshing token...");
|
|
8501
|
+
try {
|
|
8502
|
+
const account = await this.getAccount();
|
|
8503
|
+
console.log("[BackendProvider] Token refreshed, account:", account?.uid);
|
|
8504
|
+
return account;
|
|
8505
|
+
} catch (error) {
|
|
8506
|
+
console.error("[BackendProvider] refreshToken failed:", error);
|
|
8507
|
+
return null;
|
|
8508
|
+
}
|
|
8509
|
+
}
|
|
8510
|
+
/**
|
|
8511
|
+
* 获取仓库分支列表
|
|
8512
|
+
* API 端点: GET /console/as/connector/oauth/{name}/branches
|
|
8513
|
+
*
|
|
8514
|
+
* @param connector 连接器名称 ('github' | 'gongfeng' | 'cnb')
|
|
8515
|
+
* @param params 平台特定的查询参数
|
|
8516
|
+
* @param page 页码,从1开始,0表示不分页获取全部
|
|
8517
|
+
* @param perPage 每页数量,最大100
|
|
8518
|
+
* @returns Promise<OauthBranch[]> 分支列表
|
|
8519
|
+
*/
|
|
8520
|
+
async getBranches(connector, params, page = 0, perPage = 100) {
|
|
8521
|
+
return oauthRepositoryService.getBranches(connector, params, page, perPage);
|
|
8522
|
+
}
|
|
8523
|
+
/**
|
|
8524
|
+
* 获取仓库列表
|
|
8525
|
+
* API 端点: GET /console/as/connector/oauth/{name}/repos
|
|
8526
|
+
*
|
|
8527
|
+
* Note: 由于工蜂原生支持的 Search 能力会匹配 path/name/description 部分,
|
|
8528
|
+
* 且不支持定制,不满足产品要求(只按 name 匹配),因此前端拉取全量数据后做筛选。
|
|
8529
|
+
*
|
|
8530
|
+
* @param connector 连接器名称 ('github' | 'gongfeng' | 'cnb')
|
|
8531
|
+
* @param page 页码,从1开始,0表示不分页获取全部
|
|
8532
|
+
* - GitHub 只支持全量数据,必须传 0
|
|
8533
|
+
* - 工蜂和 CNB 依据前端逻辑而定
|
|
8534
|
+
* @param perPage 每页数量,最大100
|
|
8535
|
+
* @returns Promise<ListReposResponse> 仓库列表响应
|
|
8536
|
+
*/
|
|
8537
|
+
async getRepositories(connector, page = 0, perPage = 100) {
|
|
8538
|
+
return oauthRepositoryService.getRepositories(connector, page, perPage);
|
|
8539
|
+
}
|
|
8276
8540
|
};
|
|
8277
8541
|
/**
|
|
8278
8542
|
* 创建 BackendProvider 实例
|
|
@@ -8312,6 +8576,7 @@ const BACKEND_REQUEST_TYPES = {
|
|
|
8312
8576
|
GET_FILE: "backend:get-file",
|
|
8313
8577
|
RELOAD_WINDOW: "backend:reload-window",
|
|
8314
8578
|
CLOSE_AGENT_MANAGER: "backend:close-agent-manager",
|
|
8579
|
+
OPEN_EXTERNAL: "backend:open-external",
|
|
8315
8580
|
BATCH_TOGGLE_PLUGINS: "backend:batch-toggle-plugins",
|
|
8316
8581
|
GET_SUPPORT_SCENES: "backend:get-support-scenes"
|
|
8317
8582
|
};
|
|
@@ -8607,6 +8872,20 @@ var IPCBackendProvider = class {
|
|
|
8607
8872
|
}
|
|
8608
8873
|
}
|
|
8609
8874
|
/**
|
|
8875
|
+
* 在外部浏览器中打开链接
|
|
8876
|
+
* IDE 环境: 通过 IPC 通知 IDE 使用 vscode.env.openExternal 打开 URL
|
|
8877
|
+
* @param url 要打开的 URL
|
|
8878
|
+
*/
|
|
8879
|
+
async openExternal(url) {
|
|
8880
|
+
this.log("Opening external URL via IPC:", url);
|
|
8881
|
+
try {
|
|
8882
|
+
await this.sendBackendRequest(BACKEND_REQUEST_TYPES.OPEN_EXTERNAL, { url });
|
|
8883
|
+
} catch (error) {
|
|
8884
|
+
this.log("Open external request failed:", error);
|
|
8885
|
+
throw error;
|
|
8886
|
+
}
|
|
8887
|
+
}
|
|
8888
|
+
/**
|
|
8610
8889
|
* 批量切换插件状态
|
|
8611
8890
|
* IDE 环境: 通过 IPC 调用 Extension Host 的 PluginService
|
|
8612
8891
|
*/
|