@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.cjs
CHANGED
|
@@ -2411,7 +2411,7 @@ var CloudAgentConnection = class {
|
|
|
2411
2411
|
}
|
|
2412
2412
|
async createSession(params) {
|
|
2413
2413
|
return {
|
|
2414
|
-
...await this.client.
|
|
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)
|
|
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
|
|
@@ -16922,15 +16947,9 @@ var CloudAgentProvider = class CloudAgentProvider {
|
|
|
16922
16947
|
const url = this.buildGetUrl("/console/as/conversations/", params);
|
|
16923
16948
|
const apiResponse = await httpService.get(url);
|
|
16924
16949
|
if (!apiResponse.data) throw new Error("No data in API response");
|
|
16925
|
-
const agents = apiResponse.data.conversations.map((a) => this.toAgentState(a));
|
|
16926
|
-
const pagination = apiResponse.data.pagination;
|
|
16927
|
-
console.log("[CloudAgentProvider] API response:", {
|
|
16928
|
-
agentsCount: agents.length,
|
|
16929
|
-
pagination
|
|
16930
|
-
});
|
|
16931
16950
|
return {
|
|
16932
|
-
agents,
|
|
16933
|
-
pagination
|
|
16951
|
+
agents: apiResponse.data.conversations.map((a) => this.toAgentState(a)),
|
|
16952
|
+
pagination: apiResponse.data.pagination
|
|
16934
16953
|
};
|
|
16935
16954
|
} catch (error) {
|
|
16936
16955
|
this.logger?.error("Failed to list agents:", error);
|
|
@@ -16940,13 +16959,19 @@ var CloudAgentProvider = class CloudAgentProvider {
|
|
|
16940
16959
|
/**
|
|
16941
16960
|
* Create a new conversation
|
|
16942
16961
|
* POST {endpoint}/console/as/conversations
|
|
16962
|
+
* @param params - Optional session params containing _meta with tags
|
|
16943
16963
|
*/
|
|
16944
|
-
async create() {
|
|
16964
|
+
async create(params) {
|
|
16945
16965
|
try {
|
|
16946
|
-
const
|
|
16966
|
+
const tagsObj = (params?._meta?.["codebuddy.ai"])?.tags;
|
|
16967
|
+
const tagsArray = tagsObj ? Object.entries(tagsObj).map(([key, value]) => `${key}:${value}`) : void 0;
|
|
16968
|
+
const createPayload = {
|
|
16947
16969
|
prompt: "",
|
|
16948
|
-
model: "deepseek-r1"
|
|
16949
|
-
|
|
16970
|
+
model: "deepseek-r1",
|
|
16971
|
+
...tagsArray && tagsArray.length > 0 ? { tags: tagsArray } : {}
|
|
16972
|
+
};
|
|
16973
|
+
console.log("[CloudAgentProvider] Creating conversation with payload:", createPayload);
|
|
16974
|
+
const apiResponse = await httpService.post("/console/as/conversations/", createPayload);
|
|
16950
16975
|
if (!apiResponse.data) throw new Error("No data in API response");
|
|
16951
16976
|
this.logger?.info(`Created conversation: ${apiResponse.data.id}`);
|
|
16952
16977
|
return apiResponse.data.id;
|
|
@@ -17338,7 +17363,8 @@ var CloudAgentProvider = class CloudAgentProvider {
|
|
|
17338
17363
|
type: "cloud",
|
|
17339
17364
|
status,
|
|
17340
17365
|
createdAt: data.createdAt ? new Date(data.createdAt) : void 0,
|
|
17341
|
-
capabilities: this.options.clientCapabilities
|
|
17366
|
+
capabilities: this.options.clientCapabilities,
|
|
17367
|
+
isUserDefinedTitle: data.isUserDefinedTitle
|
|
17342
17368
|
};
|
|
17343
17369
|
}
|
|
17344
17370
|
/**
|
|
@@ -17643,8 +17669,8 @@ var ActiveSessionImpl = class {
|
|
|
17643
17669
|
* await session.setMode('architect');
|
|
17644
17670
|
* ```
|
|
17645
17671
|
*/
|
|
17646
|
-
async setMode(modeId) {
|
|
17647
|
-
if (this._availableModes) {
|
|
17672
|
+
async setMode(modeId, skipAvailableChecker) {
|
|
17673
|
+
if (this._availableModes && !skipAvailableChecker) {
|
|
17648
17674
|
if (!this._availableModes.some((m) => m.id === modeId)) {
|
|
17649
17675
|
const availableIds = this._availableModes.map((m) => m.id).join(", ");
|
|
17650
17676
|
throw new Error(`Invalid modeId: "${modeId}". Available modes: ${availableIds}`);
|
|
@@ -17835,14 +17861,6 @@ var ActiveSessionImpl = class {
|
|
|
17835
17861
|
//#endregion
|
|
17836
17862
|
//#region ../agent-provider/src/common/client/session-manager.ts
|
|
17837
17863
|
/**
|
|
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
17864
|
* SessionManager - Session lifecycle management
|
|
17847
17865
|
*
|
|
17848
17866
|
* This class manages the relationship between sessions and agents.
|
|
@@ -17892,7 +17910,8 @@ var SessionManager = class {
|
|
|
17892
17910
|
createdAt: agent.createdAt,
|
|
17893
17911
|
lastActivityAt: agent.updatedAt,
|
|
17894
17912
|
cwd: agent.type === "local" ? agent.cwd : void 0,
|
|
17895
|
-
isPlayground: agent.isPlayground
|
|
17913
|
+
isPlayground: agent.isPlayground,
|
|
17914
|
+
isUserDefinedTitle: agent.isUserDefinedTitle
|
|
17896
17915
|
}));
|
|
17897
17916
|
console.log("[SessionManager] Returning sessions:", {
|
|
17898
17917
|
count: sessions.length,
|
|
@@ -17938,14 +17957,8 @@ var SessionManager = class {
|
|
|
17938
17957
|
connectionInfo
|
|
17939
17958
|
});
|
|
17940
17959
|
session.setModes(response.modes?.availableModes, response.modes?.currentModeId);
|
|
17941
|
-
|
|
17942
|
-
|
|
17943
|
-
id: m.modelId,
|
|
17944
|
-
name: m.name,
|
|
17945
|
-
description: m.description ?? void 0
|
|
17946
|
-
}));
|
|
17947
|
-
session.setModels(localModels, response.models?.currentModelId);
|
|
17948
|
-
}
|
|
17960
|
+
const availableModels = this.extractAvailableModels(response);
|
|
17961
|
+
if (availableModels) session.setModels(availableModels, response.models?.currentModelId);
|
|
17949
17962
|
this.logger?.info(`Session created: ${response.sessionId}`);
|
|
17950
17963
|
return session;
|
|
17951
17964
|
}
|
|
@@ -17981,17 +17994,31 @@ var SessionManager = class {
|
|
|
17981
17994
|
mcpServers: params.mcpServers
|
|
17982
17995
|
});
|
|
17983
17996
|
session.setModes(response.modes?.availableModes, response.modes?.currentModeId);
|
|
17984
|
-
|
|
17985
|
-
|
|
17986
|
-
id: m.modelId,
|
|
17987
|
-
name: m.name,
|
|
17988
|
-
description: m.description ?? void 0
|
|
17989
|
-
}));
|
|
17990
|
-
session.setModels(localModels, response.models?.currentModelId);
|
|
17991
|
-
}
|
|
17997
|
+
const availableModels = this.extractAvailableModels(response);
|
|
17998
|
+
if (availableModels) session.setModels(availableModels, response.models?.currentModelId);
|
|
17992
17999
|
this.logger?.info(`Session loaded: ${params.sessionId}`);
|
|
17993
18000
|
return session;
|
|
17994
18001
|
}
|
|
18002
|
+
/**
|
|
18003
|
+
* 从 ACP response 中提取可用模型列表
|
|
18004
|
+
*
|
|
18005
|
+
* 优先级:
|
|
18006
|
+
* 1. response.models._meta?.['codebuddy.ai']?.availableModels - 包含完整的模型信息(字段名为 'id')
|
|
18007
|
+
* 2. response.models?.availableModels - 只包含基本信息(字段名为 'modelId')
|
|
18008
|
+
* 3. undefined - 都没有时返回 undefined
|
|
18009
|
+
*
|
|
18010
|
+
* @param response - ACP 响应对象
|
|
18011
|
+
* @returns ModelInfo[] | undefined
|
|
18012
|
+
*/
|
|
18013
|
+
extractAvailableModels(response) {
|
|
18014
|
+
const metaModels = (response.models?._meta?.["codebuddy.ai"])?.availableModels;
|
|
18015
|
+
if (metaModels && Array.isArray(metaModels) && metaModels.length > 0) return metaModels;
|
|
18016
|
+
const availableModels = response.models?.availableModels;
|
|
18017
|
+
if (availableModels && Array.isArray(availableModels) && availableModels.length > 0) return availableModels.map((model) => ({
|
|
18018
|
+
...model,
|
|
18019
|
+
...model._meta?.["codebuddy.ai"] || {}
|
|
18020
|
+
}));
|
|
18021
|
+
}
|
|
17995
18022
|
};
|
|
17996
18023
|
|
|
17997
18024
|
//#endregion
|
|
@@ -18264,6 +18291,28 @@ var AgentClient = class {
|
|
|
18264
18291
|
};
|
|
18265
18292
|
}
|
|
18266
18293
|
},
|
|
18294
|
+
getSubagentList: async (params) => {
|
|
18295
|
+
try {
|
|
18296
|
+
if (this.provider && this.provider.getSubagentList) {
|
|
18297
|
+
const result = await this.provider.getSubagentList(params);
|
|
18298
|
+
this.logger?.info("Subagent list retrieved", {
|
|
18299
|
+
resultCount: result.results.length,
|
|
18300
|
+
hasError: !!result.error
|
|
18301
|
+
});
|
|
18302
|
+
return result;
|
|
18303
|
+
}
|
|
18304
|
+
return {
|
|
18305
|
+
results: [],
|
|
18306
|
+
error: "Provider does not support getSubagentList"
|
|
18307
|
+
};
|
|
18308
|
+
} catch (error) {
|
|
18309
|
+
this.logger?.error("Failed to get subagent list", error);
|
|
18310
|
+
return {
|
|
18311
|
+
results: [],
|
|
18312
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
18313
|
+
};
|
|
18314
|
+
}
|
|
18315
|
+
},
|
|
18267
18316
|
batchTogglePlugins: async (request) => {
|
|
18268
18317
|
try {
|
|
18269
18318
|
if (this.provider && this.provider.batchTogglePlugins) {
|
|
@@ -18308,10 +18357,10 @@ var AgentClient = class {
|
|
|
18308
18357
|
return [];
|
|
18309
18358
|
}
|
|
18310
18359
|
},
|
|
18311
|
-
installPlugins: async (pluginNames, marketplaceName, installScope) => {
|
|
18360
|
+
installPlugins: async (pluginNames, marketplaceName, installScope, marketplaceSource) => {
|
|
18312
18361
|
try {
|
|
18313
18362
|
if (this.provider && "installPlugins" in this.provider && typeof this.provider.installPlugins === "function") {
|
|
18314
|
-
const result = await this.provider.installPlugins(pluginNames, marketplaceName, installScope);
|
|
18363
|
+
const result = await this.provider.installPlugins(pluginNames, marketplaceName, installScope, marketplaceSource);
|
|
18315
18364
|
this.logger?.info("Install plugins", {
|
|
18316
18365
|
pluginNames,
|
|
18317
18366
|
marketplaceName,
|
|
@@ -18346,6 +18395,23 @@ var AgentClient = class {
|
|
|
18346
18395
|
return [];
|
|
18347
18396
|
}
|
|
18348
18397
|
},
|
|
18398
|
+
getAvailableCommands: async (sessionId) => {
|
|
18399
|
+
try {
|
|
18400
|
+
if (this.provider && "getAvailableCommands" in this.provider && typeof this.provider.getAvailableCommands === "function") {
|
|
18401
|
+
const result = await this.provider.getAvailableCommands(sessionId);
|
|
18402
|
+
this.logger?.info("Got available commands from provider", {
|
|
18403
|
+
sessionId: sessionId ?? "(default)",
|
|
18404
|
+
count: result?.length ?? 0
|
|
18405
|
+
});
|
|
18406
|
+
return result;
|
|
18407
|
+
}
|
|
18408
|
+
this.logger?.warn("Provider does not support getAvailableCommands", { sessionId });
|
|
18409
|
+
return [];
|
|
18410
|
+
} catch (error) {
|
|
18411
|
+
this.logger?.error("Failed to get available commands", error);
|
|
18412
|
+
return [];
|
|
18413
|
+
}
|
|
18414
|
+
},
|
|
18349
18415
|
models: this.createModelsResource()
|
|
18350
18416
|
};
|
|
18351
18417
|
}
|
|
@@ -18412,6 +18478,154 @@ let AccountStatus = /* @__PURE__ */ function(AccountStatus) {
|
|
|
18412
18478
|
return AccountStatus;
|
|
18413
18479
|
}({});
|
|
18414
18480
|
|
|
18481
|
+
//#endregion
|
|
18482
|
+
//#region ../agent-provider/src/backend/service/oauth-repository-service.ts
|
|
18483
|
+
/**
|
|
18484
|
+
* OAuth Repository Service
|
|
18485
|
+
*
|
|
18486
|
+
* 封装 OAuth 连接器相关的仓库和分支操作
|
|
18487
|
+
*/
|
|
18488
|
+
/**
|
|
18489
|
+
* OAuth Repository Service
|
|
18490
|
+
*
|
|
18491
|
+
* 提供仓库和分支的查询操作
|
|
18492
|
+
*/
|
|
18493
|
+
var OAuthRepositoryService = class {
|
|
18494
|
+
/**
|
|
18495
|
+
* 获取仓库分支列表
|
|
18496
|
+
* API 端点: GET /console/as/connector/oauth/{name}/branches
|
|
18497
|
+
*
|
|
18498
|
+
* @param connector 连接器名称 ('github' | 'gongfeng' | 'cnb')
|
|
18499
|
+
* @param params 平台特定的查询参数
|
|
18500
|
+
* @param page 页码,从1开始,0表示不分页获取全部
|
|
18501
|
+
* @param perPage 每页数量,最大100
|
|
18502
|
+
* @returns Promise<OauthBranch[]> 分支列表
|
|
18503
|
+
*
|
|
18504
|
+
* @example
|
|
18505
|
+
* ```typescript
|
|
18506
|
+
* // GitHub
|
|
18507
|
+
* const branches = await service.getBranches('github', {
|
|
18508
|
+
* owner: 'CodeBuddy-Official-Account',
|
|
18509
|
+
* repo: 'CodeBuddyIDE'
|
|
18510
|
+
* });
|
|
18511
|
+
*
|
|
18512
|
+
* // Gongfeng
|
|
18513
|
+
* const branches = await service.getBranches('gongfeng', {
|
|
18514
|
+
* project_id: '1611499'
|
|
18515
|
+
* });
|
|
18516
|
+
*
|
|
18517
|
+
* // CNB
|
|
18518
|
+
* const branches = await service.getBranches('cnb', {
|
|
18519
|
+
* repo: 'genie/genie-ide'
|
|
18520
|
+
* });
|
|
18521
|
+
* ```
|
|
18522
|
+
*/
|
|
18523
|
+
async getBranches(connector, params, page = 0, perPage = 100) {
|
|
18524
|
+
try {
|
|
18525
|
+
const url = `/console/as/connector/oauth/${connector}/branches?${this.buildBranchQueryParams(connector, params, page, perPage).toString()}`;
|
|
18526
|
+
console.log(`[OAuthRepositoryService] GET ${url}`);
|
|
18527
|
+
const apiResponse = await httpService.get(url);
|
|
18528
|
+
if (!apiResponse.data) {
|
|
18529
|
+
console.warn(`[OAuthRepositoryService] No data in branches response for ${connector}`);
|
|
18530
|
+
return [];
|
|
18531
|
+
}
|
|
18532
|
+
const branches = apiResponse.data.branches || [];
|
|
18533
|
+
console.log(`[OAuthRepositoryService] Retrieved ${branches.length} branches from ${connector}`);
|
|
18534
|
+
return branches;
|
|
18535
|
+
} catch (error) {
|
|
18536
|
+
console.error(`[OAuthRepositoryService] Failed to get branches from ${connector}:`, error);
|
|
18537
|
+
throw error;
|
|
18538
|
+
}
|
|
18539
|
+
}
|
|
18540
|
+
/**
|
|
18541
|
+
* 获取仓库列表
|
|
18542
|
+
* API 端点: GET /console/as/connector/oauth/{name}/repos
|
|
18543
|
+
*
|
|
18544
|
+
* Note: 由于工蜂原生支持的 Search 能力会匹配 path/name/description 部分,
|
|
18545
|
+
* 且不支持定制,不满足产品要求(只按 name 匹配),因此前端拉取全量数据后做筛选。
|
|
18546
|
+
*
|
|
18547
|
+
* @param connector 连接器名称 ('github' | 'gongfeng' | 'cnb')
|
|
18548
|
+
* @param page 页码,从1开始,0表示不分页获取全部
|
|
18549
|
+
* - GitHub 只支持全量数据,必须传 0
|
|
18550
|
+
* - 工蜂和 CNB 依据前端逻辑而定
|
|
18551
|
+
* @param perPage 每页数量,最大100
|
|
18552
|
+
* @returns Promise<ListReposResponse> 仓库列表响应
|
|
18553
|
+
*
|
|
18554
|
+
* @example
|
|
18555
|
+
* ```typescript
|
|
18556
|
+
* // GitHub - 必须传 page=0 获取全量数据
|
|
18557
|
+
* const response = await service.getRepositories('github', 0, 100);
|
|
18558
|
+
* // response.github_repos 是 map: installation_id => repo[]
|
|
18559
|
+
*
|
|
18560
|
+
* // Gongfeng
|
|
18561
|
+
* const response = await service.getRepositories('gongfeng', 0, 100);
|
|
18562
|
+
* // response.gongfeng_repos 是数组
|
|
18563
|
+
*
|
|
18564
|
+
* // CNB
|
|
18565
|
+
* const response = await service.getRepositories('cnb', 0, 100);
|
|
18566
|
+
* // response.cnb_repos 是数组
|
|
18567
|
+
* ```
|
|
18568
|
+
*/
|
|
18569
|
+
async getRepositories(connector, page = 0, perPage = 100) {
|
|
18570
|
+
try {
|
|
18571
|
+
const queryParams = new URLSearchParams();
|
|
18572
|
+
queryParams.append("page", String(page));
|
|
18573
|
+
queryParams.append("per_page", String(Math.min(perPage, 100)));
|
|
18574
|
+
const url = `/console/as/connector/oauth/${connector}/repos?${queryParams.toString()}`;
|
|
18575
|
+
console.log(`[OAuthRepositoryService] GET ${url}`);
|
|
18576
|
+
const apiResponse = await httpService.get(url);
|
|
18577
|
+
if (!apiResponse.data) {
|
|
18578
|
+
console.warn(`[OAuthRepositoryService] No data in repos response for ${connector}`);
|
|
18579
|
+
return {};
|
|
18580
|
+
}
|
|
18581
|
+
const response = apiResponse.data;
|
|
18582
|
+
this.logRepositoryCounts(response);
|
|
18583
|
+
return response;
|
|
18584
|
+
} catch (error) {
|
|
18585
|
+
console.error(`[OAuthRepositoryService] Failed to get repos from ${connector}:`, error);
|
|
18586
|
+
throw error;
|
|
18587
|
+
}
|
|
18588
|
+
}
|
|
18589
|
+
/**
|
|
18590
|
+
* 构建分支查询参数
|
|
18591
|
+
*/
|
|
18592
|
+
buildBranchQueryParams(connector, params, page, perPage) {
|
|
18593
|
+
const queryParams = new URLSearchParams();
|
|
18594
|
+
queryParams.append("page", String(page));
|
|
18595
|
+
queryParams.append("per_page", String(Math.min(perPage, 100)));
|
|
18596
|
+
if (connector === "github") {
|
|
18597
|
+
const githubParams = params;
|
|
18598
|
+
if (!githubParams.owner || !githubParams.repo) throw new Error("GitHub requires owner and repo parameters");
|
|
18599
|
+
queryParams.append("owner", githubParams.owner);
|
|
18600
|
+
queryParams.append("repo", githubParams.repo);
|
|
18601
|
+
} else if (connector === "gongfeng") {
|
|
18602
|
+
const gongfengParams = params;
|
|
18603
|
+
if (!gongfengParams.project_id) throw new Error("Gongfeng requires project_id parameter");
|
|
18604
|
+
queryParams.append("project_id", gongfengParams.project_id);
|
|
18605
|
+
} else if (connector === "cnb") {
|
|
18606
|
+
const cnbParams = params;
|
|
18607
|
+
if (!cnbParams.repo) throw new Error("CNB requires repo parameter");
|
|
18608
|
+
queryParams.append("repo", cnbParams.repo);
|
|
18609
|
+
} else throw new Error(`Unknown connector: ${connector}`);
|
|
18610
|
+
return queryParams;
|
|
18611
|
+
}
|
|
18612
|
+
/**
|
|
18613
|
+
* 记录仓库数量日志
|
|
18614
|
+
*/
|
|
18615
|
+
logRepositoryCounts(response) {
|
|
18616
|
+
if (response.github_repos) {
|
|
18617
|
+
const totalCount = Object.values(response.github_repos).reduce((sum, repos) => sum + repos.length, 0);
|
|
18618
|
+
console.log(`[OAuthRepositoryService] Retrieved ${totalCount} GitHub repos across ${Object.keys(response.github_repos).length} installations`);
|
|
18619
|
+
}
|
|
18620
|
+
if (response.gongfeng_repos) console.log(`[OAuthRepositoryService] Retrieved ${response.gongfeng_repos.length} Gongfeng repos`);
|
|
18621
|
+
if (response.cnb_repos) console.log(`[OAuthRepositoryService] Retrieved ${response.cnb_repos.length} CNB repos`);
|
|
18622
|
+
}
|
|
18623
|
+
};
|
|
18624
|
+
/**
|
|
18625
|
+
* OAuth Repository Service 单例实例
|
|
18626
|
+
*/
|
|
18627
|
+
const oauthRepositoryService = new OAuthRepositoryService();
|
|
18628
|
+
|
|
18415
18629
|
//#endregion
|
|
18416
18630
|
//#region ../agent-provider/src/backend/backend-provider.ts
|
|
18417
18631
|
/**
|
|
@@ -18420,27 +18634,29 @@ let AccountStatus = /* @__PURE__ */ function(AccountStatus) {
|
|
|
18420
18634
|
* 封装与后端 API 的 HTTP 通信
|
|
18421
18635
|
*/
|
|
18422
18636
|
/**
|
|
18423
|
-
*
|
|
18424
|
-
*
|
|
18637
|
+
* 判断当前账号是否是 SSO 账号
|
|
18638
|
+
* 通过 account.accountType === 'sso' 来判断,这种不行,因为未登录之前account 为空
|
|
18425
18639
|
*/
|
|
18426
18640
|
const isSSODomain = () => {
|
|
18427
18641
|
const { hostname } = window.location;
|
|
18428
18642
|
return hostname.includes(".sso.copilot") || hostname.includes("sso.codebuddy.cn") || hostname.includes(".sso.copilot-staging") || hostname.includes(".staging-sso.codebuddy.cn");
|
|
18429
18643
|
};
|
|
18430
18644
|
/**
|
|
18431
|
-
*
|
|
18432
|
-
* - SSO
|
|
18433
|
-
* - 非 SSO
|
|
18645
|
+
* 根据路径获取完整 URL
|
|
18646
|
+
* - SSO 账号需要跳转到对应的预发/生产域名
|
|
18647
|
+
* - 非 SSO 账号直接使用当前域名
|
|
18648
|
+
* @param path 路径,如 '/login'、'/logout'、'/home' 等
|
|
18649
|
+
* @returns 完整的 URL 地址
|
|
18434
18650
|
*/
|
|
18435
|
-
const
|
|
18651
|
+
const getFullUrl = (path) => {
|
|
18436
18652
|
const { hostname, protocol } = window.location;
|
|
18437
18653
|
if (isSSODomain()) {
|
|
18438
18654
|
const isCodebuddy = hostname.includes("codebuddy.cn");
|
|
18439
18655
|
const isStaging = hostname.includes("staging");
|
|
18440
|
-
if (isCodebuddy) return isStaging ? `${protocol}//staging.codebuddy.cn
|
|
18441
|
-
else return isStaging ? `${protocol}//staging-copilot.tencent.com
|
|
18656
|
+
if (isCodebuddy) return isStaging ? `${protocol}//staging.codebuddy.cn${path}` : `${protocol}//www.codebuddy.cn${path}`;
|
|
18657
|
+
else return isStaging ? `${protocol}//staging-copilot.tencent.com${path}` : `${protocol}//copilot.tencent.com${path}`;
|
|
18442
18658
|
}
|
|
18443
|
-
return `${window.location.origin}
|
|
18659
|
+
return `${window.location.origin}${path}`;
|
|
18444
18660
|
};
|
|
18445
18661
|
/** 获取当前域名的账号选择页面 URL */
|
|
18446
18662
|
const getSelectAccountUrl = () => `${window.location.origin}/login/select`;
|
|
@@ -18528,7 +18744,7 @@ var BackendProvider = class {
|
|
|
18528
18744
|
return account;
|
|
18529
18745
|
}
|
|
18530
18746
|
const redirectUrl = encodeURIComponent(window.location.href);
|
|
18531
|
-
window.location.href = `${getSelectAccountUrl()}?platform=
|
|
18747
|
+
window.location.href = `${getSelectAccountUrl()}?platform=agents&state=0&redirect_uri=${redirectUrl}`;
|
|
18532
18748
|
accountService.setAccount(null);
|
|
18533
18749
|
return null;
|
|
18534
18750
|
} catch (error) {
|
|
@@ -18551,7 +18767,8 @@ var BackendProvider = class {
|
|
|
18551
18767
|
activeStatus: connector.active_status,
|
|
18552
18768
|
displayName: connector.display_name,
|
|
18553
18769
|
oauthClientId: connector.oauth_client_id,
|
|
18554
|
-
oauthRedirectUrl: connector.oauth_redirect_url
|
|
18770
|
+
oauthRedirectUrl: connector.oauth_redirect_url,
|
|
18771
|
+
oauthAppName: connector.oauth_app_name
|
|
18555
18772
|
})) };
|
|
18556
18773
|
}
|
|
18557
18774
|
throw result;
|
|
@@ -18633,7 +18850,8 @@ var BackendProvider = class {
|
|
|
18633
18850
|
connectStatus: connector.connect_status,
|
|
18634
18851
|
displayName: connector.display_name,
|
|
18635
18852
|
oauthClientId: connector.oauth_client_id,
|
|
18636
|
-
oauthRedirectUrl: connector.oauth_redirect_url
|
|
18853
|
+
oauthRedirectUrl: connector.oauth_redirect_url,
|
|
18854
|
+
oauthAppName: connector.oauth_app_name
|
|
18637
18855
|
})) };
|
|
18638
18856
|
}
|
|
18639
18857
|
throw result;
|
|
@@ -18890,7 +19108,7 @@ var BackendProvider = class {
|
|
|
18890
19108
|
*/
|
|
18891
19109
|
async login() {
|
|
18892
19110
|
const redirectUrl = encodeURIComponent(window.location.href);
|
|
18893
|
-
window.location.href = `${
|
|
19111
|
+
window.location.href = `${getFullUrl("/login")}?platform=agents&state=0&redirect_uri=${redirectUrl}`;
|
|
18894
19112
|
}
|
|
18895
19113
|
/**
|
|
18896
19114
|
* 登出账号
|
|
@@ -18953,6 +19171,52 @@ var BackendProvider = class {
|
|
|
18953
19171
|
return null;
|
|
18954
19172
|
}
|
|
18955
19173
|
}
|
|
19174
|
+
/**
|
|
19175
|
+
* 刷新 Token
|
|
19176
|
+
* 通过调用 getAccount 刷新 cookie,适用于 Cloud 场景下页面切换回来时刷新登录态
|
|
19177
|
+
* @returns Promise<Account | null> 刷新后的账号信息
|
|
19178
|
+
*/
|
|
19179
|
+
async refreshToken() {
|
|
19180
|
+
console.log("[BackendProvider] Refreshing token...");
|
|
19181
|
+
try {
|
|
19182
|
+
const account = await this.getAccount();
|
|
19183
|
+
console.log("[BackendProvider] Token refreshed, account:", account?.uid);
|
|
19184
|
+
return account;
|
|
19185
|
+
} catch (error) {
|
|
19186
|
+
console.error("[BackendProvider] refreshToken failed:", error);
|
|
19187
|
+
return null;
|
|
19188
|
+
}
|
|
19189
|
+
}
|
|
19190
|
+
/**
|
|
19191
|
+
* 获取仓库分支列表
|
|
19192
|
+
* API 端点: GET /console/as/connector/oauth/{name}/branches
|
|
19193
|
+
*
|
|
19194
|
+
* @param connector 连接器名称 ('github' | 'gongfeng' | 'cnb')
|
|
19195
|
+
* @param params 平台特定的查询参数
|
|
19196
|
+
* @param page 页码,从1开始,0表示不分页获取全部
|
|
19197
|
+
* @param perPage 每页数量,最大100
|
|
19198
|
+
* @returns Promise<OauthBranch[]> 分支列表
|
|
19199
|
+
*/
|
|
19200
|
+
async getBranches(connector, params, page = 0, perPage = 100) {
|
|
19201
|
+
return oauthRepositoryService.getBranches(connector, params, page, perPage);
|
|
19202
|
+
}
|
|
19203
|
+
/**
|
|
19204
|
+
* 获取仓库列表
|
|
19205
|
+
* API 端点: GET /console/as/connector/oauth/{name}/repos
|
|
19206
|
+
*
|
|
19207
|
+
* Note: 由于工蜂原生支持的 Search 能力会匹配 path/name/description 部分,
|
|
19208
|
+
* 且不支持定制,不满足产品要求(只按 name 匹配),因此前端拉取全量数据后做筛选。
|
|
19209
|
+
*
|
|
19210
|
+
* @param connector 连接器名称 ('github' | 'gongfeng' | 'cnb')
|
|
19211
|
+
* @param page 页码,从1开始,0表示不分页获取全部
|
|
19212
|
+
* - GitHub 只支持全量数据,必须传 0
|
|
19213
|
+
* - 工蜂和 CNB 依据前端逻辑而定
|
|
19214
|
+
* @param perPage 每页数量,最大100
|
|
19215
|
+
* @returns Promise<ListReposResponse> 仓库列表响应
|
|
19216
|
+
*/
|
|
19217
|
+
async getRepositories(connector, page = 0, perPage = 100) {
|
|
19218
|
+
return oauthRepositoryService.getRepositories(connector, page, perPage);
|
|
19219
|
+
}
|
|
18956
19220
|
};
|
|
18957
19221
|
/**
|
|
18958
19222
|
* 创建 BackendProvider 实例
|
|
@@ -18992,6 +19256,7 @@ const BACKEND_REQUEST_TYPES = {
|
|
|
18992
19256
|
GET_FILE: "backend:get-file",
|
|
18993
19257
|
RELOAD_WINDOW: "backend:reload-window",
|
|
18994
19258
|
CLOSE_AGENT_MANAGER: "backend:close-agent-manager",
|
|
19259
|
+
OPEN_EXTERNAL: "backend:open-external",
|
|
18995
19260
|
BATCH_TOGGLE_PLUGINS: "backend:batch-toggle-plugins",
|
|
18996
19261
|
GET_SUPPORT_SCENES: "backend:get-support-scenes"
|
|
18997
19262
|
};
|
|
@@ -19287,6 +19552,20 @@ var IPCBackendProvider = class {
|
|
|
19287
19552
|
}
|
|
19288
19553
|
}
|
|
19289
19554
|
/**
|
|
19555
|
+
* 在外部浏览器中打开链接
|
|
19556
|
+
* IDE 环境: 通过 IPC 通知 IDE 使用 vscode.env.openExternal 打开 URL
|
|
19557
|
+
* @param url 要打开的 URL
|
|
19558
|
+
*/
|
|
19559
|
+
async openExternal(url) {
|
|
19560
|
+
this.log("Opening external URL via IPC:", url);
|
|
19561
|
+
try {
|
|
19562
|
+
await this.sendBackendRequest(BACKEND_REQUEST_TYPES.OPEN_EXTERNAL, { url });
|
|
19563
|
+
} catch (error) {
|
|
19564
|
+
this.log("Open external request failed:", error);
|
|
19565
|
+
throw error;
|
|
19566
|
+
}
|
|
19567
|
+
}
|
|
19568
|
+
/**
|
|
19290
19569
|
* 批量切换插件状态
|
|
19291
19570
|
* IDE 环境: 通过 IPC 调用 Extension Host 的 PluginService
|
|
19292
19571
|
*/
|