@tencent-ai/cloud-agent-sdk 0.2.12 → 0.2.13-next.2f2e439.20260206
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 +486 -91
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +624 -95
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +624 -95
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +486 -91
- package/dist/index.mjs.map +1 -1
- package/dist/tencent-ai-cloud-agent-sdk-0.2.13-next.2f2e439.20260206.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
|
}
|
|
@@ -15923,7 +15923,7 @@ var axios_default = axios;
|
|
|
15923
15923
|
* 特性:
|
|
15924
15924
|
* - 单例模式,全局唯一实例,延迟初始化(首次使用时自动创建)
|
|
15925
15925
|
* - 支持拦截器注册(其他模块可注入 header)
|
|
15926
|
-
* - 统一 401
|
|
15926
|
+
* - 统一 401 处理(支持自动刷新 token 并重试)
|
|
15927
15927
|
* - 自动携带凭证(withCredentials)
|
|
15928
15928
|
* - 类型安全
|
|
15929
15929
|
*
|
|
@@ -15963,6 +15963,8 @@ var HttpService = class HttpService {
|
|
|
15963
15963
|
*/
|
|
15964
15964
|
constructor(config = {}) {
|
|
15965
15965
|
this.unauthorizedCallbacks = /* @__PURE__ */ new Set();
|
|
15966
|
+
this.isRefreshing = false;
|
|
15967
|
+
this.refreshSubscribers = [];
|
|
15966
15968
|
this.config = config;
|
|
15967
15969
|
this.axiosInstance = axios_default.create({
|
|
15968
15970
|
baseURL: config.baseURL?.replace(/\/$/, "") || "",
|
|
@@ -16003,18 +16005,54 @@ var HttpService = class HttpService {
|
|
|
16003
16005
|
}, (error) => Promise.reject(error));
|
|
16004
16006
|
}
|
|
16005
16007
|
/**
|
|
16006
|
-
* 注册默认响应拦截器(处理 401
|
|
16008
|
+
* 注册默认响应拦截器(处理 401,支持自动重试)
|
|
16007
16009
|
*/
|
|
16008
16010
|
registerDefaultResponseInterceptor() {
|
|
16009
|
-
this.axiosInstance.interceptors.response.use((response) => response, (error) => {
|
|
16010
|
-
|
|
16011
|
-
|
|
16012
|
-
|
|
16011
|
+
this.axiosInstance.interceptors.response.use((response) => response, async (error) => {
|
|
16012
|
+
const originalRequest = error.config;
|
|
16013
|
+
if (error.response?.status === 401 && originalRequest && !originalRequest._retry) {
|
|
16014
|
+
if (originalRequest.url?.includes("/console/accounts")) {
|
|
16015
|
+
console.warn("[HttpService] Unauthorized 401 on refresh endpoint, not retrying");
|
|
16016
|
+
return Promise.reject(error);
|
|
16017
|
+
}
|
|
16018
|
+
console.warn("[HttpService] Unauthorized 401, attempting token refresh and retry");
|
|
16019
|
+
originalRequest._retry = true;
|
|
16020
|
+
if (this.isRefreshing) return new Promise((resolve, reject) => {
|
|
16021
|
+
this.refreshSubscribers.push((success) => {
|
|
16022
|
+
if (success) this.axiosInstance.request(originalRequest).then(resolve).catch(reject);
|
|
16023
|
+
else reject(error);
|
|
16024
|
+
});
|
|
16025
|
+
});
|
|
16026
|
+
this.isRefreshing = true;
|
|
16027
|
+
try {
|
|
16028
|
+
await this.triggerUnauthorizedCallbacks();
|
|
16029
|
+
this.onRefreshSuccess();
|
|
16030
|
+
return this.axiosInstance.request(originalRequest);
|
|
16031
|
+
} catch (refreshError) {
|
|
16032
|
+
this.onRefreshFailure();
|
|
16033
|
+
return Promise.reject(error);
|
|
16034
|
+
} finally {
|
|
16035
|
+
this.isRefreshing = false;
|
|
16036
|
+
}
|
|
16013
16037
|
}
|
|
16014
16038
|
return Promise.reject(error);
|
|
16015
16039
|
});
|
|
16016
16040
|
}
|
|
16017
16041
|
/**
|
|
16042
|
+
* token 刷新成功,通知所有等待的请求
|
|
16043
|
+
*/
|
|
16044
|
+
onRefreshSuccess() {
|
|
16045
|
+
this.refreshSubscribers.forEach((callback) => callback(true));
|
|
16046
|
+
this.refreshSubscribers = [];
|
|
16047
|
+
}
|
|
16048
|
+
/**
|
|
16049
|
+
* token 刷新失败,通知所有等待的请求
|
|
16050
|
+
*/
|
|
16051
|
+
onRefreshFailure() {
|
|
16052
|
+
this.refreshSubscribers.forEach((callback) => callback(false));
|
|
16053
|
+
this.refreshSubscribers = [];
|
|
16054
|
+
}
|
|
16055
|
+
/**
|
|
16018
16056
|
* 注册请求拦截器
|
|
16019
16057
|
* @param onFulfilled 请求成功拦截器
|
|
16020
16058
|
* @param onRejected 请求失败拦截器
|
|
@@ -16091,16 +16129,18 @@ var HttpService = class HttpService {
|
|
|
16091
16129
|
this.unauthorizedCallbacks.delete(callback);
|
|
16092
16130
|
}
|
|
16093
16131
|
/**
|
|
16094
|
-
* 触发所有 401
|
|
16132
|
+
* 触发所有 401 回调并等待完成
|
|
16133
|
+
* @returns Promise,等待所有回调完成
|
|
16134
|
+
* @throws 如果任何回调失败,则抛出错误
|
|
16095
16135
|
*/
|
|
16096
|
-
triggerUnauthorizedCallbacks() {
|
|
16097
|
-
this.unauthorizedCallbacks
|
|
16098
|
-
|
|
16099
|
-
|
|
16100
|
-
|
|
16101
|
-
|
|
16102
|
-
|
|
16103
|
-
}
|
|
16136
|
+
async triggerUnauthorizedCallbacks() {
|
|
16137
|
+
const callbacks = Array.from(this.unauthorizedCallbacks);
|
|
16138
|
+
const failedResults = (await Promise.allSettled(callbacks.map((callback) => callback()))).filter((r) => r.status === "rejected");
|
|
16139
|
+
if (failedResults.length > 0) {
|
|
16140
|
+
const errors = failedResults.map((r) => r.reason);
|
|
16141
|
+
console.error("[HttpService] Some unauthorized callbacks failed:", errors);
|
|
16142
|
+
throw errors[0];
|
|
16143
|
+
}
|
|
16104
16144
|
}
|
|
16105
16145
|
/**
|
|
16106
16146
|
* 更新 authToken
|
|
@@ -16212,6 +16252,7 @@ var AccountService = class {
|
|
|
16212
16252
|
this.initPromise = null;
|
|
16213
16253
|
this.initResolve = null;
|
|
16214
16254
|
this.requestInterceptorId = null;
|
|
16255
|
+
this.crossTabBroadcaster = null;
|
|
16215
16256
|
this.initPromise = new Promise((resolve) => {
|
|
16216
16257
|
this.initResolve = resolve;
|
|
16217
16258
|
});
|
|
@@ -16260,15 +16301,34 @@ var AccountService = class {
|
|
|
16260
16301
|
this.initialized = true;
|
|
16261
16302
|
this.initResolve?.(account);
|
|
16262
16303
|
}
|
|
16263
|
-
if (!wasInitialized || prev?.uid !== account?.uid)
|
|
16304
|
+
if (!wasInitialized || prev?.uid !== account?.uid) {
|
|
16305
|
+
this.notifyListeners();
|
|
16306
|
+
if (account && this.crossTabBroadcaster) this.crossTabBroadcaster.broadcastLogin();
|
|
16307
|
+
}
|
|
16264
16308
|
}
|
|
16265
16309
|
/**
|
|
16266
16310
|
* 清除账号(登出)
|
|
16311
|
+
* 先广播登出消息,再清除本地账号
|
|
16267
16312
|
*/
|
|
16268
16313
|
clearAccount() {
|
|
16314
|
+
if (this.crossTabBroadcaster) this.crossTabBroadcaster.broadcastLogout();
|
|
16269
16315
|
this.setAccount(null);
|
|
16270
16316
|
}
|
|
16271
16317
|
/**
|
|
16318
|
+
* 静默清除账号(不广播)
|
|
16319
|
+
* 用于收到其他标签页 logout 消息时,避免循环广播
|
|
16320
|
+
*/
|
|
16321
|
+
clearAccountSilently() {
|
|
16322
|
+
this.setAccount(null);
|
|
16323
|
+
}
|
|
16324
|
+
/**
|
|
16325
|
+
* 设置跨标签页认证同步广播器
|
|
16326
|
+
* 应在应用初始化时由上层(如 agent-ui)调用
|
|
16327
|
+
*/
|
|
16328
|
+
setCrossTabBroadcaster(broadcaster) {
|
|
16329
|
+
this.crossTabBroadcaster = broadcaster;
|
|
16330
|
+
}
|
|
16331
|
+
/**
|
|
16272
16332
|
* 订阅账号变化
|
|
16273
16333
|
* @param callback 变化时的回调函数
|
|
16274
16334
|
* @returns 取消订阅函数
|
|
@@ -16333,6 +16393,11 @@ var AccountService = class {
|
|
|
16333
16393
|
* 导出单例实例
|
|
16334
16394
|
*/
|
|
16335
16395
|
const accountService = new AccountService();
|
|
16396
|
+
/**
|
|
16397
|
+
* 暴露给全局,供 Agent Manager 直接调用 setAccount 刷新 Widget 状态
|
|
16398
|
+
* 这是为了解决 IDE 环境中 IPC 事件无法直接触发 Widget 账号刷新的问题
|
|
16399
|
+
*/
|
|
16400
|
+
if (typeof window !== "undefined") window.__genieAccountService = accountService;
|
|
16336
16401
|
|
|
16337
16402
|
//#endregion
|
|
16338
16403
|
//#region ../agent-provider/src/common/utils/concurrency.ts
|
|
@@ -16922,15 +16987,9 @@ var CloudAgentProvider = class CloudAgentProvider {
|
|
|
16922
16987
|
const url = this.buildGetUrl("/console/as/conversations/", params);
|
|
16923
16988
|
const apiResponse = await httpService.get(url);
|
|
16924
16989
|
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
16990
|
return {
|
|
16932
|
-
agents,
|
|
16933
|
-
pagination
|
|
16991
|
+
agents: apiResponse.data.conversations.map((a) => this.toAgentState(a)),
|
|
16992
|
+
pagination: apiResponse.data.pagination
|
|
16934
16993
|
};
|
|
16935
16994
|
} catch (error) {
|
|
16936
16995
|
this.logger?.error("Failed to list agents:", error);
|
|
@@ -16940,13 +16999,21 @@ var CloudAgentProvider = class CloudAgentProvider {
|
|
|
16940
16999
|
/**
|
|
16941
17000
|
* Create a new conversation
|
|
16942
17001
|
* POST {endpoint}/console/as/conversations
|
|
17002
|
+
* @param params - Session params containing cwd and optional configuration
|
|
16943
17003
|
*/
|
|
16944
|
-
async create() {
|
|
17004
|
+
async create(params) {
|
|
16945
17005
|
try {
|
|
16946
|
-
const
|
|
16947
|
-
|
|
16948
|
-
|
|
16949
|
-
});
|
|
17006
|
+
const { options = {} } = params;
|
|
17007
|
+
const codebuddyMeta = options._meta?.["codebuddy.ai"];
|
|
17008
|
+
const tagsObj = options.tags || codebuddyMeta?.tags;
|
|
17009
|
+
const tagsArray = tagsObj ? Object.entries(tagsObj).map(([key, value]) => `${key}:${value}`) : void 0;
|
|
17010
|
+
const createPayload = {
|
|
17011
|
+
prompt: (options.prompt || "").slice(0, 100),
|
|
17012
|
+
model: options.model || "deepseek-r1",
|
|
17013
|
+
...tagsArray && tagsArray.length > 0 ? { tags: tagsArray } : {}
|
|
17014
|
+
};
|
|
17015
|
+
console.log("[CloudAgentProvider] Creating conversation with payload:", createPayload);
|
|
17016
|
+
const apiResponse = await httpService.post("/console/as/conversations/", createPayload);
|
|
16950
17017
|
if (!apiResponse.data) throw new Error("No data in API response");
|
|
16951
17018
|
this.logger?.info(`Created conversation: ${apiResponse.data.id}`);
|
|
16952
17019
|
return apiResponse.data.id;
|
|
@@ -17312,17 +17379,20 @@ var CloudAgentProvider = class CloudAgentProvider {
|
|
|
17312
17379
|
* API 端点: GET /console/as/support/scenes
|
|
17313
17380
|
* 用于 Welcome 页面的 QuickActions 快捷操作
|
|
17314
17381
|
*
|
|
17382
|
+
* @param locale - 可选,语言环境(如 'zh-CN', 'en-US'),用于获取对应语言的场景数据
|
|
17315
17383
|
* @returns Promise<SupportScene[]> 支持的场景列表
|
|
17316
17384
|
*/
|
|
17317
|
-
async getSupportScenes() {
|
|
17385
|
+
async getSupportScenes(locale) {
|
|
17318
17386
|
try {
|
|
17319
|
-
|
|
17387
|
+
let url = "/console/as/support/scenes";
|
|
17388
|
+
if (locale) url += `?locale=${encodeURIComponent(locale)}`;
|
|
17389
|
+
const apiResponse = await httpService.get(url);
|
|
17320
17390
|
if (!apiResponse.data) {
|
|
17321
17391
|
this.logger?.warn("[CloudAgentProvider] No data in support scenes response");
|
|
17322
17392
|
return [];
|
|
17323
17393
|
}
|
|
17324
17394
|
const scenes = apiResponse.data.scenes || [];
|
|
17325
|
-
this.logger?.info(`[CloudAgentProvider] Retrieved ${scenes.length} support scenes`);
|
|
17395
|
+
this.logger?.info(`[CloudAgentProvider] Retrieved ${scenes.length} support scenes${locale ? ` for locale: ${locale}` : ""}`);
|
|
17326
17396
|
return scenes;
|
|
17327
17397
|
} catch (error) {
|
|
17328
17398
|
this.logger?.error("[CloudAgentProvider] Failed to get support scenes:", error);
|
|
@@ -17338,7 +17408,8 @@ var CloudAgentProvider = class CloudAgentProvider {
|
|
|
17338
17408
|
type: "cloud",
|
|
17339
17409
|
status,
|
|
17340
17410
|
createdAt: data.createdAt ? new Date(data.createdAt) : void 0,
|
|
17341
|
-
capabilities: this.options.clientCapabilities
|
|
17411
|
+
capabilities: this.options.clientCapabilities,
|
|
17412
|
+
isUserDefinedTitle: data.isUserDefinedTitle
|
|
17342
17413
|
};
|
|
17343
17414
|
}
|
|
17344
17415
|
/**
|
|
@@ -17643,8 +17714,8 @@ var ActiveSessionImpl = class {
|
|
|
17643
17714
|
* await session.setMode('architect');
|
|
17644
17715
|
* ```
|
|
17645
17716
|
*/
|
|
17646
|
-
async setMode(modeId) {
|
|
17647
|
-
if (this._availableModes) {
|
|
17717
|
+
async setMode(modeId, skipAvailableChecker) {
|
|
17718
|
+
if (this._availableModes && !skipAvailableChecker) {
|
|
17648
17719
|
if (!this._availableModes.some((m) => m.id === modeId)) {
|
|
17649
17720
|
const availableIds = this._availableModes.map((m) => m.id).join(", ");
|
|
17650
17721
|
throw new Error(`Invalid modeId: "${modeId}". Available modes: ${availableIds}`);
|
|
@@ -17835,14 +17906,6 @@ var ActiveSessionImpl = class {
|
|
|
17835
17906
|
//#endregion
|
|
17836
17907
|
//#region ../agent-provider/src/common/client/session-manager.ts
|
|
17837
17908
|
/**
|
|
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
17909
|
* SessionManager - Session lifecycle management
|
|
17847
17910
|
*
|
|
17848
17911
|
* This class manages the relationship between sessions and agents.
|
|
@@ -17892,7 +17955,8 @@ var SessionManager = class {
|
|
|
17892
17955
|
createdAt: agent.createdAt,
|
|
17893
17956
|
lastActivityAt: agent.updatedAt,
|
|
17894
17957
|
cwd: agent.type === "local" ? agent.cwd : void 0,
|
|
17895
|
-
isPlayground: agent.isPlayground
|
|
17958
|
+
isPlayground: agent.isPlayground,
|
|
17959
|
+
isUserDefinedTitle: agent.isUserDefinedTitle
|
|
17896
17960
|
}));
|
|
17897
17961
|
console.log("[SessionManager] Returning sessions:", {
|
|
17898
17962
|
count: sessions.length,
|
|
@@ -17923,9 +17987,9 @@ var SessionManager = class {
|
|
|
17923
17987
|
const connection = await this.provider.connect(agentId);
|
|
17924
17988
|
this.logger?.debug(`Connected to agent: ${agentId}`);
|
|
17925
17989
|
const response = await connection.createSession({
|
|
17926
|
-
_meta: params._meta,
|
|
17990
|
+
_meta: params.options?._meta,
|
|
17927
17991
|
cwd: params.cwd,
|
|
17928
|
-
mcpServers: params.mcpServers
|
|
17992
|
+
mcpServers: params.options?.mcpServers
|
|
17929
17993
|
});
|
|
17930
17994
|
if (this.provider.registerSession) {
|
|
17931
17995
|
this.provider.registerSession(response.sessionId, agentId);
|
|
@@ -17938,14 +18002,8 @@ var SessionManager = class {
|
|
|
17938
18002
|
connectionInfo
|
|
17939
18003
|
});
|
|
17940
18004
|
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
|
-
}
|
|
18005
|
+
const availableModels = this.extractAvailableModels(response);
|
|
18006
|
+
if (availableModels) session.setModels(availableModels, response.models?.currentModelId);
|
|
17949
18007
|
this.logger?.info(`Session created: ${response.sessionId}`);
|
|
17950
18008
|
return session;
|
|
17951
18009
|
}
|
|
@@ -17981,17 +18039,31 @@ var SessionManager = class {
|
|
|
17981
18039
|
mcpServers: params.mcpServers
|
|
17982
18040
|
});
|
|
17983
18041
|
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
|
-
}
|
|
18042
|
+
const availableModels = this.extractAvailableModels(response);
|
|
18043
|
+
if (availableModels) session.setModels(availableModels, response.models?.currentModelId);
|
|
17992
18044
|
this.logger?.info(`Session loaded: ${params.sessionId}`);
|
|
17993
18045
|
return session;
|
|
17994
18046
|
}
|
|
18047
|
+
/**
|
|
18048
|
+
* 从 ACP response 中提取可用模型列表
|
|
18049
|
+
*
|
|
18050
|
+
* 优先级:
|
|
18051
|
+
* 1. response.models._meta?.['codebuddy.ai']?.availableModels - 包含完整的模型信息(字段名为 'id')
|
|
18052
|
+
* 2. response.models?.availableModels - 只包含基本信息(字段名为 'modelId')
|
|
18053
|
+
* 3. undefined - 都没有时返回 undefined
|
|
18054
|
+
*
|
|
18055
|
+
* @param response - ACP 响应对象
|
|
18056
|
+
* @returns ModelInfo[] | undefined
|
|
18057
|
+
*/
|
|
18058
|
+
extractAvailableModels(response) {
|
|
18059
|
+
const metaModels = (response.models?._meta?.["codebuddy.ai"])?.availableModels;
|
|
18060
|
+
if (metaModels && Array.isArray(metaModels) && metaModels.length > 0) return metaModels;
|
|
18061
|
+
const availableModels = response.models?.availableModels;
|
|
18062
|
+
if (availableModels && Array.isArray(availableModels) && availableModels.length > 0) return availableModels.map((model) => ({
|
|
18063
|
+
...model,
|
|
18064
|
+
...model._meta?.["codebuddy.ai"] || {}
|
|
18065
|
+
}));
|
|
18066
|
+
}
|
|
17995
18067
|
};
|
|
17996
18068
|
|
|
17997
18069
|
//#endregion
|
|
@@ -18264,6 +18336,28 @@ var AgentClient = class {
|
|
|
18264
18336
|
};
|
|
18265
18337
|
}
|
|
18266
18338
|
},
|
|
18339
|
+
getSubagentList: async (params) => {
|
|
18340
|
+
try {
|
|
18341
|
+
if (this.provider && this.provider.getSubagentList) {
|
|
18342
|
+
const result = await this.provider.getSubagentList(params);
|
|
18343
|
+
this.logger?.info("Subagent list retrieved", {
|
|
18344
|
+
resultCount: result.results.length,
|
|
18345
|
+
hasError: !!result.error
|
|
18346
|
+
});
|
|
18347
|
+
return result;
|
|
18348
|
+
}
|
|
18349
|
+
return {
|
|
18350
|
+
results: [],
|
|
18351
|
+
error: "Provider does not support getSubagentList"
|
|
18352
|
+
};
|
|
18353
|
+
} catch (error) {
|
|
18354
|
+
this.logger?.error("Failed to get subagent list", error);
|
|
18355
|
+
return {
|
|
18356
|
+
results: [],
|
|
18357
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
18358
|
+
};
|
|
18359
|
+
}
|
|
18360
|
+
},
|
|
18267
18361
|
batchTogglePlugins: async (request) => {
|
|
18268
18362
|
try {
|
|
18269
18363
|
if (this.provider && this.provider.batchTogglePlugins) {
|
|
@@ -18308,10 +18402,10 @@ var AgentClient = class {
|
|
|
18308
18402
|
return [];
|
|
18309
18403
|
}
|
|
18310
18404
|
},
|
|
18311
|
-
installPlugins: async (pluginNames, marketplaceName, installScope) => {
|
|
18405
|
+
installPlugins: async (pluginNames, marketplaceName, installScope, marketplaceSource) => {
|
|
18312
18406
|
try {
|
|
18313
18407
|
if (this.provider && "installPlugins" in this.provider && typeof this.provider.installPlugins === "function") {
|
|
18314
|
-
const result = await this.provider.installPlugins(pluginNames, marketplaceName, installScope);
|
|
18408
|
+
const result = await this.provider.installPlugins(pluginNames, marketplaceName, installScope, marketplaceSource);
|
|
18315
18409
|
this.logger?.info("Install plugins", {
|
|
18316
18410
|
pluginNames,
|
|
18317
18411
|
marketplaceName,
|
|
@@ -18332,13 +18426,9 @@ var AgentClient = class {
|
|
|
18332
18426
|
};
|
|
18333
18427
|
}
|
|
18334
18428
|
},
|
|
18335
|
-
getSupportScenes: async () => {
|
|
18429
|
+
getSupportScenes: async (locale) => {
|
|
18336
18430
|
try {
|
|
18337
|
-
if (this.provider && "getSupportScenes" in this.provider && typeof this.provider.getSupportScenes === "function")
|
|
18338
|
-
const result = await this.provider.getSupportScenes();
|
|
18339
|
-
this.logger?.info("Got support scenes", { count: result?.length ?? 0 });
|
|
18340
|
-
return result;
|
|
18341
|
-
}
|
|
18431
|
+
if (this.provider && "getSupportScenes" in this.provider && typeof this.provider.getSupportScenes === "function") return await this.provider.getSupportScenes(locale);
|
|
18342
18432
|
this.logger?.warn("Provider does not support getSupportScenes");
|
|
18343
18433
|
return [];
|
|
18344
18434
|
} catch (error) {
|
|
@@ -18346,6 +18436,69 @@ var AgentClient = class {
|
|
|
18346
18436
|
return [];
|
|
18347
18437
|
}
|
|
18348
18438
|
},
|
|
18439
|
+
getAvailableCommands: async (sessionId) => {
|
|
18440
|
+
try {
|
|
18441
|
+
if (this.provider && "getAvailableCommands" in this.provider && typeof this.provider.getAvailableCommands === "function") {
|
|
18442
|
+
const result = await this.provider.getAvailableCommands(sessionId);
|
|
18443
|
+
this.logger?.info("Got available commands from provider", {
|
|
18444
|
+
sessionId: sessionId ?? "(default)",
|
|
18445
|
+
count: result?.length ?? 0
|
|
18446
|
+
});
|
|
18447
|
+
return result;
|
|
18448
|
+
}
|
|
18449
|
+
this.logger?.warn("Provider does not support getAvailableCommands", { sessionId });
|
|
18450
|
+
return [];
|
|
18451
|
+
} catch (error) {
|
|
18452
|
+
this.logger?.error("Failed to get available commands", error);
|
|
18453
|
+
return [];
|
|
18454
|
+
}
|
|
18455
|
+
},
|
|
18456
|
+
respondToSampling: async (sessionId, response) => {
|
|
18457
|
+
try {
|
|
18458
|
+
if (this.provider?.respondToSampling) {
|
|
18459
|
+
await this.provider.respondToSampling(sessionId, response);
|
|
18460
|
+
this.logger?.info("Responded to sampling request", {
|
|
18461
|
+
sessionId,
|
|
18462
|
+
requestId: response.id,
|
|
18463
|
+
approved: response.approved
|
|
18464
|
+
});
|
|
18465
|
+
} else this.logger?.warn("Provider does not support respondToSampling");
|
|
18466
|
+
} catch (error) {
|
|
18467
|
+
this.logger?.error("Failed to respond to sampling request", error);
|
|
18468
|
+
throw error;
|
|
18469
|
+
}
|
|
18470
|
+
},
|
|
18471
|
+
respondToRoots: async (sessionId, response) => {
|
|
18472
|
+
try {
|
|
18473
|
+
if (this.provider?.respondToRoots) {
|
|
18474
|
+
await this.provider.respondToRoots(sessionId, response);
|
|
18475
|
+
this.logger?.info("Responded to roots request", {
|
|
18476
|
+
sessionId,
|
|
18477
|
+
requestId: response.id,
|
|
18478
|
+
approved: response.approved
|
|
18479
|
+
});
|
|
18480
|
+
} else this.logger?.warn("Provider does not support respondToRoots");
|
|
18481
|
+
} catch (error) {
|
|
18482
|
+
this.logger?.error("Failed to respond to roots request", error);
|
|
18483
|
+
throw error;
|
|
18484
|
+
}
|
|
18485
|
+
},
|
|
18486
|
+
subscribeSamplingRequests: (serverName, callback) => {
|
|
18487
|
+
if (this.provider?.subscribeSamplingRequests) {
|
|
18488
|
+
this.logger?.info("Subscribing to sampling requests", { serverName });
|
|
18489
|
+
return this.provider.subscribeSamplingRequests(serverName, callback);
|
|
18490
|
+
}
|
|
18491
|
+
this.logger?.warn("Provider does not support subscribeSamplingRequests");
|
|
18492
|
+
return () => {};
|
|
18493
|
+
},
|
|
18494
|
+
subscribeRootsRequests: (serverName, callback) => {
|
|
18495
|
+
if (this.provider?.subscribeRootsRequests) {
|
|
18496
|
+
this.logger?.info("Subscribing to roots requests", { serverName });
|
|
18497
|
+
return this.provider.subscribeRootsRequests(serverName, callback);
|
|
18498
|
+
}
|
|
18499
|
+
this.logger?.warn("Provider does not support subscribeRootsRequests");
|
|
18500
|
+
return () => {};
|
|
18501
|
+
},
|
|
18349
18502
|
models: this.createModelsResource()
|
|
18350
18503
|
};
|
|
18351
18504
|
}
|
|
@@ -18412,6 +18565,154 @@ let AccountStatus = /* @__PURE__ */ function(AccountStatus) {
|
|
|
18412
18565
|
return AccountStatus;
|
|
18413
18566
|
}({});
|
|
18414
18567
|
|
|
18568
|
+
//#endregion
|
|
18569
|
+
//#region ../agent-provider/src/backend/service/oauth-repository-service.ts
|
|
18570
|
+
/**
|
|
18571
|
+
* OAuth Repository Service
|
|
18572
|
+
*
|
|
18573
|
+
* 封装 OAuth 连接器相关的仓库和分支操作
|
|
18574
|
+
*/
|
|
18575
|
+
/**
|
|
18576
|
+
* OAuth Repository Service
|
|
18577
|
+
*
|
|
18578
|
+
* 提供仓库和分支的查询操作
|
|
18579
|
+
*/
|
|
18580
|
+
var OAuthRepositoryService = class {
|
|
18581
|
+
/**
|
|
18582
|
+
* 获取仓库分支列表
|
|
18583
|
+
* API 端点: GET /console/as/connector/oauth/{name}/branches
|
|
18584
|
+
*
|
|
18585
|
+
* @param connector 连接器名称 ('github' | 'gongfeng' | 'cnb')
|
|
18586
|
+
* @param params 平台特定的查询参数
|
|
18587
|
+
* @param page 页码,从1开始,0表示不分页获取全部
|
|
18588
|
+
* @param perPage 每页数量,最大100
|
|
18589
|
+
* @returns Promise<OauthBranch[]> 分支列表
|
|
18590
|
+
*
|
|
18591
|
+
* @example
|
|
18592
|
+
* ```typescript
|
|
18593
|
+
* // GitHub
|
|
18594
|
+
* const branches = await service.getBranches('github', {
|
|
18595
|
+
* owner: 'CodeBuddy-Official-Account',
|
|
18596
|
+
* repo: 'CodeBuddyIDE'
|
|
18597
|
+
* });
|
|
18598
|
+
*
|
|
18599
|
+
* // Gongfeng
|
|
18600
|
+
* const branches = await service.getBranches('gongfeng', {
|
|
18601
|
+
* project_id: '1611499'
|
|
18602
|
+
* });
|
|
18603
|
+
*
|
|
18604
|
+
* // CNB
|
|
18605
|
+
* const branches = await service.getBranches('cnb', {
|
|
18606
|
+
* repo: 'genie/genie-ide'
|
|
18607
|
+
* });
|
|
18608
|
+
* ```
|
|
18609
|
+
*/
|
|
18610
|
+
async getBranches(connector, params, page = 0, perPage = 100) {
|
|
18611
|
+
try {
|
|
18612
|
+
const url = `/console/as/connector/oauth/${connector}/branches?${this.buildBranchQueryParams(connector, params, page, perPage).toString()}`;
|
|
18613
|
+
console.log(`[OAuthRepositoryService] GET ${url}`);
|
|
18614
|
+
const apiResponse = await httpService.get(url);
|
|
18615
|
+
if (!apiResponse.data) {
|
|
18616
|
+
console.warn(`[OAuthRepositoryService] No data in branches response for ${connector}`);
|
|
18617
|
+
return [];
|
|
18618
|
+
}
|
|
18619
|
+
const branches = apiResponse.data.branches || [];
|
|
18620
|
+
console.log(`[OAuthRepositoryService] Retrieved ${branches.length} branches from ${connector}`);
|
|
18621
|
+
return branches;
|
|
18622
|
+
} catch (error) {
|
|
18623
|
+
console.error(`[OAuthRepositoryService] Failed to get branches from ${connector}:`, error);
|
|
18624
|
+
throw error;
|
|
18625
|
+
}
|
|
18626
|
+
}
|
|
18627
|
+
/**
|
|
18628
|
+
* 获取仓库列表
|
|
18629
|
+
* API 端点: GET /console/as/connector/oauth/{name}/repos
|
|
18630
|
+
*
|
|
18631
|
+
* Note: 由于工蜂原生支持的 Search 能力会匹配 path/name/description 部分,
|
|
18632
|
+
* 且不支持定制,不满足产品要求(只按 name 匹配),因此前端拉取全量数据后做筛选。
|
|
18633
|
+
*
|
|
18634
|
+
* @param connector 连接器名称 ('github' | 'gongfeng' | 'cnb')
|
|
18635
|
+
* @param page 页码,从1开始,0表示不分页获取全部
|
|
18636
|
+
* - GitHub 只支持全量数据,必须传 0
|
|
18637
|
+
* - 工蜂和 CNB 依据前端逻辑而定
|
|
18638
|
+
* @param perPage 每页数量,最大100
|
|
18639
|
+
* @returns Promise<ListReposResponse> 仓库列表响应
|
|
18640
|
+
*
|
|
18641
|
+
* @example
|
|
18642
|
+
* ```typescript
|
|
18643
|
+
* // GitHub - 必须传 page=0 获取全量数据
|
|
18644
|
+
* const response = await service.getRepositories('github', 0, 100);
|
|
18645
|
+
* // response.github_repos 是 map: installation_id => repo[]
|
|
18646
|
+
*
|
|
18647
|
+
* // Gongfeng
|
|
18648
|
+
* const response = await service.getRepositories('gongfeng', 0, 100);
|
|
18649
|
+
* // response.gongfeng_repos 是数组
|
|
18650
|
+
*
|
|
18651
|
+
* // CNB
|
|
18652
|
+
* const response = await service.getRepositories('cnb', 0, 100);
|
|
18653
|
+
* // response.cnb_repos 是数组
|
|
18654
|
+
* ```
|
|
18655
|
+
*/
|
|
18656
|
+
async getRepositories(connector, page = 0, perPage = 100) {
|
|
18657
|
+
try {
|
|
18658
|
+
const queryParams = new URLSearchParams();
|
|
18659
|
+
queryParams.append("page", String(page));
|
|
18660
|
+
queryParams.append("per_page", String(Math.min(perPage, 100)));
|
|
18661
|
+
const url = `/console/as/connector/oauth/${connector}/repos?${queryParams.toString()}`;
|
|
18662
|
+
console.log(`[OAuthRepositoryService] GET ${url}`);
|
|
18663
|
+
const apiResponse = await httpService.get(url);
|
|
18664
|
+
if (!apiResponse.data) {
|
|
18665
|
+
console.warn(`[OAuthRepositoryService] No data in repos response for ${connector}`);
|
|
18666
|
+
return {};
|
|
18667
|
+
}
|
|
18668
|
+
const response = apiResponse.data;
|
|
18669
|
+
this.logRepositoryCounts(response);
|
|
18670
|
+
return response;
|
|
18671
|
+
} catch (error) {
|
|
18672
|
+
console.error(`[OAuthRepositoryService] Failed to get repos from ${connector}:`, error);
|
|
18673
|
+
throw error;
|
|
18674
|
+
}
|
|
18675
|
+
}
|
|
18676
|
+
/**
|
|
18677
|
+
* 构建分支查询参数
|
|
18678
|
+
*/
|
|
18679
|
+
buildBranchQueryParams(connector, params, page, perPage) {
|
|
18680
|
+
const queryParams = new URLSearchParams();
|
|
18681
|
+
queryParams.append("page", String(page));
|
|
18682
|
+
queryParams.append("per_page", String(Math.min(perPage, 100)));
|
|
18683
|
+
if (connector === "github") {
|
|
18684
|
+
const githubParams = params;
|
|
18685
|
+
if (!githubParams.owner || !githubParams.repo) throw new Error("GitHub requires owner and repo parameters");
|
|
18686
|
+
queryParams.append("owner", githubParams.owner);
|
|
18687
|
+
queryParams.append("repo", githubParams.repo);
|
|
18688
|
+
} else if (connector === "gongfeng") {
|
|
18689
|
+
const gongfengParams = params;
|
|
18690
|
+
if (!gongfengParams.project_id) throw new Error("Gongfeng requires project_id parameter");
|
|
18691
|
+
queryParams.append("project_id", gongfengParams.project_id);
|
|
18692
|
+
} else if (connector === "cnb") {
|
|
18693
|
+
const cnbParams = params;
|
|
18694
|
+
if (!cnbParams.repo) throw new Error("CNB requires repo parameter");
|
|
18695
|
+
queryParams.append("repo", cnbParams.repo);
|
|
18696
|
+
} else throw new Error(`Unknown connector: ${connector}`);
|
|
18697
|
+
return queryParams;
|
|
18698
|
+
}
|
|
18699
|
+
/**
|
|
18700
|
+
* 记录仓库数量日志
|
|
18701
|
+
*/
|
|
18702
|
+
logRepositoryCounts(response) {
|
|
18703
|
+
if (response.github_repos) {
|
|
18704
|
+
const totalCount = Object.values(response.github_repos).reduce((sum, repos) => sum + repos.length, 0);
|
|
18705
|
+
console.log(`[OAuthRepositoryService] Retrieved ${totalCount} GitHub repos across ${Object.keys(response.github_repos).length} installations`);
|
|
18706
|
+
}
|
|
18707
|
+
if (response.gongfeng_repos) console.log(`[OAuthRepositoryService] Retrieved ${response.gongfeng_repos.length} Gongfeng repos`);
|
|
18708
|
+
if (response.cnb_repos) console.log(`[OAuthRepositoryService] Retrieved ${response.cnb_repos.length} CNB repos`);
|
|
18709
|
+
}
|
|
18710
|
+
};
|
|
18711
|
+
/**
|
|
18712
|
+
* OAuth Repository Service 单例实例
|
|
18713
|
+
*/
|
|
18714
|
+
const oauthRepositoryService = new OAuthRepositoryService();
|
|
18715
|
+
|
|
18415
18716
|
//#endregion
|
|
18416
18717
|
//#region ../agent-provider/src/backend/backend-provider.ts
|
|
18417
18718
|
/**
|
|
@@ -18420,27 +18721,36 @@ let AccountStatus = /* @__PURE__ */ function(AccountStatus) {
|
|
|
18420
18721
|
* 封装与后端 API 的 HTTP 通信
|
|
18421
18722
|
*/
|
|
18422
18723
|
/**
|
|
18423
|
-
*
|
|
18424
|
-
*
|
|
18724
|
+
* 判断当前账号是否是 SSO 账号
|
|
18725
|
+
* 通过 account.accountType === 'sso' 来判断,这种不行,因为未登录之前account 为空
|
|
18425
18726
|
*/
|
|
18426
18727
|
const isSSODomain = () => {
|
|
18427
18728
|
const { hostname } = window.location;
|
|
18428
18729
|
return hostname.includes(".sso.copilot") || hostname.includes("sso.codebuddy.cn") || hostname.includes(".sso.copilot-staging") || hostname.includes(".staging-sso.codebuddy.cn");
|
|
18429
18730
|
};
|
|
18731
|
+
const safeParseJSON = (jsonString) => {
|
|
18732
|
+
try {
|
|
18733
|
+
return JSON.parse(jsonString);
|
|
18734
|
+
} catch (error) {
|
|
18735
|
+
return {};
|
|
18736
|
+
}
|
|
18737
|
+
};
|
|
18430
18738
|
/**
|
|
18431
|
-
*
|
|
18432
|
-
* - SSO
|
|
18433
|
-
* - 非 SSO
|
|
18739
|
+
* 根据路径获取完整 URL
|
|
18740
|
+
* - SSO 账号需要跳转到对应的预发/生产域名
|
|
18741
|
+
* - 非 SSO 账号直接使用当前域名
|
|
18742
|
+
* @param path 路径,如 '/login'、'/logout'、'/home' 等
|
|
18743
|
+
* @returns 完整的 URL 地址
|
|
18434
18744
|
*/
|
|
18435
|
-
const
|
|
18745
|
+
const getFullUrl = (path) => {
|
|
18436
18746
|
const { hostname, protocol } = window.location;
|
|
18437
18747
|
if (isSSODomain()) {
|
|
18438
18748
|
const isCodebuddy = hostname.includes("codebuddy.cn");
|
|
18439
18749
|
const isStaging = hostname.includes("staging");
|
|
18440
|
-
if (isCodebuddy) return isStaging ? `${protocol}//staging.codebuddy.cn
|
|
18441
|
-
else return isStaging ? `${protocol}//staging-copilot.tencent.com
|
|
18750
|
+
if (isCodebuddy) return isStaging ? `${protocol}//staging.codebuddy.cn${path}` : `${protocol}//www.codebuddy.cn${path}`;
|
|
18751
|
+
else return isStaging ? `${protocol}//staging-copilot.tencent.com${path}` : `${protocol}//copilot.tencent.com${path}`;
|
|
18442
18752
|
}
|
|
18443
|
-
return `${window.location.origin}
|
|
18753
|
+
return `${window.location.origin}${path}`;
|
|
18444
18754
|
};
|
|
18445
18755
|
/** 获取当前域名的账号选择页面 URL */
|
|
18446
18756
|
const getSelectAccountUrl = () => `${window.location.origin}/login/select`;
|
|
@@ -18478,12 +18788,30 @@ var BackendProvider = class {
|
|
|
18478
18788
|
constructor(config) {
|
|
18479
18789
|
httpService.setBaseURL(config.baseUrl);
|
|
18480
18790
|
if (config.authToken) httpService.setAuthToken(config.authToken);
|
|
18481
|
-
httpService.onUnauthorized(() =>
|
|
18482
|
-
|
|
18483
|
-
|
|
18484
|
-
|
|
18791
|
+
httpService.onUnauthorized(() => this.handleUnauthorized());
|
|
18792
|
+
}
|
|
18793
|
+
/**
|
|
18794
|
+
* 处理 401 未授权错误
|
|
18795
|
+
* 先尝试刷新 token,失败后再执行登出流程
|
|
18796
|
+
*
|
|
18797
|
+
* @throws 如果 token 刷新失败,抛出错误通知 HttpService 不要重试
|
|
18798
|
+
*/
|
|
18799
|
+
async handleUnauthorized() {
|
|
18800
|
+
console.log("[BackendProvider] User unauthorized (401), attempting token refresh first");
|
|
18801
|
+
try {
|
|
18802
|
+
if (await this.refreshToken()) {
|
|
18803
|
+
console.log("[BackendProvider] Token refresh successful after 401, user still logged in");
|
|
18804
|
+
return;
|
|
18805
|
+
}
|
|
18806
|
+
throw new Error("Token refresh returned null");
|
|
18807
|
+
} catch (error) {
|
|
18808
|
+
console.error("[BackendProvider] Token refresh failed after 401:", error);
|
|
18809
|
+
console.log("[BackendProvider] Token refresh failed, triggering logout");
|
|
18810
|
+
this.logout().catch((logoutError) => {
|
|
18811
|
+
console.error("[BackendProvider] Logout failed in 401 handler:", logoutError);
|
|
18485
18812
|
});
|
|
18486
|
-
|
|
18813
|
+
throw error;
|
|
18814
|
+
}
|
|
18487
18815
|
}
|
|
18488
18816
|
/**
|
|
18489
18817
|
* 获取当前账号信息
|
|
@@ -18528,7 +18856,7 @@ var BackendProvider = class {
|
|
|
18528
18856
|
return account;
|
|
18529
18857
|
}
|
|
18530
18858
|
const redirectUrl = encodeURIComponent(window.location.href);
|
|
18531
|
-
window.location.href = `${getSelectAccountUrl()}?platform=
|
|
18859
|
+
window.location.href = `${getSelectAccountUrl()}?platform=agents&state=0&redirect_uri=${redirectUrl}`;
|
|
18532
18860
|
accountService.setAccount(null);
|
|
18533
18861
|
return null;
|
|
18534
18862
|
} catch (error) {
|
|
@@ -18551,7 +18879,8 @@ var BackendProvider = class {
|
|
|
18551
18879
|
activeStatus: connector.active_status,
|
|
18552
18880
|
displayName: connector.display_name,
|
|
18553
18881
|
oauthClientId: connector.oauth_client_id,
|
|
18554
|
-
oauthRedirectUrl: connector.oauth_redirect_url
|
|
18882
|
+
oauthRedirectUrl: connector.oauth_redirect_url,
|
|
18883
|
+
oauthAppName: connector.oauth_app_name
|
|
18555
18884
|
})) };
|
|
18556
18885
|
}
|
|
18557
18886
|
throw result;
|
|
@@ -18633,7 +18962,8 @@ var BackendProvider = class {
|
|
|
18633
18962
|
connectStatus: connector.connect_status,
|
|
18634
18963
|
displayName: connector.display_name,
|
|
18635
18964
|
oauthClientId: connector.oauth_client_id,
|
|
18636
|
-
oauthRedirectUrl: connector.oauth_redirect_url
|
|
18965
|
+
oauthRedirectUrl: connector.oauth_redirect_url,
|
|
18966
|
+
oauthAppName: connector.oauth_app_name
|
|
18637
18967
|
})) };
|
|
18638
18968
|
}
|
|
18639
18969
|
throw result;
|
|
@@ -18724,6 +19054,9 @@ var BackendProvider = class {
|
|
|
18724
19054
|
PackageCode: void 0,
|
|
18725
19055
|
name: ""
|
|
18726
19056
|
};
|
|
19057
|
+
const productFeatures = typeof window !== "undefined" && window.PRODUCT_FEATURES ? safeParseJSON(window.PRODUCT_FEATURES) : {};
|
|
19058
|
+
console.log("[PRODUCT_FEATURES]", productFeatures);
|
|
19059
|
+
if (!productFeatures.billing) return defaultPlan;
|
|
18727
19060
|
try {
|
|
18728
19061
|
const now = /* @__PURE__ */ new Date();
|
|
18729
19062
|
const futureDate = new Date(now.getTime() + 101 * 365 * 24 * 60 * 60 * 1e3);
|
|
@@ -18745,7 +19078,7 @@ var BackendProvider = class {
|
|
|
18745
19078
|
if (!time) return 0;
|
|
18746
19079
|
return new Date(time).getTime();
|
|
18747
19080
|
};
|
|
18748
|
-
const dailyCredits = [CommodityCode.free
|
|
19081
|
+
const dailyCredits = [CommodityCode.free];
|
|
18749
19082
|
const planResources = resources.map((r) => {
|
|
18750
19083
|
const isDaily = dailyCredits.includes(r.PackageCode);
|
|
18751
19084
|
const endTime = isDaily ? r.CycleEndTime : r.DeductionEndTime;
|
|
@@ -18766,10 +19099,11 @@ var BackendProvider = class {
|
|
|
18766
19099
|
CommodityCode.proMon,
|
|
18767
19100
|
CommodityCode.proMonPlus,
|
|
18768
19101
|
CommodityCode.proYear,
|
|
19102
|
+
CommodityCode.freeMon,
|
|
18769
19103
|
CommodityCode.extra
|
|
18770
19104
|
].includes(code)) return 1;
|
|
18771
19105
|
if ([CommodityCode.gift, CommodityCode.activity].includes(code)) return 2;
|
|
18772
|
-
if ([CommodityCode.free
|
|
19106
|
+
if ([CommodityCode.free].includes(code)) return 3;
|
|
18773
19107
|
return 4;
|
|
18774
19108
|
};
|
|
18775
19109
|
return getPriority(a.packageCode) - getPriority(b.packageCode);
|
|
@@ -18890,7 +19224,7 @@ var BackendProvider = class {
|
|
|
18890
19224
|
*/
|
|
18891
19225
|
async login() {
|
|
18892
19226
|
const redirectUrl = encodeURIComponent(window.location.href);
|
|
18893
|
-
window.location.href = `${
|
|
19227
|
+
window.location.href = `${getFullUrl("/login")}?platform=agents&state=0&redirect_uri=${redirectUrl}`;
|
|
18894
19228
|
}
|
|
18895
19229
|
/**
|
|
18896
19230
|
* 登出账号
|
|
@@ -18953,6 +19287,52 @@ var BackendProvider = class {
|
|
|
18953
19287
|
return null;
|
|
18954
19288
|
}
|
|
18955
19289
|
}
|
|
19290
|
+
/**
|
|
19291
|
+
* 刷新 Token
|
|
19292
|
+
* 通过调用 getAccount 刷新 cookie,适用于 Cloud 场景下页面切换回来时刷新登录态
|
|
19293
|
+
* @returns Promise<Account | null> 刷新后的账号信息
|
|
19294
|
+
*/
|
|
19295
|
+
async refreshToken() {
|
|
19296
|
+
console.log("[BackendProvider] Refreshing token...");
|
|
19297
|
+
try {
|
|
19298
|
+
const account = await this.getAccount();
|
|
19299
|
+
console.log("[BackendProvider] Token refreshed, account:", account?.uid);
|
|
19300
|
+
return account;
|
|
19301
|
+
} catch (error) {
|
|
19302
|
+
console.error("[BackendProvider] refreshToken failed:", error);
|
|
19303
|
+
return null;
|
|
19304
|
+
}
|
|
19305
|
+
}
|
|
19306
|
+
/**
|
|
19307
|
+
* 获取仓库分支列表
|
|
19308
|
+
* API 端点: GET /console/as/connector/oauth/{name}/branches
|
|
19309
|
+
*
|
|
19310
|
+
* @param connector 连接器名称 ('github' | 'gongfeng' | 'cnb')
|
|
19311
|
+
* @param params 平台特定的查询参数
|
|
19312
|
+
* @param page 页码,从1开始,0表示不分页获取全部
|
|
19313
|
+
* @param perPage 每页数量,最大100
|
|
19314
|
+
* @returns Promise<OauthBranch[]> 分支列表
|
|
19315
|
+
*/
|
|
19316
|
+
async getBranches(connector, params, page = 0, perPage = 100) {
|
|
19317
|
+
return oauthRepositoryService.getBranches(connector, params, page, perPage);
|
|
19318
|
+
}
|
|
19319
|
+
/**
|
|
19320
|
+
* 获取仓库列表
|
|
19321
|
+
* API 端点: GET /console/as/connector/oauth/{name}/repos
|
|
19322
|
+
*
|
|
19323
|
+
* Note: 由于工蜂原生支持的 Search 能力会匹配 path/name/description 部分,
|
|
19324
|
+
* 且不支持定制,不满足产品要求(只按 name 匹配),因此前端拉取全量数据后做筛选。
|
|
19325
|
+
*
|
|
19326
|
+
* @param connector 连接器名称 ('github' | 'gongfeng' | 'cnb')
|
|
19327
|
+
* @param page 页码,从1开始,0表示不分页获取全部
|
|
19328
|
+
* - GitHub 只支持全量数据,必须传 0
|
|
19329
|
+
* - 工蜂和 CNB 依据前端逻辑而定
|
|
19330
|
+
* @param perPage 每页数量,最大100
|
|
19331
|
+
* @returns Promise<ListReposResponse> 仓库列表响应
|
|
19332
|
+
*/
|
|
19333
|
+
async getRepositories(connector, page = 0, perPage = 100) {
|
|
19334
|
+
return oauthRepositoryService.getRepositories(connector, page, perPage);
|
|
19335
|
+
}
|
|
18956
19336
|
};
|
|
18957
19337
|
/**
|
|
18958
19338
|
* 创建 BackendProvider 实例
|
|
@@ -18992,6 +19372,7 @@ const BACKEND_REQUEST_TYPES = {
|
|
|
18992
19372
|
GET_FILE: "backend:get-file",
|
|
18993
19373
|
RELOAD_WINDOW: "backend:reload-window",
|
|
18994
19374
|
CLOSE_AGENT_MANAGER: "backend:close-agent-manager",
|
|
19375
|
+
OPEN_EXTERNAL: "backend:open-external",
|
|
18995
19376
|
BATCH_TOGGLE_PLUGINS: "backend:batch-toggle-plugins",
|
|
18996
19377
|
GET_SUPPORT_SCENES: "backend:get-support-scenes"
|
|
18997
19378
|
};
|
|
@@ -19287,6 +19668,20 @@ var IPCBackendProvider = class {
|
|
|
19287
19668
|
}
|
|
19288
19669
|
}
|
|
19289
19670
|
/**
|
|
19671
|
+
* 在外部浏览器中打开链接
|
|
19672
|
+
* IDE 环境: 通过 IPC 通知 IDE 使用 vscode.env.openExternal 打开 URL
|
|
19673
|
+
* @param url 要打开的 URL
|
|
19674
|
+
*/
|
|
19675
|
+
async openExternal(url) {
|
|
19676
|
+
this.log("Opening external URL via IPC:", url);
|
|
19677
|
+
try {
|
|
19678
|
+
await this.sendBackendRequest(BACKEND_REQUEST_TYPES.OPEN_EXTERNAL, { url });
|
|
19679
|
+
} catch (error) {
|
|
19680
|
+
this.log("Open external request failed:", error);
|
|
19681
|
+
throw error;
|
|
19682
|
+
}
|
|
19683
|
+
}
|
|
19684
|
+
/**
|
|
19290
19685
|
* 批量切换插件状态
|
|
19291
19686
|
* IDE 环境: 通过 IPC 调用 Extension Host 的 PluginService
|
|
19292
19687
|
*/
|