@tencent-ai/cloud-agent-sdk 0.2.13 → 0.2.14-next.17885cf.20260323

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -39,6 +39,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
39
39
  }) : target, mod));
40
40
 
41
41
  //#endregion
42
+ const require_e2b_filesystem = require('./e2b-filesystem-4-LU6-jg.cjs');
42
43
  let zod = require("zod");
43
44
  let _agentclientprotocol_sdk = require("@agentclientprotocol/sdk");
44
45
  require("@bufbuild/protobuf");
@@ -59,7 +60,6 @@ crypto = __toESM(crypto);
59
60
  let zlib = require("zlib");
60
61
  zlib = __toESM(zlib);
61
62
  let events = require("events");
62
- let e2b = require("e2b");
63
63
 
64
64
  //#region ../agent-provider/src/common/_legacy/tool-schemas.ts
65
65
  /**
@@ -93,7 +93,6 @@ const ToolInputSchemas = {
93
93
  queryString: zod.z.string().describe("用户的实际问题或搜索查询"),
94
94
  knowledgeBaseNames: zod.z.string().describe("知识库名称,多个用逗号分隔")
95
95
  }),
96
- read_rules: zod.z.object({ ruleNames: zod.z.string().describe("要读取的规则关键词,用逗号分隔,格式:{ruleName}_{ruleId}") }),
97
96
  mcp_get_tool_description: zod.z.object({ toolRequests: zod.z.string().describe("JSON 字符串,二维数组格式:[[\"server1\", \"tool1\"], [\"server2\", \"tool2\"]]") }),
98
97
  mcp_call_tool: zod.z.object({
99
98
  serverName: zod.z.string().describe("MCP 服务器名称"),
@@ -107,13 +106,6 @@ const ToolInputSchemas = {
107
106
  arguments: zod.z.record(zod.z.unknown()).optional().describe("资源模板的参数"),
108
107
  downloadPath: zod.z.string().optional().describe("可选的绝对路径,用于保存资源到磁盘")
109
108
  }),
110
- create_rule: zod.z.object({
111
- ruleScope: zod.z.string().describe("规则范围,project rule 或 user rule"),
112
- ruleName: zod.z.string().describe("规则文件名,不带扩展名"),
113
- ruleType: zod.z.string().describe("规则类型,always、manual 或 requested"),
114
- ruleContent: zod.z.string().describe("规则内容,使用 Markdown 格式"),
115
- ruleDescription: zod.z.string().optional().describe("规则描述,使用 Markdown 格式")
116
- }),
117
109
  update_memory: zod.z.object({
118
110
  action: zod.z.enum([
119
111
  "create",
@@ -172,7 +164,6 @@ const ToolInputSchemas = {
172
164
  cloud_studio_fetch_log: zod.z.object({}).passthrough(),
173
165
  cloud_studio_execute_command: zod.z.object({}).passthrough(),
174
166
  cloud_studio_deploy_sandbox: zod.z.object({}).passthrough(),
175
- component_get_prompt: zod.z.object({}).passthrough(),
176
167
  web_fetch: zod.z.object({
177
168
  url: zod.z.string().describe("要获取内容的 URL"),
178
169
  fetchInfo: zod.z.string().describe("用户想要获取的信息描述")
@@ -180,7 +171,9 @@ const ToolInputSchemas = {
180
171
  use_skill: zod.z.object({ command: zod.z.string().describe("技能名称(不含参数),如 \"pdf\" 或 \"xlsx\"") }),
181
172
  web_search: zod.z.object({
182
173
  explanation: zod.z.string().describe("为什么使用此工具的一句话解释"),
183
- searchTerm: zod.z.string().describe("要在网络上搜索的搜索词")
174
+ query: zod.z.string().describe("搜索关键词"),
175
+ max_results: zod.z.number().optional().describe("最大返回数量"),
176
+ language: zod.z.string().optional().describe("语言代码,例如 zh-CN")
184
177
  }),
185
178
  task: zod.z.object({
186
179
  subagent_name: zod.z.string().describe("要调用的子代理名称"),
@@ -258,11 +251,6 @@ const ToolOutputSchemas = {
258
251
  selectedKnowledgeBases: zod.z.string(),
259
252
  queryInput: zod.z.string()
260
253
  }),
261
- read_rules: zod.z.object({
262
- type: zod.z.literal("rule_match_result"),
263
- ruleDescription: zod.z.string(),
264
- filePaths: zod.z.array(zod.z.string())
265
- }),
266
254
  mcp_get_tool_description: zod.z.object({}).passthrough(),
267
255
  mcp_call_tool: zod.z.object({
268
256
  type: zod.z.literal("mcp_call_tool_result"),
@@ -299,17 +287,6 @@ const ToolOutputSchemas = {
299
287
  content: zod.z.string(),
300
288
  downloadPath: zod.z.string().optional()
301
289
  }),
302
- create_rule: zod.z.object({
303
- type: zod.z.literal("rule_create_result"),
304
- ruleName: zod.z.string(),
305
- createState: zod.z.enum([
306
- "success",
307
- "invoke",
308
- "cancelled"
309
- ]),
310
- hint: zod.z.string().optional(),
311
- filePath: zod.z.string().optional()
312
- }),
313
290
  update_memory: zod.z.object({
314
291
  type: zod.z.literal("update_memory_result"),
315
292
  success: zod.z.boolean(),
@@ -323,9 +300,9 @@ const ToolOutputSchemas = {
323
300
  }),
324
301
  search_content: zod.z.object({
325
302
  type: zod.z.literal("search_content_result"),
326
- directory: zod.z.string(),
303
+ path: zod.z.string(),
327
304
  pattern: zod.z.string(),
328
- fileTypes: zod.z.string(),
305
+ glob: zod.z.string(),
329
306
  matches: zod.z.array(zod.z.object({
330
307
  filePath: zod.z.string(),
331
308
  content: zod.z.string(),
@@ -337,7 +314,7 @@ const ToolOutputSchemas = {
337
314
  totalCount: zod.z.number(),
338
315
  hasMore: zod.z.boolean(),
339
316
  offset: zod.z.number(),
340
- limit: zod.z.number(),
317
+ headLimit: zod.z.number(),
341
318
  contextBefore: zod.z.number(),
342
319
  contextAfter: zod.z.number(),
343
320
  contextAround: zod.z.number().optional(),
@@ -523,15 +500,6 @@ const ToolOutputSchemas = {
523
500
  }).optional()
524
501
  }))
525
502
  }),
526
- component_get_prompt: zod.z.object({
527
- type: zod.z.literal("component_get_prompt_result"),
528
- componentType: zod.z.string(),
529
- webFramework: zod.z.string(),
530
- data: zod.z.object({
531
- type: zod.z.literal("text"),
532
- text: zod.z.string()
533
- })
534
- }),
535
503
  web_fetch: zod.z.object({
536
504
  type: zod.z.literal("web_fetch_tool_result"),
537
505
  message: zod.z.string(),
@@ -547,14 +515,29 @@ const ToolOutputSchemas = {
547
515
  }),
548
516
  web_search: zod.z.object({
549
517
  type: zod.z.literal("web_search_tool_result"),
550
- data: zod.z.array(zod.z.object({
551
- passage: zod.z.string(),
552
- uri: zod.z.string(),
553
- site: zod.z.string(),
518
+ query: zod.z.string().optional(),
519
+ searchType: zod.z.literal("text2text").optional(),
520
+ provider: zod.z.string().optional(),
521
+ results: zod.z.array(zod.z.object({
554
522
  title: zod.z.string(),
555
- snippets: zod.z.array(zod.z.string()).optional(),
556
- content: zod.z.string().optional()
523
+ url: zod.z.string(),
524
+ snippet: zod.z.string().optional(),
525
+ site: zod.z.string().optional(),
526
+ highlights: zod.z.array(zod.z.string()).optional(),
527
+ content: zod.z.string().optional(),
528
+ favicon: zod.z.string().optional()
557
529
  })),
530
+ images: zod.z.array(zod.z.object({
531
+ url: zod.z.string(),
532
+ description: zod.z.string().optional(),
533
+ sourceUrl: zod.z.string().optional(),
534
+ width: zod.z.number().optional(),
535
+ height: zod.z.number().optional(),
536
+ title: zod.z.string().optional(),
537
+ siteName: zod.z.string().optional()
538
+ })),
539
+ totalResults: zod.z.number().optional(),
540
+ responseTimeMs: zod.z.number().optional(),
558
541
  searchInput: zod.z.string().optional()
559
542
  }),
560
543
  task: zod.z.object({
@@ -700,7 +683,11 @@ const ExtensionMethod = {
700
683
  CHECKPOINT: "_codebuddy.ai/checkpoint",
701
684
  USAGE: "_codebuddy.ai/usage",
702
685
  COMMAND: "_codebuddy.ai/command",
703
- AUTH_URL: "_codebuddy.ai/authUrl"
686
+ AUTH_URL: "_codebuddy.ai/authUrl",
687
+ FILE_HISTORY_SNAPSHOT: "_codebuddy.ai/file_history_snapshot",
688
+ DELEGATE_TOOL: "_codebuddy.ai/delegateTool",
689
+ DELEGATE_TOOLS_CHANGED: "_codebuddy.ai/delegateToolsChanged",
690
+ UI_CONTROL: "_codebuddy.ai/uiControl"
704
691
  };
705
692
  /**
706
693
  * All known extension methods
@@ -711,7 +698,10 @@ const KNOWN_EXTENSIONS = [
711
698
  ExtensionMethod.CHECKPOINT,
712
699
  ExtensionMethod.USAGE,
713
700
  ExtensionMethod.COMMAND,
714
- ExtensionMethod.AUTH_URL
701
+ ExtensionMethod.AUTH_URL,
702
+ ExtensionMethod.FILE_HISTORY_SNAPSHOT,
703
+ ExtensionMethod.DELEGATE_TOOL,
704
+ ExtensionMethod.DELEGATE_TOOLS_CHANGED
715
705
  ];
716
706
 
717
707
  //#endregion
@@ -762,7 +752,7 @@ function parseSSELine(line, currentEvent) {
762
752
  };
763
753
  }
764
754
  function streamableHttp(options) {
765
- const { endpoint, authToken, headers: customHeaders = {}, reconnect = {}, signal: externalSignal, fetch: customFetch = globalThis.fetch, onConnect, onDisconnect, onError, heartbeatTimeout = 6e4, postTimeout = 3e4, backpressure = {} } = options;
755
+ const { endpoint, authToken, headers: customHeaders = {}, reconnect = {}, signal: externalSignal, fetch: customFetch = globalThis.fetch, onConnect, onDisconnect, onError, heartbeatTimeout = 6e4, connectionTimeout = 3e4, postTimeout = 3e4, backpressure = {} } = options;
766
756
  const { enabled: reconnectEnabled = true, initialDelay = 1e3, maxDelay = 3e4, maxRetries = Infinity, jitter: jitterEnabled = true } = reconnect;
767
757
  const { highWaterMark = 100, lowWaterMark = 50, pauseTimeout = 5e3 } = backpressure;
768
758
  let connectionId;
@@ -973,11 +963,21 @@ function streamableHttp(options) {
973
963
  const headers = buildHeaders();
974
964
  headers["Accept"] = "text/event-stream";
975
965
  if (lastEventId) headers["Last-Event-ID"] = lastEventId;
976
- const response = await customFetch(endpoint, {
977
- method: "GET",
978
- headers,
979
- signal: combinedSignal
980
- });
966
+ const connectTimeoutMs = connectionTimeout > 0 ? connectionTimeout : 3e4;
967
+ const connectController = new AbortController();
968
+ const connectTimer = setTimeout(() => connectController.abort(), connectTimeoutMs);
969
+ if (externalSignal) externalSignal.addEventListener("abort", () => connectController.abort(), { once: true });
970
+ abortController.signal.addEventListener("abort", () => connectController.abort(), { once: true });
971
+ let response;
972
+ try {
973
+ response = await customFetch(endpoint, {
974
+ method: "GET",
975
+ headers,
976
+ signal: connectController.signal
977
+ });
978
+ } finally {
979
+ clearTimeout(connectTimer);
980
+ }
981
981
  if (!response.ok) throw new Error(`HTTP ${response.status}`);
982
982
  const newConnectionId = response.headers.get("Acp-Connection-Id");
983
983
  if (!newConnectionId) throw new Error("Server did not return Acp-Connection-Id header");
@@ -1182,6 +1182,10 @@ var ArtifactManager = class {
1182
1182
  */
1183
1183
  const DEFAULT_INITIALIZE_TIMEOUT = 3e4;
1184
1184
  /**
1185
+ * Default timeout for session/new operation (waiting for sessionId via SSE)
1186
+ */
1187
+ const DEFAULT_SESSION_TIMEOUT = 3e4;
1188
+ /**
1185
1189
  * Default timeout for permission requests
1186
1190
  */
1187
1191
  const DEFAULT_PERMISSION_TIMEOUT = 3e5;
@@ -1237,8 +1241,14 @@ var InitializationError = class extends ACPClientError {
1237
1241
  * Error thrown for session-related failures
1238
1242
  */
1239
1243
  var SessionError = class extends ACPClientError {
1240
- constructor(message, sessionId, cause) {
1241
- super(message, "SESSION_ERROR", cause);
1244
+ constructor(message, sessionId, agentIdOrCause, cause) {
1245
+ if (agentIdOrCause instanceof Error) {
1246
+ super(message, "SESSION_ERROR", agentIdOrCause);
1247
+ this.agentId = void 0;
1248
+ } else {
1249
+ super(message, "SESSION_ERROR", cause);
1250
+ this.agentId = agentIdOrCause;
1251
+ }
1242
1252
  this.name = "SessionError";
1243
1253
  this.sessionId = sessionId;
1244
1254
  }
@@ -1913,6 +1923,9 @@ var StreamableHttpClient = class {
1913
1923
  headers: this.options.headers,
1914
1924
  reconnect: this.options.reconnect,
1915
1925
  fetch: this.options.fetch,
1926
+ heartbeatTimeout: this.options.heartbeatTimeout,
1927
+ postTimeout: this.options.postTimeout,
1928
+ connectionTimeout: this.options.connectionTimeout,
1916
1929
  onConnect: (connectionId) => {
1917
1930
  this.options.logger?.debug(`Transport connected: ${connectionId}`);
1918
1931
  },
@@ -1987,10 +2000,6 @@ var StreamableHttpClient = class {
1987
2000
  },
1988
2001
  requestPermission: async (params) => this.handleRequestPermission(params),
1989
2002
  extNotification: async (method, params) => {
1990
- console.log("[ACP-Client] extNotification callback invoked:", {
1991
- method,
1992
- paramsKeys: Object.keys(params)
1993
- });
1994
2003
  await this.handleExtNotification(method, params);
1995
2004
  },
1996
2005
  extMethod: async (method, params) => this.handleExtMethod(method, params)
@@ -1998,19 +2007,47 @@ var StreamableHttpClient = class {
1998
2007
  }
1999
2008
  /**
2000
2009
  * Create a new session
2010
+ *
2011
+ * Retries on transient network errors (e.g., proxy connection reset)
2012
+ * since session/new is idempotent and safe to retry.
2013
+ *
2014
+ * A timeout (`options.sessionTimeout`, default 30 s) guards against the
2015
+ * SSE response never arriving — the POST returns 202 immediately and the
2016
+ * sessionId comes back via GET SSE, which can hang indefinitely.
2017
+ * On timeout a `SessionError` is thrown.
2001
2018
  */
2002
2019
  async createSession(cwd) {
2003
2020
  this.ensureInitialized("createSession");
2004
- try {
2005
- const response = await this.connection.newSession({
2021
+ const maxRetries = 2;
2022
+ const timeout = this.options.sessionTimeout ?? DEFAULT_SESSION_TIMEOUT;
2023
+ let lastError;
2024
+ for (let attempt = 0; attempt <= maxRetries; attempt++) try {
2025
+ const sessionPromise = this.connection.newSession({
2006
2026
  cwd,
2007
2027
  mcpServers: []
2008
2028
  });
2029
+ let response;
2030
+ if (timeout > 0) {
2031
+ const timeoutPromise = new Promise((_, reject) => {
2032
+ setTimeout(() => {
2033
+ reject(new SessionError(`session/new timed out after ${timeout}ms`));
2034
+ }, timeout);
2035
+ });
2036
+ response = await Promise.race([sessionPromise, timeoutPromise]);
2037
+ } else response = await sessionPromise;
2009
2038
  this.options.logger?.info(`Session created: ${response.sessionId}`);
2010
2039
  return response;
2011
2040
  } catch (err) {
2012
- throw new SessionError(`Failed to create session: ${err instanceof Error ? err.message : String(err)}`, void 0, err instanceof Error ? err : void 0);
2041
+ lastError = err instanceof Error ? err : new Error(String(err));
2042
+ if (attempt < maxRetries && isRetryableNetworkError(err)) {
2043
+ const delay = 500 * Math.pow(2, attempt);
2044
+ this.options.logger?.warn(`session/new network error, retrying in ${delay}ms (attempt ${attempt + 1}/${maxRetries}): ${lastError.message}`);
2045
+ await new Promise((resolve) => setTimeout(resolve, delay));
2046
+ continue;
2047
+ }
2048
+ throw new SessionError(`Failed to create session: ${lastError.message}`, void 0, lastError);
2013
2049
  }
2050
+ throw new SessionError(`Failed to create session: ${lastError?.message}`, void 0, lastError);
2014
2051
  }
2015
2052
  /**
2016
2053
  * Load an existing session
@@ -2234,6 +2271,18 @@ var StreamableHttpClient = class {
2234
2271
  if (this.state !== "initialized") throw new InvalidStateError(operation, this.state, ["initialized"]);
2235
2272
  }
2236
2273
  };
2274
+ /**
2275
+ * Check if an error is a retryable network-level error.
2276
+ * Only network failures (TypeError from fetch) are retried, NOT HTTP errors (4xx/5xx).
2277
+ */
2278
+ function isRetryableNetworkError(error) {
2279
+ if (error instanceof TypeError) return true;
2280
+ if (error instanceof Error) {
2281
+ const msg = error.message.toLowerCase();
2282
+ return msg.includes("failed to fetch") || msg.includes("fetch failed") || msg.includes("network request failed") || msg.includes("econnreset") || msg.includes("econnrefused") || msg.includes("socket hang up");
2283
+ }
2284
+ return false;
2285
+ }
2237
2286
 
2238
2287
  //#endregion
2239
2288
  //#region ../agent-provider/src/common/providers/cloud-agent-provider/cloud-connection.ts
@@ -2269,7 +2318,7 @@ var CloudAgentConnection = class {
2269
2318
  fetch: config.fetch,
2270
2319
  clientCapabilities: config.clientCapabilities,
2271
2320
  onSessionUpdate: (update) => {
2272
- if (!this._isStreaming) this.emit("sessionUpdate", update);
2321
+ if (!this._isStreaming && this.isOwnSessionNotification(update)) this.emit("sessionUpdate", update);
2273
2322
  },
2274
2323
  onArtifact: (artifact, event) => {
2275
2324
  console.log("[CloudConnection] onArtifact callback:", {
@@ -2283,10 +2332,41 @@ var CloudAgentConnection = class {
2283
2332
  },
2284
2333
  onUsageUpdate: (usage) => {
2285
2334
  this.emit("usageUpdate", usage);
2335
+ },
2336
+ onExtNotification: (method, params) => {
2337
+ console.log("[CloudConnection] Received extNotification:", {
2338
+ method,
2339
+ paramsKeys: Object.keys(params)
2340
+ });
2341
+ if (method === ExtensionMethod.COMMAND) {
2342
+ const action = params.action;
2343
+ const commandParams = params.params;
2344
+ console.log("[CloudConnection] Emitting command event:", {
2345
+ action,
2346
+ paramsKeys: commandParams ? Object.keys(commandParams) : []
2347
+ });
2348
+ this.emit("command", {
2349
+ action,
2350
+ params: commandParams
2351
+ });
2352
+ }
2286
2353
  }
2287
2354
  });
2288
2355
  this.setupEventForwarding();
2289
2356
  }
2357
+ /**
2358
+ * Check whether a notification belongs to this connection's own session.
2359
+ *
2360
+ * CloudConnection.createSession() overrides sessionId to agentId, so the
2361
+ * rest of the client stack uses agentId as the canonical session
2362
+ * identifier. Notifications whose sessionId differs from agentId
2363
+ * originate from sub-agent sessions running inside the same sandbox and
2364
+ * should be silently ignored at this layer — the adapter layer handles
2365
+ * sub-agent messages independently via parentToolUseId in _meta.
2366
+ */
2367
+ isOwnSessionNotification(notification) {
2368
+ return notification.sessionId === this.agentId;
2369
+ }
2290
2370
  setupEventForwarding() {
2291
2371
  this.client.on("connecting", () => {
2292
2372
  this.emit("connecting", void 0);
@@ -2447,6 +2527,7 @@ var CloudAgentConnection = class {
2447
2527
  let resolveUpdate = null;
2448
2528
  let done = false;
2449
2529
  const listener = (update) => {
2530
+ if (!this.isOwnSessionNotification(update)) return;
2450
2531
  if (resolveUpdate) {
2451
2532
  resolveUpdate(update);
2452
2533
  resolveUpdate = null;
@@ -2529,6 +2610,16 @@ var CloudAgentConnection = class {
2529
2610
  get sessionConnectionInfo() {
2530
2611
  return this._sessionConnectionInfo;
2531
2612
  }
2613
+ async reportTelemetry(eventName, payload) {
2614
+ try {
2615
+ await this.client.extMethod("reportTelemetry", {
2616
+ eventName,
2617
+ payload
2618
+ });
2619
+ } catch (error) {
2620
+ console.warn("[CloudAgentConnection] reportTelemetry failed:", error);
2621
+ }
2622
+ }
2532
2623
  async extMethod(method, params) {
2533
2624
  return this.client.extMethod(method, params);
2534
2625
  }
@@ -3131,7 +3222,7 @@ var utils_default = {
3131
3222
  *
3132
3223
  * @returns {Error} The created error.
3133
3224
  */
3134
- function AxiosError(message, code, config, request, response) {
3225
+ function AxiosError$1(message, code, config, request, response) {
3135
3226
  Error.call(this);
3136
3227
  if (Error.captureStackTrace) Error.captureStackTrace(this, this.constructor);
3137
3228
  else this.stack = (/* @__PURE__ */ new Error()).stack;
@@ -3145,7 +3236,7 @@ function AxiosError(message, code, config, request, response) {
3145
3236
  this.status = response.status ? response.status : null;
3146
3237
  }
3147
3238
  }
3148
- utils_default.inherits(AxiosError, Error, { toJSON: function toJSON() {
3239
+ utils_default.inherits(AxiosError$1, Error, { toJSON: function toJSON() {
3149
3240
  return {
3150
3241
  message: this.message,
3151
3242
  name: this.name,
@@ -3160,7 +3251,7 @@ utils_default.inherits(AxiosError, Error, { toJSON: function toJSON() {
3160
3251
  status: this.status
3161
3252
  };
3162
3253
  } });
3163
- const prototype$1 = AxiosError.prototype;
3254
+ const prototype$1 = AxiosError$1.prototype;
3164
3255
  const descriptors = {};
3165
3256
  [
3166
3257
  "ERR_BAD_OPTION_VALUE",
@@ -3178,22 +3269,22 @@ const descriptors = {};
3178
3269
  ].forEach((code) => {
3179
3270
  descriptors[code] = { value: code };
3180
3271
  });
3181
- Object.defineProperties(AxiosError, descriptors);
3272
+ Object.defineProperties(AxiosError$1, descriptors);
3182
3273
  Object.defineProperty(prototype$1, "isAxiosError", { value: true });
3183
- AxiosError.from = (error, code, config, request, response, customProps) => {
3274
+ AxiosError$1.from = (error, code, config, request, response, customProps) => {
3184
3275
  const axiosError = Object.create(prototype$1);
3185
3276
  utils_default.toFlatObject(error, axiosError, function filter(obj) {
3186
3277
  return obj !== Error.prototype;
3187
3278
  }, (prop) => {
3188
3279
  return prop !== "isAxiosError";
3189
3280
  });
3190
- AxiosError.call(axiosError, error.message, code, config, request, response);
3281
+ AxiosError$1.call(axiosError, error.message, code, config, request, response);
3191
3282
  axiosError.cause = error;
3192
3283
  axiosError.name = error.name;
3193
3284
  customProps && Object.assign(axiosError, customProps);
3194
3285
  return axiosError;
3195
3286
  };
3196
- var AxiosError_default = AxiosError;
3287
+ var AxiosError_default = AxiosError$1;
3197
3288
 
3198
3289
  //#endregion
3199
3290
  //#region ../../node_modules/delayed-stream/lib/delayed_stream.js
@@ -11920,7 +12011,7 @@ const predicates = utils_default.toFlatObject(utils_default, {}, null, function
11920
12011
  *
11921
12012
  * @returns
11922
12013
  */
11923
- function toFormData(obj, formData, options) {
12014
+ function toFormData$1(obj, formData, options) {
11924
12015
  if (!utils_default.isObject(obj)) throw new TypeError("target must be an object");
11925
12016
  formData = formData || new (FormData_default || FormData)();
11926
12017
  options = utils_default.toFlatObject(options, {
@@ -11991,7 +12082,7 @@ function toFormData(obj, formData, options) {
11991
12082
  build(obj);
11992
12083
  return formData;
11993
12084
  }
11994
- var toFormData_default = toFormData;
12085
+ var toFormData_default = toFormData$1;
11995
12086
 
11996
12087
  //#endregion
11997
12088
  //#region ../agent-provider/node_modules/axios/lib/helpers/AxiosURLSearchParams.js
@@ -12515,7 +12606,7 @@ function buildAccessors(obj, header) {
12515
12606
  });
12516
12607
  });
12517
12608
  }
12518
- var AxiosHeaders = class {
12609
+ var AxiosHeaders$1 = class {
12519
12610
  constructor(headers) {
12520
12611
  headers && this.set(headers);
12521
12612
  }
@@ -12653,7 +12744,7 @@ var AxiosHeaders = class {
12653
12744
  return this;
12654
12745
  }
12655
12746
  };
12656
- AxiosHeaders.accessor([
12747
+ AxiosHeaders$1.accessor([
12657
12748
  "Content-Type",
12658
12749
  "Content-Length",
12659
12750
  "Accept",
@@ -12661,7 +12752,7 @@ AxiosHeaders.accessor([
12661
12752
  "User-Agent",
12662
12753
  "Authorization"
12663
12754
  ]);
12664
- utils_default.reduceDescriptors(AxiosHeaders.prototype, ({ value }, key) => {
12755
+ utils_default.reduceDescriptors(AxiosHeaders$1.prototype, ({ value }, key) => {
12665
12756
  let mapped = key[0].toUpperCase() + key.slice(1);
12666
12757
  return {
12667
12758
  get: () => value,
@@ -12670,8 +12761,8 @@ utils_default.reduceDescriptors(AxiosHeaders.prototype, ({ value }, key) => {
12670
12761
  }
12671
12762
  };
12672
12763
  });
12673
- utils_default.freezeMethods(AxiosHeaders);
12674
- var AxiosHeaders_default = AxiosHeaders;
12764
+ utils_default.freezeMethods(AxiosHeaders$1);
12765
+ var AxiosHeaders_default = AxiosHeaders$1;
12675
12766
 
12676
12767
  //#endregion
12677
12768
  //#region ../agent-provider/node_modules/axios/lib/core/transformData.js
@@ -12697,7 +12788,7 @@ function transformData(fns, response) {
12697
12788
 
12698
12789
  //#endregion
12699
12790
  //#region ../agent-provider/node_modules/axios/lib/cancel/isCancel.js
12700
- function isCancel(value) {
12791
+ function isCancel$1(value) {
12701
12792
  return !!(value && value.__CANCEL__);
12702
12793
  }
12703
12794
 
@@ -12712,12 +12803,12 @@ function isCancel(value) {
12712
12803
  *
12713
12804
  * @returns {CanceledError} The created error.
12714
12805
  */
12715
- function CanceledError(message, config, request) {
12806
+ function CanceledError$1(message, config, request) {
12716
12807
  AxiosError_default.call(this, message == null ? "canceled" : message, AxiosError_default.ERR_CANCELED, config, request);
12717
12808
  this.name = "CanceledError";
12718
12809
  }
12719
- utils_default.inherits(CanceledError, AxiosError_default, { __CANCEL__: true });
12720
- var CanceledError_default = CanceledError;
12810
+ utils_default.inherits(CanceledError$1, AxiosError_default, { __CANCEL__: true });
12811
+ var CanceledError_default = CanceledError$1;
12721
12812
 
12722
12813
  //#endregion
12723
12814
  //#region ../agent-provider/node_modules/axios/lib/core/settle.js
@@ -14119,7 +14210,9 @@ var require_follow_redirects = /* @__PURE__ */ __commonJSMin(((exports, module)
14119
14210
 
14120
14211
  //#endregion
14121
14212
  //#region ../agent-provider/node_modules/axios/lib/env/data.js
14122
- const VERSION = "1.10.0";
14213
+ var import_follow_redirects = /* @__PURE__ */ __toESM(require_follow_redirects(), 1);
14214
+ var import_proxy_from_env = /* @__PURE__ */ __toESM(require_proxy_from_env(), 1);
14215
+ const VERSION$1 = "1.10.0";
14123
14216
 
14124
14217
  //#endregion
14125
14218
  //#region ../agent-provider/node_modules/axios/lib/helpers/parseProtocol.js
@@ -14482,8 +14575,6 @@ const asyncDecorator = (fn) => (...args) => utils_default.asap(() => fn(...args)
14482
14575
 
14483
14576
  //#endregion
14484
14577
  //#region ../agent-provider/node_modules/axios/lib/adapters/http.js
14485
- var import_proxy_from_env = /* @__PURE__ */ __toESM(require_proxy_from_env(), 1);
14486
- var import_follow_redirects = /* @__PURE__ */ __toESM(require_follow_redirects(), 1);
14487
14578
  const zlibOptions = {
14488
14579
  flush: zlib.default.constants.Z_SYNC_FLUSH,
14489
14580
  finishFlush: zlib.default.constants.Z_SYNC_FLUSH
@@ -14649,7 +14740,7 @@ var http_default = isHttpAdapterSupported && function httpAdapter(config) {
14649
14740
  }
14650
14741
  if (supportedProtocols.indexOf(protocol) === -1) return reject(new AxiosError_default("Unsupported protocol " + protocol, AxiosError_default.ERR_BAD_REQUEST, config));
14651
14742
  const headers = AxiosHeaders_default.from(config.headers).normalize();
14652
- headers.set("User-Agent", "axios/" + VERSION, false);
14743
+ headers.set("User-Agent", "axios/" + VERSION$1, false);
14653
14744
  const { onUploadProgress, onDownloadProgress } = config;
14654
14745
  const maxRate = config.maxRate;
14655
14746
  let maxUploadRate = void 0;
@@ -14659,7 +14750,7 @@ var http_default = isHttpAdapterSupported && function httpAdapter(config) {
14659
14750
  data = formDataToStream_default(data, (formHeaders) => {
14660
14751
  headers.set(formHeaders);
14661
14752
  }, {
14662
- tag: `axios-${VERSION}-boundary`,
14753
+ tag: `axios-${VERSION$1}-boundary`,
14663
14754
  boundary: userBoundary && userBoundary[1] || void 0
14664
14755
  });
14665
14756
  } else if (utils_default.isFormData(data) && utils_default.isFunction(data.getHeaders)) {
@@ -14924,7 +15015,7 @@ const headersToObject = (thing) => thing instanceof AxiosHeaders_default ? { ...
14924
15015
  *
14925
15016
  * @returns {Object} New object resulting from merging config2 to config1
14926
15017
  */
14927
- function mergeConfig(config1, config2) {
15018
+ function mergeConfig$1(config1, config2) {
14928
15019
  config2 = config2 || {};
14929
15020
  const config = {};
14930
15021
  function getMergedValue(target, source, prop, caseless) {
@@ -14990,7 +15081,7 @@ function mergeConfig(config1, config2) {
14990
15081
  //#endregion
14991
15082
  //#region ../agent-provider/node_modules/axios/lib/helpers/resolveConfig.js
14992
15083
  var resolveConfig_default = (config) => {
14993
- const newConfig = mergeConfig({}, config);
15084
+ const newConfig = mergeConfig$1({}, config);
14994
15085
  let { data, withXSRFToken, xsrfHeaderName, xsrfCookieName, headers, auth } = newConfig;
14995
15086
  newConfig.headers = headers = AxiosHeaders_default.from(headers);
14996
15087
  newConfig.url = buildURL(buildFullPath(newConfig.baseURL, newConfig.url, newConfig.allowAbsoluteUrls), config.params, config.paramsSerializer);
@@ -15421,7 +15512,7 @@ function dispatchRequest(config) {
15421
15512
  response.headers = AxiosHeaders_default.from(response.headers);
15422
15513
  return response;
15423
15514
  }, function onAdapterRejection(reason) {
15424
- if (!isCancel(reason)) {
15515
+ if (!isCancel$1(reason)) {
15425
15516
  throwIfCancellationRequested(config);
15426
15517
  if (reason && reason.response) {
15427
15518
  reason.response.data = transformData.call(config, config.transformResponse, reason.response);
@@ -15459,7 +15550,7 @@ const deprecatedWarnings = {};
15459
15550
  */
15460
15551
  validators$1.transitional = function transitional(validator, version, message) {
15461
15552
  function formatMessage(opt, desc) {
15462
- return "[Axios v" + VERSION + "] Transitional option '" + opt + "'" + desc + (message ? ". " + message : "");
15553
+ return "[Axios v" + VERSION$1 + "] Transitional option '" + opt + "'" + desc + (message ? ". " + message : "");
15463
15554
  }
15464
15555
  return (value, opt, opts) => {
15465
15556
  if (validator === false) throw new AxiosError_default(formatMessage(opt, " has been removed" + (version ? " in " + version : "")), AxiosError_default.ERR_DEPRECATED);
@@ -15516,7 +15607,7 @@ const validators = validator_default.validators;
15516
15607
  *
15517
15608
  * @return {Axios} A new instance of Axios
15518
15609
  */
15519
- var Axios = class {
15610
+ var Axios$1 = class {
15520
15611
  constructor(instanceConfig) {
15521
15612
  this.defaults = instanceConfig || {};
15522
15613
  this.interceptors = {
@@ -15553,7 +15644,7 @@ var Axios = class {
15553
15644
  config = config || {};
15554
15645
  config.url = configOrUrl;
15555
15646
  } else config = configOrUrl || {};
15556
- config = mergeConfig(this.defaults, config);
15647
+ config = mergeConfig$1(this.defaults, config);
15557
15648
  const { transitional, paramsSerializer, headers } = config;
15558
15649
  if (transitional !== void 0) validator_default.assertOptions(transitional, {
15559
15650
  silentJSONParsing: validators.transitional(validators.boolean),
@@ -15632,7 +15723,7 @@ var Axios = class {
15632
15723
  return promise;
15633
15724
  }
15634
15725
  getUri(config) {
15635
- config = mergeConfig(this.defaults, config);
15726
+ config = mergeConfig$1(this.defaults, config);
15636
15727
  return buildURL(buildFullPath(config.baseURL, config.url, config.allowAbsoluteUrls), config.params, config.paramsSerializer);
15637
15728
  }
15638
15729
  };
@@ -15642,8 +15733,8 @@ utils_default.forEach([
15642
15733
  "head",
15643
15734
  "options"
15644
15735
  ], function forEachMethodNoData(method) {
15645
- Axios.prototype[method] = function(url, config) {
15646
- return this.request(mergeConfig(config || {}, {
15736
+ Axios$1.prototype[method] = function(url, config) {
15737
+ return this.request(mergeConfig$1(config || {}, {
15647
15738
  method,
15648
15739
  url,
15649
15740
  data: (config || {}).data
@@ -15657,7 +15748,7 @@ utils_default.forEach([
15657
15748
  ], function forEachMethodWithData(method) {
15658
15749
  function generateHTTPMethod(isForm) {
15659
15750
  return function httpMethod(url, data, config) {
15660
- return this.request(mergeConfig(config || {}, {
15751
+ return this.request(mergeConfig$1(config || {}, {
15661
15752
  method,
15662
15753
  headers: isForm ? { "Content-Type": "multipart/form-data" } : {},
15663
15754
  url,
@@ -15665,10 +15756,10 @@ utils_default.forEach([
15665
15756
  }));
15666
15757
  };
15667
15758
  }
15668
- Axios.prototype[method] = generateHTTPMethod();
15669
- Axios.prototype[method + "Form"] = generateHTTPMethod(true);
15759
+ Axios$1.prototype[method] = generateHTTPMethod();
15760
+ Axios$1.prototype[method + "Form"] = generateHTTPMethod(true);
15670
15761
  });
15671
- var Axios_default = Axios;
15762
+ var Axios_default = Axios$1;
15672
15763
 
15673
15764
  //#endregion
15674
15765
  //#region ../agent-provider/node_modules/axios/lib/cancel/CancelToken.js
@@ -15679,7 +15770,7 @@ var Axios_default = Axios;
15679
15770
  *
15680
15771
  * @returns {CancelToken}
15681
15772
  */
15682
- var CancelToken = class CancelToken {
15773
+ var CancelToken$1 = class CancelToken$1 {
15683
15774
  constructor(executor) {
15684
15775
  if (typeof executor !== "function") throw new TypeError("executor must be a function.");
15685
15776
  let resolvePromise;
@@ -15751,14 +15842,14 @@ var CancelToken = class CancelToken {
15751
15842
  static source() {
15752
15843
  let cancel;
15753
15844
  return {
15754
- token: new CancelToken(function executor(c) {
15845
+ token: new CancelToken$1(function executor(c) {
15755
15846
  cancel = c;
15756
15847
  }),
15757
15848
  cancel
15758
15849
  };
15759
15850
  }
15760
15851
  };
15761
- var CancelToken_default = CancelToken;
15852
+ var CancelToken_default = CancelToken$1;
15762
15853
 
15763
15854
  //#endregion
15764
15855
  //#region ../agent-provider/node_modules/axios/lib/helpers/spread.js
@@ -15783,7 +15874,7 @@ var CancelToken_default = CancelToken;
15783
15874
  *
15784
15875
  * @returns {Function}
15785
15876
  */
15786
- function spread(callback) {
15877
+ function spread$1(callback) {
15787
15878
  return function wrap(arr) {
15788
15879
  return callback.apply(null, arr);
15789
15880
  };
@@ -15798,13 +15889,13 @@ function spread(callback) {
15798
15889
  *
15799
15890
  * @returns {boolean} True if the payload is an error thrown by Axios, otherwise false
15800
15891
  */
15801
- function isAxiosError(payload) {
15892
+ function isAxiosError$1(payload) {
15802
15893
  return utils_default.isObject(payload) && payload.isAxiosError === true;
15803
15894
  }
15804
15895
 
15805
15896
  //#endregion
15806
15897
  //#region ../agent-provider/node_modules/axios/lib/helpers/HttpStatusCode.js
15807
- const HttpStatusCode = {
15898
+ const HttpStatusCode$1 = {
15808
15899
  Continue: 100,
15809
15900
  SwitchingProtocols: 101,
15810
15901
  Processing: 102,
@@ -15869,10 +15960,10 @@ const HttpStatusCode = {
15869
15960
  NotExtended: 510,
15870
15961
  NetworkAuthenticationRequired: 511
15871
15962
  };
15872
- Object.entries(HttpStatusCode).forEach(([key, value]) => {
15873
- HttpStatusCode[value] = key;
15963
+ Object.entries(HttpStatusCode$1).forEach(([key, value]) => {
15964
+ HttpStatusCode$1[value] = key;
15874
15965
  });
15875
- var HttpStatusCode_default = HttpStatusCode;
15966
+ var HttpStatusCode_default = HttpStatusCode$1;
15876
15967
 
15877
15968
  //#endregion
15878
15969
  //#region ../agent-provider/node_modules/axios/lib/axios.js
@@ -15889,7 +15980,7 @@ function createInstance(defaultConfig) {
15889
15980
  utils_default.extend(instance, Axios_default.prototype, context, { allOwnKeys: true });
15890
15981
  utils_default.extend(instance, context, null, { allOwnKeys: true });
15891
15982
  instance.create = function create(instanceConfig) {
15892
- return createInstance(mergeConfig(defaultConfig, instanceConfig));
15983
+ return createInstance(mergeConfig$1(defaultConfig, instanceConfig));
15893
15984
  };
15894
15985
  return instance;
15895
15986
  }
@@ -15897,17 +15988,17 @@ const axios = createInstance(defaults_default);
15897
15988
  axios.Axios = Axios_default;
15898
15989
  axios.CanceledError = CanceledError_default;
15899
15990
  axios.CancelToken = CancelToken_default;
15900
- axios.isCancel = isCancel;
15901
- axios.VERSION = VERSION;
15991
+ axios.isCancel = isCancel$1;
15992
+ axios.VERSION = VERSION$1;
15902
15993
  axios.toFormData = toFormData_default;
15903
15994
  axios.AxiosError = AxiosError_default;
15904
15995
  axios.Cancel = axios.CanceledError;
15905
15996
  axios.all = function all(promises) {
15906
15997
  return Promise.all(promises);
15907
15998
  };
15908
- axios.spread = spread;
15909
- axios.isAxiosError = isAxiosError;
15910
- axios.mergeConfig = mergeConfig;
15999
+ axios.spread = spread$1;
16000
+ axios.isAxiosError = isAxiosError$1;
16001
+ axios.mergeConfig = mergeConfig$1;
15911
16002
  axios.AxiosHeaders = AxiosHeaders_default;
15912
16003
  axios.formToJSON = (thing) => formDataToJSON_default(utils_default.isHTMLForm(thing) ? new FormData(thing) : thing);
15913
16004
  axios.getAdapter = adapters_default.getAdapter;
@@ -15915,6 +16006,10 @@ axios.HttpStatusCode = HttpStatusCode_default;
15915
16006
  axios.default = axios;
15916
16007
  var axios_default = axios;
15917
16008
 
16009
+ //#endregion
16010
+ //#region ../agent-provider/node_modules/axios/index.js
16011
+ const { Axios, AxiosError, CanceledError, isCancel, CancelToken, VERSION, all, Cancel, isAxiosError, spread, toFormData, AxiosHeaders, HttpStatusCode, formToJSON, getAdapter, mergeConfig } = axios_default;
16012
+
15918
16013
  //#endregion
15919
16014
  //#region ../agent-provider/src/http/http-service.ts
15920
16015
  /**
@@ -15923,7 +16018,7 @@ var axios_default = axios;
15923
16018
  * 特性:
15924
16019
  * - 单例模式,全局唯一实例,延迟初始化(首次使用时自动创建)
15925
16020
  * - 支持拦截器注册(其他模块可注入 header)
15926
- * - 统一 401/403 处理
16021
+ * - 统一 401 处理(支持自动刷新 token 并重试)
15927
16022
  * - 自动携带凭证(withCredentials)
15928
16023
  * - 类型安全
15929
16024
  *
@@ -15963,6 +16058,8 @@ var HttpService = class HttpService {
15963
16058
  */
15964
16059
  constructor(config = {}) {
15965
16060
  this.unauthorizedCallbacks = /* @__PURE__ */ new Set();
16061
+ this.isRefreshing = false;
16062
+ this.refreshSubscribers = [];
15966
16063
  this.config = config;
15967
16064
  this.axiosInstance = axios_default.create({
15968
16065
  baseURL: config.baseURL?.replace(/\/$/, "") || "",
@@ -16003,18 +16100,54 @@ var HttpService = class HttpService {
16003
16100
  }, (error) => Promise.reject(error));
16004
16101
  }
16005
16102
  /**
16006
- * 注册默认响应拦截器(处理 401/403)
16103
+ * 注册默认响应拦截器(处理 401,支持自动重试)
16007
16104
  */
16008
16105
  registerDefaultResponseInterceptor() {
16009
- this.axiosInstance.interceptors.response.use((response) => response, (error) => {
16010
- if (error.response?.status === 401 || error.response?.status === 403) {
16011
- console.warn("[HttpService] Unauthorized (401/403), triggering callbacks");
16012
- this.triggerUnauthorizedCallbacks();
16106
+ this.axiosInstance.interceptors.response.use((response) => response, async (error) => {
16107
+ const originalRequest = error.config;
16108
+ if (error.response?.status === 401 && originalRequest && !originalRequest._retry) {
16109
+ if (originalRequest.url?.includes("/console/accounts")) {
16110
+ console.warn("[HttpService] Unauthorized 401 on refresh endpoint, not retrying");
16111
+ return Promise.reject(error);
16112
+ }
16113
+ console.warn("[HttpService] Unauthorized 401, attempting token refresh and retry");
16114
+ originalRequest._retry = true;
16115
+ if (this.isRefreshing) return new Promise((resolve, reject) => {
16116
+ this.refreshSubscribers.push((success) => {
16117
+ if (success) this.axiosInstance.request(originalRequest).then(resolve).catch(reject);
16118
+ else reject(error);
16119
+ });
16120
+ });
16121
+ this.isRefreshing = true;
16122
+ try {
16123
+ await this.triggerUnauthorizedCallbacks();
16124
+ this.onRefreshSuccess();
16125
+ return this.axiosInstance.request(originalRequest);
16126
+ } catch (refreshError) {
16127
+ this.onRefreshFailure();
16128
+ return Promise.reject(error);
16129
+ } finally {
16130
+ this.isRefreshing = false;
16131
+ }
16013
16132
  }
16014
16133
  return Promise.reject(error);
16015
16134
  });
16016
16135
  }
16017
16136
  /**
16137
+ * token 刷新成功,通知所有等待的请求
16138
+ */
16139
+ onRefreshSuccess() {
16140
+ this.refreshSubscribers.forEach((callback) => callback(true));
16141
+ this.refreshSubscribers = [];
16142
+ }
16143
+ /**
16144
+ * token 刷新失败,通知所有等待的请求
16145
+ */
16146
+ onRefreshFailure() {
16147
+ this.refreshSubscribers.forEach((callback) => callback(false));
16148
+ this.refreshSubscribers = [];
16149
+ }
16150
+ /**
16018
16151
  * 注册请求拦截器
16019
16152
  * @param onFulfilled 请求成功拦截器
16020
16153
  * @param onRejected 请求失败拦截器
@@ -16091,16 +16224,18 @@ var HttpService = class HttpService {
16091
16224
  this.unauthorizedCallbacks.delete(callback);
16092
16225
  }
16093
16226
  /**
16094
- * 触发所有 401 回调
16227
+ * 触发所有 401 回调并等待完成
16228
+ * @returns Promise,等待所有回调完成
16229
+ * @throws 如果任何回调失败,则抛出错误
16095
16230
  */
16096
- triggerUnauthorizedCallbacks() {
16097
- this.unauthorizedCallbacks.forEach((callback) => {
16098
- try {
16099
- callback();
16100
- } catch (error) {
16101
- console.error("[HttpService] Error in unauthorized callback:", error);
16102
- }
16103
- });
16231
+ async triggerUnauthorizedCallbacks() {
16232
+ const callbacks = Array.from(this.unauthorizedCallbacks);
16233
+ const failedResults = (await Promise.allSettled(callbacks.map((callback) => callback()))).filter((r) => r.status === "rejected");
16234
+ if (failedResults.length > 0) {
16235
+ const errors = failedResults.map((r) => r.reason);
16236
+ console.error("[HttpService] Some unauthorized callbacks failed:", errors);
16237
+ throw errors[0];
16238
+ }
16104
16239
  }
16105
16240
  /**
16106
16241
  * 更新 authToken
@@ -16166,6 +16301,14 @@ var HttpService = class HttpService {
16166
16301
  return (await this.axiosInstance.put(url, data, config)).data;
16167
16302
  }
16168
16303
  /**
16304
+ * 通用请求方法
16305
+ * @param config axios 请求配置
16306
+ * @returns 原始 AxiosResponse
16307
+ */
16308
+ async request(config) {
16309
+ return this.axiosInstance.request(config);
16310
+ }
16311
+ /**
16169
16312
  * 获取原始 axios 实例(用于高级场景)
16170
16313
  */
16171
16314
  getAxiosInstance() {
@@ -16359,6 +16502,109 @@ const accountService = new AccountService();
16359
16502
  */
16360
16503
  if (typeof window !== "undefined") window.__genieAccountService = accountService;
16361
16504
 
16505
+ //#endregion
16506
+ //#region ../agent-provider/src/common/utils/lru-cache.ts
16507
+ /**
16508
+ * LRU (Least Recently Used) Cache
16509
+ * 当缓存达到容量上限时,自动淘汰最久未使用的数据
16510
+ *
16511
+ * @template K - Key 类型
16512
+ * @template V - Value 类型
16513
+ */
16514
+ var LRUCache = class {
16515
+ /**
16516
+ * 创建 LRU 缓存实例
16517
+ * @param capacity - 缓存容量上限
16518
+ */
16519
+ constructor(capacity) {
16520
+ if (capacity <= 0) throw new Error("Cache capacity must be greater than 0");
16521
+ this.capacity = capacity;
16522
+ this.cache = /* @__PURE__ */ new Map();
16523
+ }
16524
+ /**
16525
+ * 获取缓存值
16526
+ * @param key - 键
16527
+ * @returns 值,如果不存在返回 undefined
16528
+ */
16529
+ get(key) {
16530
+ if (!this.cache.has(key)) return;
16531
+ const value = this.cache.get(key);
16532
+ this.cache.delete(key);
16533
+ this.cache.set(key, value);
16534
+ return value;
16535
+ }
16536
+ /**
16537
+ * 设置缓存值
16538
+ * @param key - 键
16539
+ * @param value - 值
16540
+ */
16541
+ set(key, value) {
16542
+ if (this.cache.has(key)) this.cache.delete(key);
16543
+ else if (this.cache.size >= this.capacity) {
16544
+ const firstKey = this.cache.keys().next().value;
16545
+ this.cache.delete(firstKey);
16546
+ }
16547
+ this.cache.set(key, value);
16548
+ }
16549
+ /**
16550
+ * 检查 key 是否存在
16551
+ * @param key - 键
16552
+ * @returns 是否存在
16553
+ */
16554
+ has(key) {
16555
+ return this.cache.has(key);
16556
+ }
16557
+ /**
16558
+ * 删除指定 key
16559
+ * @param key - 键
16560
+ * @returns 是否删除成功
16561
+ */
16562
+ delete(key) {
16563
+ return this.cache.delete(key);
16564
+ }
16565
+ /**
16566
+ * 清空缓存
16567
+ */
16568
+ clear() {
16569
+ this.cache.clear();
16570
+ }
16571
+ /**
16572
+ * 获取当前缓存大小
16573
+ * @returns 当前缓存的元素数量
16574
+ */
16575
+ get size() {
16576
+ return this.cache.size;
16577
+ }
16578
+ /**
16579
+ * 获取缓存容量
16580
+ * @returns 缓存容量上限
16581
+ */
16582
+ get maxSize() {
16583
+ return this.capacity;
16584
+ }
16585
+ /**
16586
+ * 获取所有 key
16587
+ * @returns key 数组
16588
+ */
16589
+ keys() {
16590
+ return Array.from(this.cache.keys());
16591
+ }
16592
+ /**
16593
+ * 获取所有 value
16594
+ * @returns value 数组
16595
+ */
16596
+ values() {
16597
+ return Array.from(this.cache.values());
16598
+ }
16599
+ /**
16600
+ * 遍历缓存
16601
+ * @param callback - 回调函数
16602
+ */
16603
+ forEach(callback) {
16604
+ this.cache.forEach((value, key) => callback(value, key));
16605
+ }
16606
+ };
16607
+
16362
16608
  //#endregion
16363
16609
  //#region ../agent-provider/src/common/utils/concurrency.ts
16364
16610
  /**
@@ -16460,20 +16706,32 @@ var CosUploadService = class {
16460
16706
  * 上传单个文件到 COS
16461
16707
  *
16462
16708
  * @param file - 要上传的文件
16709
+ * @param abortSignal - 可选的 AbortSignal,用于取消上传
16463
16710
  * @returns 上传结果,包含访问 URL 或错误信息
16464
16711
  */
16465
- async uploadFile(file) {
16712
+ async uploadFile(file, abortSignal) {
16466
16713
  const filename = file.name;
16467
16714
  this.logger?.info(`[CosUploadService] Uploading file: ${filename}`);
16468
16715
  try {
16716
+ if (abortSignal?.aborted) return {
16717
+ success: false,
16718
+ error: "Upload cancelled",
16719
+ aborted: true
16720
+ };
16469
16721
  const objectKey = this.generateObjectKey(filename);
16470
16722
  this.logger?.debug(`[CosUploadService] Generated objectKey: ${objectKey}`);
16471
16723
  const presignedItem = (await this.getPresignedUrls([objectKey])).items[0];
16472
16724
  if (!presignedItem) throw new Error("No presigned URL item returned");
16725
+ if (abortSignal?.aborted) return {
16726
+ success: false,
16727
+ error: "Upload cancelled",
16728
+ aborted: true
16729
+ };
16473
16730
  const uploadResponse = await fetch(presignedItem.upload_url, {
16474
16731
  method: "PUT",
16475
16732
  body: file,
16476
- headers: { "Content-Type": file.type || "application/octet-stream" }
16733
+ headers: { "Content-Type": file.type || "application/octet-stream" },
16734
+ signal: abortSignal
16477
16735
  });
16478
16736
  if (!uploadResponse.ok) {
16479
16737
  const errorText = await uploadResponse.text().catch(() => uploadResponse.statusText);
@@ -16487,6 +16745,11 @@ var CosUploadService = class {
16487
16745
  objectKey
16488
16746
  };
16489
16747
  } catch (error) {
16748
+ if (error instanceof Error && error.name === "AbortError") return {
16749
+ success: false,
16750
+ error: "Upload cancelled",
16751
+ aborted: true
16752
+ };
16490
16753
  const errorMessage = error instanceof Error ? error.message : "Unknown error";
16491
16754
  this.logger?.error(`[CosUploadService] Upload failed: ${filename}`, error);
16492
16755
  return {
@@ -16501,14 +16764,25 @@ var CosUploadService = class {
16501
16764
  * 使用并发控制,限制同时上传的文件数量
16502
16765
  *
16503
16766
  * @param files - 要上传的文件数组
16767
+ * @param abortSignal - 可选的 AbortSignal,用于取消上传
16504
16768
  * @returns 所有文件的上传结果
16505
16769
  */
16506
- async uploadFiles(files) {
16770
+ async uploadFiles(files, abortSignal) {
16507
16771
  if (files.length === 0) return {
16508
16772
  success: true,
16509
16773
  urls: [],
16510
16774
  results: []
16511
16775
  };
16776
+ if (abortSignal?.aborted) return {
16777
+ success: false,
16778
+ error: "Upload cancelled",
16779
+ aborted: true,
16780
+ results: files.map(() => ({
16781
+ success: false,
16782
+ error: "Upload cancelled",
16783
+ aborted: true
16784
+ }))
16785
+ };
16512
16786
  this.logger?.info(`[CosUploadService] Uploading ${files.length} file(s) with concurrency ${this.uploadConcurrency}`);
16513
16787
  try {
16514
16788
  const fileInfos = files.map((file) => ({
@@ -16520,6 +16794,12 @@ var CosUploadService = class {
16520
16794
  this.logger?.debug(`[CosUploadService] Got ${presignedResponse.items.length} presigned URLs`);
16521
16795
  if (presignedResponse.items.length !== fileInfos.length) throw new Error(`Expected ${fileInfos.length} presigned URLs, got ${presignedResponse.items.length}`);
16522
16796
  const results = (await runWithConcurrencySettled(fileInfos.map(({ file }, index) => async () => {
16797
+ if (abortSignal?.aborted) return {
16798
+ success: false,
16799
+ error: "Upload cancelled",
16800
+ aborted: true,
16801
+ objectKey: fileInfos[index].objectKey
16802
+ };
16523
16803
  const presignedItem = presignedResponse.items[index];
16524
16804
  if (!presignedItem) return {
16525
16805
  success: false,
@@ -16530,7 +16810,8 @@ var CosUploadService = class {
16530
16810
  const uploadResponse = await fetch(presignedItem.upload_url, {
16531
16811
  method: "PUT",
16532
16812
  body: file,
16533
- headers: { "Content-Type": file.type || "application/octet-stream" }
16813
+ headers: { "Content-Type": file.type || "application/octet-stream" },
16814
+ signal: abortSignal
16534
16815
  });
16535
16816
  if (!uploadResponse.ok) {
16536
16817
  const errorText = await uploadResponse.text().catch(() => uploadResponse.statusText);
@@ -16547,6 +16828,12 @@ var CosUploadService = class {
16547
16828
  objectKey: presignedItem.object_key
16548
16829
  };
16549
16830
  } catch (error) {
16831
+ if (error instanceof Error && error.name === "AbortError") return {
16832
+ success: false,
16833
+ error: "Upload cancelled",
16834
+ aborted: true,
16835
+ objectKey: presignedItem.object_key
16836
+ };
16550
16837
  return {
16551
16838
  success: false,
16552
16839
  error: error instanceof Error ? error.message : "Unknown error",
@@ -16594,91 +16881,6 @@ var CosUploadService = class {
16594
16881
  }
16595
16882
  };
16596
16883
 
16597
- //#endregion
16598
- //#region ../agent-provider/src/common/providers/cloud-agent-provider/e2b-filesystem.ts
16599
- /**
16600
- * E2B Filesystem Implementation
16601
- *
16602
- * Provides FilesResource implementation using E2B Sandbox SDK.
16603
- * Directly uses e2b SDK types.
16604
- *
16605
- * @see https://e2b.dev/docs/filesystem/read-write
16606
- * @see https://e2b.dev/docs/filesystem/watch
16607
- */
16608
- /**
16609
- * E2B Filesystem Implementation
16610
- *
16611
- * Wraps E2B Sandbox SDK's filesystem operations to implement FilesResource interface.
16612
- *
16613
- * @example
16614
- * ```typescript
16615
- * const fs = await E2BFilesystem.connect({
16616
- * sandboxId: 'sandbox-123',
16617
- * apiKey: 'e2b_xxx'
16618
- * });
16619
- *
16620
- * // Read/write files
16621
- * await fs.write('/test.txt', 'Hello World');
16622
- * const content = await fs.read('/test.txt');
16623
- *
16624
- * // Watch for changes
16625
- * const handle = await fs.watchDir('/workspace', (event) => {
16626
- * console.log('File changed:', event);
16627
- * });
16628
- * ```
16629
- */
16630
- var E2BFilesystem = class E2BFilesystem {
16631
- constructor(sandbox) {
16632
- this.sandbox = sandbox;
16633
- }
16634
- /**
16635
- * Connect to an E2B Sandbox and create filesystem instance
16636
- */
16637
- static async connect(info) {
16638
- return new E2BFilesystem(await e2b.Sandbox.connect(info.sandboxId, {
16639
- domain: info.domain,
16640
- apiUrl: info.apiUrl,
16641
- requestTimeoutMs: info.requestTimeoutMs,
16642
- debug: info.debug,
16643
- headers: info.headers
16644
- }));
16645
- }
16646
- /**
16647
- * Get the underlying E2B Sandbox instance
16648
- */
16649
- getSandbox() {
16650
- return this.sandbox;
16651
- }
16652
- read(path, opts) {
16653
- return this.sandbox.files.read(path, opts);
16654
- }
16655
- write(pathOrFiles, dataOrOpts, opts) {
16656
- if (Array.isArray(pathOrFiles)) return this.sandbox.files.write(pathOrFiles, dataOrOpts);
16657
- return this.sandbox.files.write(pathOrFiles, dataOrOpts, opts);
16658
- }
16659
- async list(path, opts) {
16660
- return this.sandbox.files.list(path, opts);
16661
- }
16662
- async exists(path, opts) {
16663
- return this.sandbox.files.exists(path, opts);
16664
- }
16665
- async makeDir(path, opts) {
16666
- return this.sandbox.files.makeDir(path, opts);
16667
- }
16668
- async remove(path, opts) {
16669
- return this.sandbox.files.remove(path, opts);
16670
- }
16671
- async rename(oldPath, newPath, opts) {
16672
- return this.sandbox.files.rename(oldPath, newPath, opts);
16673
- }
16674
- async getInfo(path, opts) {
16675
- return this.sandbox.files.getInfo(path, opts);
16676
- }
16677
- async watchDir(path, onEvent, opts) {
16678
- return this.sandbox.files.watchDir(path, onEvent, opts);
16679
- }
16680
- };
16681
-
16682
16884
  //#endregion
16683
16885
  //#region ../agent-provider/src/common/providers/cloud-agent-provider/cloud-provider.ts
16684
16886
  /**
@@ -16827,8 +17029,11 @@ var CloudAgentProvider = class CloudAgentProvider {
16827
17029
  this.filesystemCache = /* @__PURE__ */ new Map();
16828
17030
  this.connectionCache = /* @__PURE__ */ new Map();
16829
17031
  this.eventListeners = /* @__PURE__ */ new Map();
17032
+ this.productConfigCache = null;
16830
17033
  this.options = options;
16831
17034
  this.logger = options.logger;
17035
+ this.marketplaceCache = new LRUCache(200);
17036
+ this.pluginCache = new LRUCache(2e3);
16832
17037
  if (options.endpoint) httpService.setBaseURL(options.endpoint);
16833
17038
  if (options.authToken) httpService.setAuthToken(options.authToken);
16834
17039
  if (options.headers && Object.keys(options.headers).length > 0) this.requestInterceptorId = httpService.registerRequestInterceptor((config) => {
@@ -16879,7 +17084,19 @@ var CloudAgentProvider = class CloudAgentProvider {
16879
17084
  const cached = this.filesystemCache.get(agentId);
16880
17085
  if (cached) return cached;
16881
17086
  const info = await this.getSandboxInfo(agentId);
16882
- const filesystem = createAgentFilesystem(await E2BFilesystem.connect(info));
17087
+ let e2bFilesystem;
17088
+ if (this.options.filesystemFactory) e2bFilesystem = await this.options.filesystemFactory(info);
17089
+ else {
17090
+ const { E2BFilesystem } = await Promise.resolve().then(() => require("./e2b-filesystem-Cac-bpRR.cjs"));
17091
+ e2bFilesystem = await E2BFilesystem.connect(info);
17092
+ }
17093
+ if (e2bFilesystem.setReconnectFn) e2bFilesystem.setReconnectFn(async () => {
17094
+ this.logger?.debug(`Reconnecting E2B sandbox for agent: ${agentId}`);
17095
+ const newInfo = await this.getSandboxInfo(agentId);
17096
+ this.logger?.debug(`E2B sandbox reconnected for agent: ${agentId}`);
17097
+ return newInfo;
17098
+ });
17099
+ const filesystem = createAgentFilesystem(e2bFilesystem);
16883
17100
  this.filesystemCache.set(agentId, filesystem);
16884
17101
  this.logger?.debug(`Created filesystem for agent: ${agentId}`);
16885
17102
  return filesystem;
@@ -16947,15 +17164,9 @@ var CloudAgentProvider = class CloudAgentProvider {
16947
17164
  const url = this.buildGetUrl("/console/as/conversations/", params);
16948
17165
  const apiResponse = await httpService.get(url);
16949
17166
  if (!apiResponse.data) throw new Error("No data in API response");
16950
- const agents = apiResponse.data.conversations.map((a) => this.toAgentState(a));
16951
- const pagination = apiResponse.data.pagination;
16952
- console.log("[CloudAgentProvider] API response:", {
16953
- agentsCount: agents.length,
16954
- pagination
16955
- });
16956
17167
  return {
16957
- agents,
16958
- pagination
17168
+ agents: apiResponse.data.conversations.map((a) => this.toAgentState(a)),
17169
+ pagination: apiResponse.data.pagination
16959
17170
  };
16960
17171
  } catch (error) {
16961
17172
  this.logger?.error("Failed to list agents:", error);
@@ -16965,15 +17176,17 @@ var CloudAgentProvider = class CloudAgentProvider {
16965
17176
  /**
16966
17177
  * Create a new conversation
16967
17178
  * POST {endpoint}/console/as/conversations
16968
- * @param params - Optional session params containing _meta with tags
17179
+ * @param params - Session params containing cwd and optional configuration
16969
17180
  */
16970
17181
  async create(params) {
16971
17182
  try {
16972
- const tagsObj = (params?._meta?.["codebuddy.ai"])?.tags;
17183
+ const { options = {} } = params;
17184
+ const codebuddyMeta = options._meta?.["codebuddy.ai"];
17185
+ const tagsObj = options.tags || codebuddyMeta?.tags;
16973
17186
  const tagsArray = tagsObj ? Object.entries(tagsObj).map(([key, value]) => `${key}:${value}`) : void 0;
16974
17187
  const createPayload = {
16975
- prompt: "",
16976
- model: "deepseek-r1",
17188
+ prompt: (options.prompt || "").slice(0, 100),
17189
+ model: options.model || "deepseek-r1",
16977
17190
  ...tagsArray && tagsArray.length > 0 ? { tags: tagsArray } : {}
16978
17191
  };
16979
17192
  console.log("[CloudAgentProvider] Creating conversation with payload:", createPayload);
@@ -17027,7 +17240,14 @@ var CloudAgentProvider = class CloudAgentProvider {
17027
17240
  } catch (error) {
17028
17241
  this.logger?.debug(`Failed to fetch conversation details for ${agentId}:`, error);
17029
17242
  }
17030
- if (this.connectionCache.get(endpoint)) this.connectionCache.delete(endpoint);
17243
+ const existingConnection = this.connectionCache.get(endpoint);
17244
+ if (existingConnection) {
17245
+ this.connectionCache.delete(endpoint);
17246
+ existingConnection.removeAllListeners();
17247
+ existingConnection.disconnect().catch((err) => {
17248
+ this.logger?.debug("Failed to disconnect old connection:", err);
17249
+ });
17250
+ }
17031
17251
  const clientCapabilities = {
17032
17252
  ...this.options.clientCapabilities,
17033
17253
  _meta: {
@@ -17147,6 +17367,35 @@ var CloudAgentProvider = class CloudAgentProvider {
17147
17367
  }
17148
17368
  }
17149
17369
  /**
17370
+ * Update conversation status by ID
17371
+ * POST {endpoint}/console/as/conversations/{agentId}
17372
+ *
17373
+ * @param agentId - Conversation ID to update
17374
+ * @param status - New status for the conversation
17375
+ * @returns PatchConversationResponse containing the updated conversation ID
17376
+ *
17377
+ * @example
17378
+ * ```typescript
17379
+ * const result = await provider.updateStatus('agent-123', 'completed');
17380
+ * console.log('Updated conversation status:', result.id);
17381
+ * ```
17382
+ */
17383
+ async updateStatus(agentId, status) {
17384
+ try {
17385
+ const body = { status };
17386
+ const apiResponse = await httpService.post(`/console/as/conversations/${agentId}`, body);
17387
+ if (!apiResponse.data) {
17388
+ this.logger?.info(`Updated conversation status: ${agentId} to "${status}"`);
17389
+ return { id: agentId };
17390
+ }
17391
+ this.logger?.info(`Updated conversation status: ${apiResponse.data.id} to "${status}"`);
17392
+ return apiResponse.data;
17393
+ } catch (error) {
17394
+ this.logger?.error(`Failed to update conversation status ${agentId}:`, error);
17395
+ throw error;
17396
+ }
17397
+ }
17398
+ /**
17150
17399
  * Get available models from product configuration
17151
17400
  *
17152
17401
  * GET {endpoint}/console/enterprises/{personal|enterpriseId}/models?repos[]={repo}
@@ -17177,9 +17426,13 @@ var CloudAgentProvider = class CloudAgentProvider {
17177
17426
  this.logger?.warn("[CloudAgentProvider] No data in config response, returning empty models");
17178
17427
  return [];
17179
17428
  }
17180
- const models = apiResponse.data.models ?? [];
17181
- this.logger?.info(`[CloudAgentProvider] Retrieved ${models.length} models from /console/enterprises API`);
17182
- return models.map((model) => ({
17429
+ this.productConfigCache = apiResponse.data;
17430
+ const productConfig = apiResponse.data;
17431
+ const allModels = productConfig.models ?? [];
17432
+ const cliModelIds = (productConfig.agents ?? []).find((agent) => agent.name === "cli")?.models ?? [];
17433
+ const filteredModels = cliModelIds.length > 0 ? allModels.filter((model) => cliModelIds.includes(model.id)) : allModels;
17434
+ this.logger?.info(`[CloudAgentProvider] Retrieved ${filteredModels.length} models for cli agent (total: ${allModels.length})`);
17435
+ return filteredModels.map((model) => ({
17183
17436
  id: model.id,
17184
17437
  name: model.name ?? model.id,
17185
17438
  description: model.description,
@@ -17201,6 +17454,43 @@ var CloudAgentProvider = class CloudAgentProvider {
17201
17454
  }
17202
17455
  }
17203
17456
  /**
17457
+ * 获取产品部署类型(从缓存)
17458
+ * 需要先调用 getModels() 初始化缓存
17459
+ *
17460
+ * @returns 部署类型:'SaaS' | 'Cloud-Hosted' | 'Self-Hosted',默认为 'SaaS'
17461
+ */
17462
+ getDeploymentType() {
17463
+ return this.productConfigCache?.deploymentType ?? "SaaS";
17464
+ }
17465
+ /**
17466
+ * 获取 Credit 购买引导配置(从缓存)
17467
+ * 需要先调用 getModels() 初始化缓存
17468
+ *
17469
+ * @returns Credit 购买引导配置,key 为错误码。如果后端未返回,则使用默认配置
17470
+ */
17471
+ getCreditPurchaseActions() {
17472
+ return this.productConfigCache?.config?.creditPurchaseActions ?? {
17473
+ "14018": {
17474
+ labelZh: "获取 Credits",
17475
+ labelEn: "Get credits",
17476
+ url: "https://www.codebuddy.cn/profile/plan",
17477
+ showButton: true
17478
+ },
17479
+ "6004": {
17480
+ labelZh: "升级专业版",
17481
+ labelEn: "Upgrade to Pro",
17482
+ url: "https://www.codebuddy.cn/profile/plan",
17483
+ showButton: true
17484
+ },
17485
+ "6005": {
17486
+ labelZh: "升级专业版",
17487
+ labelEn: "Upgrade to Pro",
17488
+ url: "https://www.codebuddy.cn/profile/plan",
17489
+ showButton: true
17490
+ }
17491
+ };
17492
+ }
17493
+ /**
17204
17494
  * Generate a unique request ID
17205
17495
  */
17206
17496
  generateRequestId() {
@@ -17283,7 +17573,7 @@ var CloudAgentProvider = class CloudAgentProvider {
17283
17573
  /**
17284
17574
  * Upload files to cloud storage via COS presigned URL
17285
17575
  *
17286
- * @param params - files array (File objects in browser)
17576
+ * @param params - files array (File objects in browser), optional abortSignal
17287
17577
  * @returns Response with corresponding cloud URLs
17288
17578
  */
17289
17579
  async uploadFile(params) {
@@ -17293,12 +17583,13 @@ var CloudAgentProvider = class CloudAgentProvider {
17293
17583
  success: false,
17294
17584
  error: "No valid File objects provided"
17295
17585
  };
17296
- const result = await this.cosUploadService.uploadFiles(files);
17586
+ const result = await this.cosUploadService.uploadFiles(files, params.abortSignal);
17297
17587
  return {
17298
17588
  success: result.success,
17299
17589
  urls: result.urls,
17300
17590
  expireSeconds: result.expireSeconds,
17301
- error: result.error
17591
+ error: result.error,
17592
+ aborted: result.aborted
17302
17593
  };
17303
17594
  }
17304
17595
  /**
@@ -17340,20 +17631,22 @@ var CloudAgentProvider = class CloudAgentProvider {
17340
17631
  }
17341
17632
  /**
17342
17633
  * 获取支持的场景列表
17343
- * API 端点: GET /console/as/support/scenes
17634
+ * API 端点: GET /v2/as/support/scenes (不鉴权)
17344
17635
  * 用于 Welcome 页面的 QuickActions 快捷操作
17345
17636
  *
17637
+ * @param locale - 可选,语言环境(如 'zh-CN', 'en-US'),用于获取对应语言的场景数据
17346
17638
  * @returns Promise<SupportScene[]> 支持的场景列表
17347
17639
  */
17348
- async getSupportScenes() {
17640
+ async getSupportScenes(locale) {
17349
17641
  try {
17350
- const apiResponse = await httpService.get("/console/as/support/scenes");
17642
+ const url = this.buildGetUrl("/v2/as/support/scenes", locale ? { locale } : void 0);
17643
+ const apiResponse = await httpService.get(url);
17351
17644
  if (!apiResponse.data) {
17352
17645
  this.logger?.warn("[CloudAgentProvider] No data in support scenes response");
17353
17646
  return [];
17354
17647
  }
17355
17648
  const scenes = apiResponse.data.scenes || [];
17356
- this.logger?.info(`[CloudAgentProvider] Retrieved ${scenes.length} support scenes`);
17649
+ this.logger?.info(`[CloudAgentProvider] Retrieved ${scenes.length} support scenes${locale ? ` for locale: ${locale}` : ""}`);
17357
17650
  return scenes;
17358
17651
  } catch (error) {
17359
17652
  this.logger?.error("[CloudAgentProvider] Failed to get support scenes:", error);
@@ -17369,7 +17662,9 @@ var CloudAgentProvider = class CloudAgentProvider {
17369
17662
  type: "cloud",
17370
17663
  status,
17371
17664
  createdAt: data.createdAt ? new Date(data.createdAt) : void 0,
17372
- capabilities: this.options.clientCapabilities
17665
+ updatedAt: data.updatedAt ? new Date(data.updatedAt) : void 0,
17666
+ capabilities: this.options.clientCapabilities,
17667
+ isUserDefinedTitle: data.isUserDefinedTitle
17373
17668
  };
17374
17669
  }
17375
17670
  /**
@@ -17385,57 +17680,500 @@ var CloudAgentProvider = class CloudAgentProvider {
17385
17680
  const queryString = searchParams.toString();
17386
17681
  return queryString ? `${path}?${queryString}` : path;
17387
17682
  }
17388
- };
17389
-
17390
- //#endregion
17391
- //#region ../agent-provider/src/common/providers/local-agent-provider/local-connection.ts
17392
- /**
17393
- * Local Agent Connection
17394
- * Wraps AcpJsonRpcClient to implement AgentConnection interface
17395
- *
17396
- * Uses IWidgetChannel for IPC communication with ExtensionHost
17397
- * Migrated from ipc-agent-provider for unified local agent access
17398
- */
17399
-
17400
- //#endregion
17401
- //#region ../agent-provider/src/common/client/session.ts
17402
- /**
17403
- * ActiveSessionImpl - Implements the ActiveSession interface
17404
- *
17405
- * This class wraps an AgentConnection and provides the session-centric API.
17406
- * It is created by SessionManager when creating or loading sessions.
17407
- *
17408
- * @example
17409
- * ```typescript
17410
- * // Created by client.sessions.new() or client.sessions.load()
17411
- * const session = await client.sessions.new({ cwd: '/workspace' });
17412
- *
17413
- * // Access agent state
17414
- * console.log(session.agentState.status);
17415
- *
17416
- * // Send prompt
17417
- * const response = await session.prompts.send({ content: 'Hello!' });
17418
- *
17419
- * // Cleanup
17420
- * session.disconnect();
17421
- * ```
17422
- */
17423
- var ActiveSessionImpl = class {
17424
17683
  /**
17425
- * Create an ActiveSessionImpl instance
17426
- *
17427
- * @param sessionId - Session ID
17428
- * @param agentId - Agent ID
17429
- * @param connection - Already connected AgentConnection
17430
- * @param options - Additional options
17684
+ * 获取已安装插件列表
17685
+ * GET /console/as/user/plugins/installed
17431
17686
  */
17432
- constructor(sessionId, agentId, connection, options = {}) {
17433
- this._availableCommands = [];
17434
- this.listeners = /* @__PURE__ */ new Map();
17435
- this.onceListeners = /* @__PURE__ */ new Map();
17436
- this._id = sessionId;
17437
- this._agentId = agentId;
17438
- this.connection = connection;
17687
+ async getInstalledPlugins(forceRefresh) {
17688
+ try {
17689
+ const result = ((await httpService.get("/console/as/user/plugins/installed")).data?.plugins || []).map((p) => ({
17690
+ name: p.plugin_name,
17691
+ marketplaceName: p.marketplace_name,
17692
+ status: p.enabled ? "enabled" : "disabled",
17693
+ description: p.description,
17694
+ version: p.version,
17695
+ installScope: p.scope === "local" ? "project" : p.scope,
17696
+ installedScopes: [p.scope],
17697
+ installId: p.id
17698
+ }));
17699
+ result.forEach((plugin) => {
17700
+ this.pluginCache.set(plugin.name, plugin);
17701
+ });
17702
+ return result;
17703
+ } catch (error) {
17704
+ this.logger?.error("[CloudAgentProvider] getInstalledPlugins failed:", error);
17705
+ throw error;
17706
+ }
17707
+ }
17708
+ /**
17709
+ * 安装插件
17710
+ * POST /console/as/user/plugins/install
17711
+ *
17712
+ * @param pluginNames - 插件名称数组
17713
+ * @param marketplaceNameOrId - 市场名称或 ID
17714
+ */
17715
+ async installPlugins(pluginNames, marketplaceNameOrId, installScope, marketplaceSource, workspacePath) {
17716
+ try {
17717
+ const marketplaceId = await this.findMarketplaceId(marketplaceNameOrId);
17718
+ if (!marketplaceId) return {
17719
+ success: false,
17720
+ error: `Marketplace not found: ${marketplaceNameOrId}`
17721
+ };
17722
+ const failed = (await Promise.allSettled(pluginNames.map((pluginName) => httpService.post("/console/as/user/plugins/install", {
17723
+ plugin_name: pluginName,
17724
+ marketplace_id: marketplaceId,
17725
+ version: "latest"
17726
+ })))).filter((r) => r.status === "rejected");
17727
+ if (failed.length > 0) {
17728
+ const errors = failed.map((r) => r.reason?.message || "Unknown error");
17729
+ return {
17730
+ success: false,
17731
+ error: `安装失败 ${failed.length} 个插件: ${errors.join(", ")}`
17732
+ };
17733
+ }
17734
+ return { success: true };
17735
+ } catch (error) {
17736
+ return {
17737
+ success: false,
17738
+ error: this.extractErrorMessage(error)
17739
+ };
17740
+ }
17741
+ }
17742
+ /**
17743
+ * 卸载插件
17744
+ * POST /console/as/user/plugins/installed/:id/uninstall
17745
+ *
17746
+ * 完整链路:
17747
+ * CloudAgentProvider.uninstallPlugin()
17748
+ * -> HTTP POST /console/as/user/plugins/installed/:id/uninstall
17749
+ * -> agentserver: PluginInstallService.Uninstall()
17750
+ * -> 软删除 DB + 异步同步到活跃沙箱
17751
+ *
17752
+ * @param pluginName - 插件名称
17753
+ * @param marketplaceName - 市场名称(用于标识唯一插件)
17754
+ * @param scope - 卸载范围 ('user' | 'project' | 'project-local')
17755
+ */
17756
+ async uninstallPlugin(pluginName, marketplaceName, scope) {
17757
+ try {
17758
+ const installId = await this.findPluginInstallId(pluginName);
17759
+ if (!installId) return {
17760
+ success: false,
17761
+ error: `Plugin not found or not installed: ${pluginName}`
17762
+ };
17763
+ await httpService.post(`/console/as/user/plugins/installed/${installId}/uninstall`);
17764
+ return { success: true };
17765
+ } catch (error) {
17766
+ return {
17767
+ success: false,
17768
+ error: this.extractErrorMessage(error)
17769
+ };
17770
+ }
17771
+ }
17772
+ /**
17773
+ * 获取插件市场列表
17774
+ * GET /console/as/marketplace/sources
17775
+ */
17776
+ async getPluginMarketplaces(forceRefresh) {
17777
+ try {
17778
+ const result = ((await httpService.get("/console/as/marketplace/sources")).data?.sources || []).map((src) => ({
17779
+ id: src.id,
17780
+ name: src.name,
17781
+ type: this.mapSourceType(src.source_type),
17782
+ source: { url: src.url },
17783
+ description: src.name,
17784
+ isBuiltin: src.is_default
17785
+ }));
17786
+ result.forEach((m) => {
17787
+ const marketplaceInfo = {
17788
+ id: m.id,
17789
+ name: m.name
17790
+ };
17791
+ this.marketplaceCache.set(m.name, marketplaceInfo);
17792
+ this.marketplaceCache.set(m.id, marketplaceInfo);
17793
+ });
17794
+ return result;
17795
+ } catch (error) {
17796
+ this.logger?.error("[CloudAgentProvider] getPluginMarketplaces failed:", error);
17797
+ throw error;
17798
+ }
17799
+ }
17800
+ /**
17801
+ * 获取市场下的插件列表
17802
+ * - 有 searchText: GET /console/as/marketplace/plugins/search (跨所有市场搜索)
17803
+ * - 无 searchText: GET /console/as/marketplace/plugins (指定市场)
17804
+ *
17805
+ * @param marketplaceNameOrId - 市场名称或 ID(优先使用 ID,如果是名称则从缓存查询 ID)
17806
+ * @param forceRefresh - 是否强制刷新
17807
+ * @param searchText - 搜索关键字(如果提供,则跨所有市场搜索)
17808
+ */
17809
+ async getMarketplacePlugins(marketplaceNameOrId, forceRefresh, searchText) {
17810
+ try {
17811
+ if (searchText) return ((await httpService.get("/console/as/marketplace/plugins/search", { params: {
17812
+ q: searchText,
17813
+ page: 1,
17814
+ page_size: 100
17815
+ } })).data?.plugins || []).map((p) => this.mapPluginData(p));
17816
+ const sourceId = await this.findMarketplaceId(marketplaceNameOrId);
17817
+ if (!sourceId) {
17818
+ this.logger?.warn(`[CloudAgentProvider] Marketplace not found: ${marketplaceNameOrId}`);
17819
+ return [];
17820
+ }
17821
+ const params = {
17822
+ source_id: sourceId,
17823
+ page: 1,
17824
+ page_size: 100
17825
+ };
17826
+ return ((await httpService.get("/console/as/marketplace/plugins", { params })).data?.plugins || []).map((p) => this.mapPluginData(p));
17827
+ } catch (error) {
17828
+ this.logger?.error("[CloudAgentProvider] getMarketplacePlugins failed:", error);
17829
+ throw error;
17830
+ }
17831
+ }
17832
+ /**
17833
+ * 获取插件详情
17834
+ * GET /console/as/marketplace/plugins/:name/detail
17835
+ *
17836
+ * @param pluginName - 插件名称
17837
+ * @param marketplaceNameOrId - 市场名称或 ID(优先使用 ID,如果是名称则从缓存查询 ID)
17838
+ */
17839
+ async getPluginDetail(pluginName, marketplaceNameOrId) {
17840
+ try {
17841
+ const sourceId = await this.findMarketplaceId(marketplaceNameOrId);
17842
+ if (!sourceId) {
17843
+ this.logger?.warn(`[CloudAgentProvider] Marketplace not found: ${marketplaceNameOrId}`);
17844
+ return null;
17845
+ }
17846
+ const p = (await httpService.get(`/console/as/marketplace/plugins/${pluginName}/detail`, { params: { source_id: sourceId } })).data?.plugin;
17847
+ if (!p) return null;
17848
+ const capabilities = p.capabilities ? this.parseCapabilities(p.capabilities) : {};
17849
+ const tags = p.tags ? JSON.parse(p.tags) : [];
17850
+ return {
17851
+ name: p.name,
17852
+ marketplaceName: p.marketplace_name,
17853
+ description: p.description,
17854
+ version: p.version,
17855
+ iconUrl: p.icon_url,
17856
+ tags,
17857
+ installed: p.installed,
17858
+ status: p.enabled ? "enabled" : p.installed ? "disabled" : "not-installed",
17859
+ readme: p.readme,
17860
+ author: p.author,
17861
+ homepage: p.homepage,
17862
+ repositoryUrl: p.repository_url,
17863
+ license: p.license,
17864
+ ...capabilities
17865
+ };
17866
+ } catch (error) {
17867
+ this.logger?.error("[CloudAgentProvider] getPluginDetail failed:", error);
17868
+ throw error;
17869
+ }
17870
+ }
17871
+ /**
17872
+ * 添加插件市场
17873
+ * POST /console/as/marketplace/sources
17874
+ */
17875
+ async addPluginMarketplace(sourceUrl, name) {
17876
+ try {
17877
+ const body = {
17878
+ source_type: sourceUrl.startsWith("http") ? "url" : "github",
17879
+ url: sourceUrl,
17880
+ name: name || sourceUrl
17881
+ };
17882
+ const sourceData = (await httpService.post("/console/as/marketplace/sources", body)).data?.source;
17883
+ if (!sourceData) throw new Error("Invalid response from server");
17884
+ const marketplaceInfo = {
17885
+ id: sourceData.id,
17886
+ name: sourceData.name
17887
+ };
17888
+ this.marketplaceCache.set(sourceData.name, marketplaceInfo);
17889
+ this.marketplaceCache.set(sourceData.id, marketplaceInfo);
17890
+ return {
17891
+ success: true,
17892
+ marketplace: {
17893
+ id: sourceData.id,
17894
+ name: sourceData.name,
17895
+ type: this.mapSourceType(sourceData.source_type),
17896
+ source: { url: sourceData.url },
17897
+ isBuiltin: sourceData.is_default
17898
+ }
17899
+ };
17900
+ } catch (error) {
17901
+ return {
17902
+ success: false,
17903
+ error: this.extractErrorMessage(error)
17904
+ };
17905
+ }
17906
+ }
17907
+ /**
17908
+ * 删除插件市场
17909
+ * POST /console/as/marketplace/sources/:id/delete
17910
+ */
17911
+ async removePluginMarketplace(marketplaceNameOrId) {
17912
+ try {
17913
+ const marketplaceId = await this.findMarketplaceId(marketplaceNameOrId);
17914
+ if (!marketplaceId) return {
17915
+ success: false,
17916
+ error: `Marketplace not found: ${marketplaceNameOrId}`
17917
+ };
17918
+ await httpService.post(`/console/as/marketplace/sources/${marketplaceId}/delete`, {});
17919
+ return { success: true };
17920
+ } catch (error) {
17921
+ return {
17922
+ success: false,
17923
+ error: this.extractErrorMessage(error)
17924
+ };
17925
+ }
17926
+ }
17927
+ /**
17928
+ * 刷新插件市场
17929
+ * POST /console/as/marketplace/sources/:id/check-updates
17930
+ */
17931
+ async refreshPluginMarketplace(marketplaceNameOrId) {
17932
+ try {
17933
+ const marketplaceId = await this.findMarketplaceId(marketplaceNameOrId);
17934
+ if (!marketplaceId) return {
17935
+ success: false,
17936
+ error: `Marketplace not found: ${marketplaceNameOrId}`
17937
+ };
17938
+ return {
17939
+ success: true,
17940
+ plugins: (await httpService.post(`/console/as/marketplace/sources/${marketplaceId}/check-updates`, {})).data?.updated_plugins || []
17941
+ };
17942
+ } catch (error) {
17943
+ return {
17944
+ success: false,
17945
+ error: this.extractErrorMessage(error)
17946
+ };
17947
+ }
17948
+ }
17949
+ /**
17950
+ * 批量切换插件启用/禁用状态
17951
+ * POST /console/as/user/plugins/installed/:id/toggle
17952
+ */
17953
+ async batchTogglePlugins(request) {
17954
+ try {
17955
+ const results = await Promise.allSettled(request.items.map(async (item) => {
17956
+ const installId = await this.findPluginInstallId(item.pluginName);
17957
+ if (!installId) throw new Error(`Plugin not found or not installed: ${item.pluginName}`);
17958
+ const enabled = item.operation === "enable";
17959
+ await httpService.post(`/console/as/user/plugins/installed/${installId}/toggle`, { enabled });
17960
+ return item;
17961
+ }));
17962
+ const succeededPlugins = [];
17963
+ const failedPlugins = [];
17964
+ results.forEach((r, i) => {
17965
+ const item = request.items[i];
17966
+ if (r.status === "fulfilled") succeededPlugins.push(item);
17967
+ else failedPlugins.push({
17968
+ ...item,
17969
+ error: r.reason?.message || "Unknown error"
17970
+ });
17971
+ });
17972
+ return {
17973
+ success: failedPlugins.length === 0,
17974
+ succeededPlugins,
17975
+ failedPlugins
17976
+ };
17977
+ } catch (error) {
17978
+ return {
17979
+ success: false,
17980
+ succeededPlugins: [],
17981
+ failedPlugins: request.items.map((item) => ({
17982
+ ...item,
17983
+ error: this.extractErrorMessage(error)
17984
+ }))
17985
+ };
17986
+ }
17987
+ }
17988
+ /**
17989
+ * 将后端插件数据映射为前端格式
17990
+ */
17991
+ mapPluginData(p) {
17992
+ const capabilities = p.capabilities ? this.parseCapabilities(p.capabilities) : {};
17993
+ let tags = [];
17994
+ if (p.tags) {
17995
+ if (Array.isArray(p.tags)) tags = p.tags;
17996
+ else if (typeof p.tags === "string") try {
17997
+ const parsed = JSON.parse(p.tags);
17998
+ tags = Array.isArray(parsed) ? parsed : [parsed];
17999
+ } catch {
18000
+ tags = p.tags.split(",").map((t) => t.trim()).filter((t) => t);
18001
+ }
18002
+ }
18003
+ return {
18004
+ name: p.name,
18005
+ marketplaceName: p.marketplace_name,
18006
+ description: p.description,
18007
+ version: p.version,
18008
+ iconUrl: p.icon_url,
18009
+ tags,
18010
+ installed: p.installed,
18011
+ status: p.enabled ? "enabled" : p.installed ? "disabled" : "not-installed",
18012
+ installedScopes: p.installed ? [p.installed_scope] : [],
18013
+ ...capabilities
18014
+ };
18015
+ }
18016
+ /**
18017
+ * 从缓存中查找插件的 install_id
18018
+ * 如果缓存未命中,则调用 API 获取并缓存
18019
+ *
18020
+ * @param pluginName - 插件名称
18021
+ * @returns install_id 或 null
18022
+ */
18023
+ async findPluginInstallId(pluginName) {
18024
+ const cached = this.pluginCache.get(pluginName);
18025
+ if (cached) return cached.installId;
18026
+ await this.getInstalledPlugins();
18027
+ return this.pluginCache.get(pluginName)?.installId || null;
18028
+ }
18029
+ /**
18030
+ * 从缓存中查找 marketplace ID
18031
+ * 如果缓存未命中,则调用 API 获取并缓存
18032
+ */
18033
+ async findMarketplaceId(nameOrId) {
18034
+ const cached = this.marketplaceCache.get(nameOrId);
18035
+ if (cached) return cached.id;
18036
+ await this.getPluginMarketplaces();
18037
+ return this.marketplaceCache.get(nameOrId)?.id || null;
18038
+ }
18039
+ /**
18040
+ * 提取 API 错误信息
18041
+ * 从 AxiosError 中提取详细的错误信息,包括 HTTP 状态码、错误码和错误消息
18042
+ */
18043
+ extractErrorMessage(error) {
18044
+ if (error instanceof AxiosError) {
18045
+ const status = error.response?.status;
18046
+ const apiResponse = error.response?.data;
18047
+ const parts = [];
18048
+ if (status) parts.push(`HTTP ${status}`);
18049
+ if (apiResponse?.code) parts.push(`Code ${apiResponse.code}`);
18050
+ if (apiResponse?.msg) parts.push(apiResponse.msg);
18051
+ else if (error.message) parts.push(error.message);
18052
+ const errorMessage = parts.join(" - ");
18053
+ this.logger?.error("[CloudAgentProvider] API Error:", {
18054
+ status,
18055
+ code: apiResponse?.code,
18056
+ msg: apiResponse?.msg,
18057
+ requestId: apiResponse?.requestId,
18058
+ url: error.config?.url,
18059
+ method: error.config?.method
18060
+ });
18061
+ return errorMessage;
18062
+ }
18063
+ if (error instanceof Error) return error.message;
18064
+ return "Unknown error";
18065
+ }
18066
+ /**
18067
+ * 映射后端 source_type 到前端类型
18068
+ */
18069
+ mapSourceType(sourceType) {
18070
+ switch (sourceType) {
18071
+ case "github": return "github";
18072
+ case "official": return "custom";
18073
+ default: return "custom";
18074
+ }
18075
+ }
18076
+ /**
18077
+ * 解析 capabilities JSON 字符串
18078
+ */
18079
+ parseCapabilities(capabilitiesStr) {
18080
+ try {
18081
+ const cap = JSON.parse(capabilitiesStr);
18082
+ return {
18083
+ commands: cap.commands,
18084
+ skills: cap.skills,
18085
+ mcpServers: cap.mcp,
18086
+ agents: cap.agents,
18087
+ hooks: cap.hooks,
18088
+ rules: cap.rules
18089
+ };
18090
+ } catch {
18091
+ return {};
18092
+ }
18093
+ }
18094
+ /**
18095
+ * 上报 telemetry 事件(Cloud 模式)
18096
+ * 通过 HTTP POST 发送到 /v2/report
18097
+ * 注入用户信息和浏览器环境等公共字段
18098
+ */
18099
+ async reportTelemetry(eventName, payload) {
18100
+ try {
18101
+ const account = accountService.getAccount();
18102
+ const commonFields = {};
18103
+ if (account) {
18104
+ commonFields.userId = account.uid;
18105
+ commonFields.userNickname = account.nickname;
18106
+ if (account.enterpriseId) commonFields.enterpriseId = account.enterpriseId;
18107
+ if (account.enterpriseUserName) commonFields.username = account.enterpriseUserName;
18108
+ }
18109
+ if (typeof navigator !== "undefined") {
18110
+ commonFields.userAgent = navigator.userAgent;
18111
+ commonFields.os = navigator.platform;
18112
+ }
18113
+ const events = [{
18114
+ eventCode: eventName,
18115
+ timestamp: Date.now(),
18116
+ reportDelay: 0,
18117
+ ...commonFields,
18118
+ ...payload
18119
+ }];
18120
+ await httpService.post("/v2/report", events);
18121
+ } catch (error) {
18122
+ this.logger?.warn("reportTelemetry() failed:", error);
18123
+ }
18124
+ }
18125
+ };
18126
+
18127
+ //#endregion
18128
+ //#region ../agent-provider/src/common/providers/local-agent-provider/local-connection.ts
18129
+ /**
18130
+ * Local Agent Connection
18131
+ * Wraps AcpJsonRpcClient to implement AgentConnection interface
18132
+ *
18133
+ * Uses IWidgetChannel for IPC communication with ExtensionHost
18134
+ * Migrated from ipc-agent-provider for unified local agent access
18135
+ */
18136
+
18137
+ //#endregion
18138
+ //#region ../agent-provider/src/common/client/session.ts
18139
+ /**
18140
+ * ActiveSessionImpl - Implements the ActiveSession interface
18141
+ *
18142
+ * This class wraps an AgentConnection and provides the session-centric API.
18143
+ * It is created by SessionManager when creating or loading sessions.
18144
+ *
18145
+ * @example
18146
+ * ```typescript
18147
+ * // Created by client.sessions.new() or client.sessions.load()
18148
+ * const session = await client.sessions.new({ cwd: '/workspace' });
18149
+ *
18150
+ * // Access agent state
18151
+ * console.log(session.agentState.status);
18152
+ *
18153
+ * // Send prompt
18154
+ * const response = await session.prompts.send({ content: 'Hello!' });
18155
+ *
18156
+ * // Cleanup
18157
+ * session.disconnect();
18158
+ * ```
18159
+ */
18160
+ var ActiveSessionImpl = class {
18161
+ /**
18162
+ * Create an ActiveSessionImpl instance
18163
+ *
18164
+ * @param sessionId - Session ID
18165
+ * @param agentId - Agent ID
18166
+ * @param connection - Already connected AgentConnection
18167
+ * @param options - Additional options
18168
+ */
18169
+ constructor(sessionId, agentId, connection, options = {}) {
18170
+ this._availableCommands = [];
18171
+ this.listeners = /* @__PURE__ */ new Map();
18172
+ this.onceListeners = /* @__PURE__ */ new Map();
18173
+ this.connectionListeners = [];
18174
+ this._id = sessionId;
18175
+ this._agentId = agentId;
18176
+ this.connection = connection;
17439
18177
  this.logger = options.logger;
17440
18178
  this._getFilesystem = options.getFilesystem;
17441
18179
  this._connectionInfo = options.connectionInfo;
@@ -17458,6 +18196,18 @@ var ActiveSessionImpl = class {
17458
18196
  return this._agentId;
17459
18197
  }
17460
18198
  /**
18199
+ * Actual workspace path (set from newSession response _meta)
18200
+ */
18201
+ get cwd() {
18202
+ return this._cwd;
18203
+ }
18204
+ /**
18205
+ * Set actual workspace path (called by SessionManager after createSession)
18206
+ */
18207
+ setCwd(cwd) {
18208
+ this._cwd = cwd;
18209
+ }
18210
+ /**
17461
18211
  * Agent state (live connection state)
17462
18212
  * Returns LocalAgentState or CloudAgentState based on transport type
17463
18213
  */
@@ -17651,10 +18401,10 @@ var ActiveSessionImpl = class {
17651
18401
  return this.connection.cancelQuestion(toolCallId, reason);
17652
18402
  }
17653
18403
  /**
17654
- * Callback for tool operations (skip or cancel)
18404
+ * Callback for tool operations (approve / skip / cancel)
17655
18405
  * @param toolCallId Tool call ID
17656
18406
  * @param toolName Tool name
17657
- * @param action Action to perform ('skip' or 'cancel')
18407
+ * @param action Action to perform ('approve' / 'skip' / 'cancel')
17658
18408
  */
17659
18409
  async toolCallback(toolCallId, toolName, action) {
17660
18410
  return await this.getConnectionOrThrow().toolCallback(this._id, toolCallId, toolName, action);
@@ -17698,6 +18448,7 @@ var ActiveSessionImpl = class {
17698
18448
  * ```
17699
18449
  */
17700
18450
  async setSessionModel(modelId) {
18451
+ this._currentModelId = modelId;
17701
18452
  await this.getConnectionOrThrow().setSessionModel(this._id, modelId);
17702
18453
  }
17703
18454
  /**
@@ -17775,11 +18526,23 @@ var ActiveSessionImpl = class {
17775
18526
  * Disconnect from the session/agent
17776
18527
  */
17777
18528
  disconnect() {
18529
+ this.removeConnectionListeners();
17778
18530
  this.connection.disconnect();
17779
18531
  this.removeAllListeners();
17780
18532
  this.logger?.info(`Session ${this._id}: Disconnected`);
17781
18533
  }
17782
18534
  /**
18535
+ * Detach the session from connection events without disconnecting the connection.
18536
+ * This should be called when the session is being replaced but the connection is shared.
18537
+ * Unlike disconnect(), this only removes event listeners without closing the connection.
18538
+ */
18539
+ detach() {
18540
+ this.logger?.info(`Session ${this._id}: Detaching from connection events`);
18541
+ this.removeConnectionListeners();
18542
+ this.removeAllListeners();
18543
+ this.logger?.info(`Session ${this._id}: Detached successfully`);
18544
+ }
18545
+ /**
17783
18546
  * Symbol.dispose for 'using' keyword support
17784
18547
  * Automatically disconnects and cleans up when session goes out of scope
17785
18548
  *
@@ -17798,60 +18561,85 @@ var ActiveSessionImpl = class {
17798
18561
  if (!this.connection.isInitialized) throw new Error(`Session ${this._id}: Connection not initialized.`);
17799
18562
  return this.connection;
17800
18563
  }
18564
+ /**
18565
+ * 在 connection 上注册 listener 并保存引用,便于 disconnect 时移除
18566
+ */
18567
+ addConnectionListener(connection, event, listener) {
18568
+ connection.on(event, listener);
18569
+ this.connectionListeners.push({
18570
+ event,
18571
+ listener
18572
+ });
18573
+ }
18574
+ /**
18575
+ * 从 connection 上移除所有本 session 注册的 listener
18576
+ */
18577
+ removeConnectionListeners() {
18578
+ for (const { event, listener } of this.connectionListeners) this.connection.off(event, listener);
18579
+ this.connectionListeners = [];
18580
+ }
17801
18581
  setupConnectionEvents(connection) {
17802
- connection.on("connected", () => {
18582
+ this.addConnectionListener(connection, "connected", () => {
17803
18583
  this.emit("connected", void 0);
17804
18584
  });
17805
- connection.on("disconnected", () => {
18585
+ this.addConnectionListener(connection, "disconnected", () => {
17806
18586
  this.emit("disconnected", void 0);
17807
18587
  });
17808
- connection.on("error", (error) => {
18588
+ this.addConnectionListener(connection, "error", (error) => {
17809
18589
  this.emit("error", error);
17810
18590
  });
17811
- connection.on("sessionUpdate", (update) => {
18591
+ this.addConnectionListener(connection, "sessionUpdate", (update) => {
18592
+ const notificationSessionId = update?.sessionId;
18593
+ if (notificationSessionId && notificationSessionId !== this._id) {
18594
+ console.log(`[RT-DEBUG][AgentMgr:Session] sessionUpdate SKIPPED: notifSessionId mismatch, notif=${notificationSessionId?.substring(0, 8)}, my=${this._id?.substring(0, 8)}`);
18595
+ return;
18596
+ }
17812
18597
  this.emit("sessionUpdate", update);
17813
18598
  });
17814
- connection.on("artifactCreated", (artifact) => {
17815
- console.log("[Session] Forwarding artifactCreated:", {
17816
- artifactUri: artifact.uri,
17817
- artifactType: artifact.type
17818
- });
18599
+ this.addConnectionListener(connection, "artifactCreated", (artifact) => {
18600
+ if (!this.shouldForwardArtifact(artifact)) return;
17819
18601
  this.emit("artifactCreated", artifact);
17820
18602
  });
17821
- connection.on("artifactUpdated", (artifact) => {
17822
- console.log("[Session] Forwarding artifactUpdated:", {
17823
- artifactUri: artifact.uri,
17824
- artifactType: artifact.type
17825
- });
18603
+ this.addConnectionListener(connection, "artifactUpdated", (artifact) => {
18604
+ if (!this.shouldForwardArtifact(artifact)) return;
17826
18605
  this.emit("artifactUpdated", artifact);
17827
18606
  });
17828
- connection.on("artifactDeleted", (artifact) => {
17829
- console.log("[Session] Forwarding artifactDeleted:", { artifactUri: artifact.uri });
18607
+ this.addConnectionListener(connection, "artifactDeleted", (artifact) => {
18608
+ if (!this.shouldForwardArtifact(artifact)) return;
17830
18609
  this.emit("artifactDeleted", artifact);
17831
18610
  });
17832
- connection.on("permissionRequest", (request) => {
18611
+ this.addConnectionListener(connection, "permissionRequest", (request) => {
17833
18612
  this.emit("permissionRequest", request);
17834
18613
  });
17835
- connection.on("questionRequest", (request) => {
18614
+ this.addConnectionListener(connection, "questionRequest", (request) => {
17836
18615
  this.emit("questionRequest", request);
17837
18616
  });
17838
- connection.on("questionCancelled", () => {
18617
+ this.addConnectionListener(connection, "questionCancelled", () => {
17839
18618
  this.prompts.cancel();
17840
18619
  });
17841
- connection.on("usageUpdate", (usage) => {
18620
+ this.addConnectionListener(connection, "usageUpdate", (usage) => {
17842
18621
  this.emit("usageUpdate", usage);
17843
18622
  });
17844
- connection.on("checkpointCreated", (checkpoint) => {
18623
+ this.addConnectionListener(connection, "checkpointCreated", (checkpoint) => {
18624
+ const originSessionId = checkpoint.__sessionId;
18625
+ if (originSessionId && originSessionId !== this._id) return;
17845
18626
  this.emit("checkpointCreated", checkpoint);
17846
18627
  });
17847
- connection.on("checkpointUpdated", (checkpoint) => {
18628
+ this.addConnectionListener(connection, "checkpointUpdated", (checkpoint) => {
18629
+ const originSessionId = checkpoint.__sessionId;
18630
+ if (originSessionId && originSessionId !== this._id) return;
17848
18631
  this.emit("checkpointUpdated", checkpoint);
17849
18632
  });
17850
- connection.on("command", (command) => {
17851
- console.log("[Session] Forwarding command:", {
17852
- action: command.action,
17853
- paramsKeys: command.params ? Object.keys(command.params) : []
17854
- });
18633
+ this.addConnectionListener(connection, "command", (command) => {
18634
+ const originSessionId = command.__sessionId;
18635
+ if (originSessionId && originSessionId !== this._id) {
18636
+ console.log("[Session] Command not forwarded:", {
18637
+ command,
18638
+ originSessionId,
18639
+ sessionId: this._id
18640
+ });
18641
+ return;
18642
+ }
17855
18643
  this.emit("command", command);
17856
18644
  });
17857
18645
  }
@@ -17861,6 +18649,15 @@ var ActiveSessionImpl = class {
17861
18649
  _meta: response._meta ?? void 0
17862
18650
  };
17863
18651
  }
18652
+ /**
18653
+ * 判断 artifact 是否应该转发给当前 session
18654
+ * 所有类型的 artifact 都按 __sessionId 严格隔离
18655
+ */
18656
+ shouldForwardArtifact(artifact) {
18657
+ const originSessionId = artifact.__sessionId;
18658
+ if (!originSessionId || originSessionId !== this._id) return false;
18659
+ return true;
18660
+ }
17864
18661
  };
17865
18662
 
17866
18663
  //#endregion
@@ -17893,6 +18690,7 @@ var ActiveSessionImpl = class {
17893
18690
  */
17894
18691
  var SessionManager = class {
17895
18692
  constructor(options) {
18693
+ this.pendingConnections = /* @__PURE__ */ new Map();
17896
18694
  this.provider = options.provider;
17897
18695
  this.logger = options.logger;
17898
18696
  }
@@ -17913,9 +18711,11 @@ var SessionManager = class {
17913
18711
  name: agent.name,
17914
18712
  status: agent.status,
17915
18713
  createdAt: agent.createdAt,
18714
+ updatedAt: agent.updatedAt,
17916
18715
  lastActivityAt: agent.updatedAt,
17917
18716
  cwd: agent.type === "local" ? agent.cwd : void 0,
17918
- isPlayground: agent.isPlayground
18717
+ isPlayground: agent.isPlayground,
18718
+ isUserDefinedTitle: agent.isUserDefinedTitle
17919
18719
  }));
17920
18720
  console.log("[SessionManager] Returning sessions:", {
17921
18721
  count: sessions.length,
@@ -17942,27 +18742,107 @@ var SessionManager = class {
17942
18742
  if (this.provider.create) {
17943
18743
  agentId = await this.provider.create(params);
17944
18744
  this.logger?.debug(`Created new agent: ${agentId}`);
18745
+ if (params.options?.onSessionPrepared) {
18746
+ const initialPrompt = params.options?.prompt;
18747
+ const initialTitle = initialPrompt?.slice(0, 50) || "";
18748
+ params.options.onSessionPrepared({
18749
+ id: agentId,
18750
+ agentId,
18751
+ name: initialTitle + (initialPrompt && initialPrompt.length > 50 ? "..." : ""),
18752
+ status: "connecting",
18753
+ cwd: params.cwd || "",
18754
+ createdAt: /* @__PURE__ */ new Date()
18755
+ });
18756
+ this.logger?.debug(`Called onSessionPrepared for: ${agentId}`);
18757
+ }
17945
18758
  } else throw new Error("Provider does not support creating agents. Use sessions.load() with an existing sessionId.");
17946
18759
  const connection = await this.provider.connect(agentId);
17947
18760
  this.logger?.debug(`Connected to agent: ${agentId}`);
17948
- const response = await connection.createSession({
17949
- _meta: params._meta,
17950
- cwd: params.cwd,
17951
- mcpServers: params.mcpServers
17952
- });
17953
- if (this.provider.registerSession) {
17954
- this.provider.registerSession(response.sessionId, agentId);
17955
- this.logger?.debug(`Registered session mapping: ${response.sessionId} → ${agentId}`);
18761
+ let response;
18762
+ try {
18763
+ response = await connection.createSession({
18764
+ _meta: params.options?._meta,
18765
+ cwd: params.cwd,
18766
+ mcpServers: params.options?.mcpServers
18767
+ });
18768
+ } catch (err) {
18769
+ this.pendingConnections.set(agentId, connection);
18770
+ this.logger?.debug(`Cached pending connection for agent: ${agentId}`);
18771
+ if (err instanceof SessionError) throw new SessionError(err.message, err.sessionId, agentId, err.cause instanceof Error ? err.cause : void 0);
18772
+ const cause = err instanceof Error ? err : new Error(String(err));
18773
+ throw new SessionError(`Failed to create session: ${cause.message}`, void 0, agentId, cause);
17956
18774
  }
17957
- const connectionInfo = connection.sessionConnectionInfo;
17958
- const session = new ActiveSessionImpl(response.sessionId, agentId, connection, {
17959
- logger: this.logger,
18775
+ return this.buildActiveSession(response, agentId, connection, params);
18776
+ }
18777
+ /**
18778
+ * Retry creating a session after initial session/new request failed.
18779
+ *
18780
+ * Use this when `sessions.create()` fails at the `session/new` step
18781
+ * (after agent creation and connection establishment succeeded).
18782
+ * The caller retrieves `agentId` from the thrown `SessionError.agentId`,
18783
+ * then calls this method to re-attempt only the `session/new` request
18784
+ * while reusing the already-initialized connection (no re-connect).
18785
+ *
18786
+ * @experimental This API is subject to change
18787
+ *
18788
+ * @param agentId - Agent ID from the failed SessionError
18789
+ * @param params - Original create session params (cwd, mcpServers, etc.)
18790
+ * @returns ActiveSession on success
18791
+ * @throws SessionError if session/new fails again
18792
+ *
18793
+ * @example
18794
+ * ```typescript
18795
+ * try {
18796
+ * const session = await client.sessions.create({ cwd: '/workspace' });
18797
+ * } catch (err) {
18798
+ * if (err instanceof SessionError && err.agentId) {
18799
+ * // Retry with custom logic
18800
+ * for (let i = 0; i < 3; i++) {
18801
+ * try {
18802
+ * const session = await client.sessions.retryNewSession(err.agentId, { cwd: '/workspace' });
18803
+ * break; // success
18804
+ * } catch (retryErr) {
18805
+ * await new Promise(r => setTimeout(r, 1000 * (i + 1)));
18806
+ * }
18807
+ * }
18808
+ * }
18809
+ * }
18810
+ * ```
18811
+ */
18812
+ async retryNewSession(agentId, params) {
18813
+ this.logger?.info(`Retrying session/new for agent: ${agentId}`);
18814
+ const connection = this.pendingConnections.get(agentId);
18815
+ if (!connection) throw new SessionError(`No pending connection found for agent: ${agentId}. retryNewSession() can only be called after a failed sessions.create().`, void 0, agentId);
18816
+ this.logger?.debug(`Reusing cached connection for agent: ${agentId}`);
18817
+ const response = await connection.createSession({
18818
+ _meta: params.options?._meta,
18819
+ cwd: params.cwd,
18820
+ mcpServers: params.options?.mcpServers
18821
+ });
18822
+ this.pendingConnections.delete(agentId);
18823
+ this.logger?.debug(`Cleared pending connection for agent: ${agentId}`);
18824
+ return this.buildActiveSession(response, agentId, connection, params);
18825
+ }
18826
+ /**
18827
+ * Build an ActiveSession from a NewSessionResponse.
18828
+ * Shared by createSession() and retryNewSession().
18829
+ */
18830
+ buildActiveSession(response, agentId, connection, params) {
18831
+ if (this.provider.registerSession) {
18832
+ this.provider.registerSession(response.sessionId, agentId);
18833
+ this.logger?.debug(`Registered session mapping: ${response.sessionId} → ${agentId}`);
18834
+ }
18835
+ const connectionInfo = connection.sessionConnectionInfo;
18836
+ const session = new ActiveSessionImpl(response.sessionId, agentId, connection, {
18837
+ logger: this.logger,
17960
18838
  getFilesystem: this.provider.filesystem ? () => this.provider.filesystem.getFilesystem(response.sessionId) : void 0,
17961
18839
  connectionInfo
17962
18840
  });
17963
18841
  session.setModes(response.modes?.availableModes, response.modes?.currentModeId);
17964
18842
  const availableModels = this.extractAvailableModels(response);
17965
18843
  if (availableModels) session.setModels(availableModels, response.models?.currentModelId);
18844
+ const responseCwd = response._meta?.["codebuddy.ai"]?.cwd;
18845
+ if (responseCwd) session.setCwd(responseCwd);
17966
18846
  this.logger?.info(`Session created: ${response.sessionId}`);
17967
18847
  return session;
17968
18848
  }
@@ -18091,6 +18971,7 @@ var AgentClient = class {
18091
18971
  return {
18092
18972
  list: async (options) => this.sessionManager.listSessions(options),
18093
18973
  create: async (params) => this.sessionManager.createSession(params),
18974
+ retryNewSession: async (agentId, params) => this.sessionManager.retryNewSession(agentId, params),
18094
18975
  load: async (params) => {
18095
18976
  console.log("[AgentClient] sessions.load called:", params.sessionId);
18096
18977
  return this.sessionManager.loadSession(params);
@@ -18129,6 +19010,26 @@ var AgentClient = class {
18129
19010
  throw error;
18130
19011
  }
18131
19012
  },
19013
+ updateStatus: async (sessionId, status) => {
19014
+ this.logger?.debug("AgentClient.sessions.updateStatus called", {
19015
+ sessionId,
19016
+ status
19017
+ });
19018
+ try {
19019
+ if (this.provider.updateStatus) {
19020
+ const result = await this.provider.updateStatus(sessionId, status);
19021
+ this.logger?.info("Session status updated successfully", {
19022
+ sessionId,
19023
+ status
19024
+ });
19025
+ return result;
19026
+ }
19027
+ throw new Error("Provider does not support updateStatus method");
19028
+ } catch (error) {
19029
+ this.logger?.error("Failed to update session status", error);
19030
+ throw error;
19031
+ }
19032
+ },
18132
19033
  move: async (sessionId) => {
18133
19034
  this.logger?.debug("AgentClient.sessions.move called", { sessionId });
18134
19035
  try {
@@ -18161,6 +19062,16 @@ var AgentClient = class {
18161
19062
  };
18162
19063
  }
18163
19064
  },
19065
+ requestYieldAfterCurrentStep: async (sessionId) => {
19066
+ try {
19067
+ if (this.provider?.requestYieldAfterCurrentStep) return await this.provider.requestYieldAfterCurrentStep(sessionId);
19068
+ this.logger?.warn("Provider does not support requestYieldAfterCurrentStep");
19069
+ return false;
19070
+ } catch (error) {
19071
+ this.logger?.error("Failed to request yield after current step", error);
19072
+ return false;
19073
+ }
19074
+ },
18164
19075
  getCurrentWorkspaces: async (filter) => {
18165
19076
  this.logger?.debug("AgentClient.sessions.getCurrentWorkspaces called", filter);
18166
19077
  try {
@@ -18176,6 +19087,100 @@ var AgentClient = class {
18176
19087
  return [];
18177
19088
  }
18178
19089
  },
19090
+ getAutomationSnapshot: async () => {
19091
+ try {
19092
+ if (this.provider?.getAutomationSnapshot) return await this.provider.getAutomationSnapshot();
19093
+ this.logger?.warn("Provider does not support getAutomationSnapshot");
19094
+ } catch (error) {
19095
+ this.logger?.error("Failed to get automation snapshot", error);
19096
+ }
19097
+ return {
19098
+ automations: [],
19099
+ inbox: [],
19100
+ runtimeState: {},
19101
+ updatedAt: Date.now()
19102
+ };
19103
+ },
19104
+ updateAutomation: async (payload) => {
19105
+ try {
19106
+ if (this.provider?.updateAutomation) return await this.provider.updateAutomation(payload);
19107
+ this.logger?.warn("Provider does not support updateAutomation");
19108
+ } catch (error) {
19109
+ this.logger?.error("Failed to update automation", error);
19110
+ return {
19111
+ success: false,
19112
+ message: error instanceof Error ? error.message : "Unknown error"
19113
+ };
19114
+ }
19115
+ return {
19116
+ success: false,
19117
+ message: "Provider does not support updateAutomation"
19118
+ };
19119
+ },
19120
+ deleteAutomation: async (id) => {
19121
+ try {
19122
+ if (this.provider?.deleteAutomation) return await this.provider.deleteAutomation(id);
19123
+ this.logger?.warn("Provider does not support deleteAutomation");
19124
+ } catch (error) {
19125
+ this.logger?.error("Failed to delete automation", error);
19126
+ return {
19127
+ success: false,
19128
+ message: error instanceof Error ? error.message : "Unknown error"
19129
+ };
19130
+ }
19131
+ return {
19132
+ success: false,
19133
+ message: "Provider does not support deleteAutomation"
19134
+ };
19135
+ },
19136
+ archiveAutomationInboxItem: async (itemId) => {
19137
+ try {
19138
+ if (this.provider?.archiveAutomationInboxItem) return await this.provider.archiveAutomationInboxItem(itemId);
19139
+ this.logger?.warn("Provider does not support archiveAutomationInboxItem");
19140
+ } catch (error) {
19141
+ this.logger?.error("Failed to archive automation inbox item", error);
19142
+ return {
19143
+ success: false,
19144
+ message: error instanceof Error ? error.message : "Unknown error"
19145
+ };
19146
+ }
19147
+ return {
19148
+ success: false,
19149
+ message: "Provider does not support archiveAutomationInboxItem"
19150
+ };
19151
+ },
19152
+ deleteAutomationInboxItem: async (itemId) => {
19153
+ try {
19154
+ if (this.provider?.deleteAutomationInboxItem) return await this.provider.deleteAutomationInboxItem(itemId);
19155
+ this.logger?.warn("Provider does not support deleteAutomationInboxItem");
19156
+ } catch (error) {
19157
+ this.logger?.error("Failed to delete automation inbox item", error);
19158
+ return {
19159
+ success: false,
19160
+ message: error instanceof Error ? error.message : "Unknown error"
19161
+ };
19162
+ }
19163
+ return {
19164
+ success: false,
19165
+ message: "Provider does not support deleteAutomationInboxItem"
19166
+ };
19167
+ },
19168
+ testAutomation: async (id) => {
19169
+ try {
19170
+ if (this.provider?.testAutomation) return await this.provider.testAutomation(id);
19171
+ this.logger?.warn("Provider does not support testAutomation");
19172
+ } catch (error) {
19173
+ this.logger?.error("Failed to test automation", error);
19174
+ return {
19175
+ success: false,
19176
+ message: error instanceof Error ? error.message : "Unknown error"
19177
+ };
19178
+ }
19179
+ return {
19180
+ success: false,
19181
+ message: "Provider does not support testAutomation"
19182
+ };
19183
+ },
18179
19184
  on: (event, handler) => {
18180
19185
  if (this.provider.on) this.provider.on(event, handler);
18181
19186
  else this.logger?.warn(`Provider does not support event registration: ${String(event)}`);
@@ -18317,6 +19322,167 @@ var AgentClient = class {
18317
19322
  };
18318
19323
  }
18319
19324
  },
19325
+ getSkillList: async (params) => {
19326
+ try {
19327
+ if (this.provider && this.provider.getSkillList) {
19328
+ const result = await this.provider.getSkillList(params);
19329
+ this.logger?.info("Skill list retrieved", {
19330
+ resultCount: result.results.length,
19331
+ hasError: !!result.error
19332
+ });
19333
+ return result;
19334
+ }
19335
+ return {
19336
+ results: [],
19337
+ error: "Provider does not support getSkillList"
19338
+ };
19339
+ } catch (error) {
19340
+ this.logger?.error("Failed to get skill list", error);
19341
+ return {
19342
+ results: [],
19343
+ error: error instanceof Error ? error.message : "Unknown error"
19344
+ };
19345
+ }
19346
+ },
19347
+ importSkill: async (params) => {
19348
+ try {
19349
+ if (this.provider && this.provider.importSkill) {
19350
+ const result = await this.provider.importSkill(params);
19351
+ this.logger?.info("Import skill completed", {
19352
+ success: result.success,
19353
+ hasError: !!result.error
19354
+ });
19355
+ return result;
19356
+ }
19357
+ return {
19358
+ success: false,
19359
+ error: "Provider does not support importSkill"
19360
+ };
19361
+ } catch (error) {
19362
+ this.logger?.error("Failed to import skill", error);
19363
+ return {
19364
+ success: false,
19365
+ error: error instanceof Error ? error.message : "Unknown error"
19366
+ };
19367
+ }
19368
+ },
19369
+ toggleSkill: async (params) => {
19370
+ try {
19371
+ if (this.provider && this.provider.toggleSkill) {
19372
+ const result = await this.provider.toggleSkill(params);
19373
+ this.logger?.info("Toggle skill completed", {
19374
+ success: result.success,
19375
+ hasError: !!result.error
19376
+ });
19377
+ return result;
19378
+ }
19379
+ return {
19380
+ success: false,
19381
+ error: "Provider does not support toggleSkill"
19382
+ };
19383
+ } catch (error) {
19384
+ this.logger?.error("Failed to toggle skill", error);
19385
+ return {
19386
+ success: false,
19387
+ error: error instanceof Error ? error.message : "Unknown error"
19388
+ };
19389
+ }
19390
+ },
19391
+ deleteSkill: async (params) => {
19392
+ try {
19393
+ if (this.provider && this.provider.deleteSkill) {
19394
+ const result = await this.provider.deleteSkill(params);
19395
+ this.logger?.info("Delete skill completed", {
19396
+ success: result.success,
19397
+ hasError: !!result.error
19398
+ });
19399
+ return result;
19400
+ }
19401
+ return {
19402
+ success: false,
19403
+ error: "Provider does not support deleteSkill"
19404
+ };
19405
+ } catch (error) {
19406
+ this.logger?.error("Failed to delete skill", error);
19407
+ return {
19408
+ success: false,
19409
+ error: error instanceof Error ? error.message : "Unknown error"
19410
+ };
19411
+ }
19412
+ },
19413
+ getSkillContent: async (params) => {
19414
+ try {
19415
+ if (this.provider && this.provider.getSkillContent) {
19416
+ const result = await this.provider.getSkillContent(params);
19417
+ this.logger?.info("Get skill content completed", { hasError: !!result.error });
19418
+ return result;
19419
+ }
19420
+ return {
19421
+ content: "",
19422
+ error: "Provider does not support getSkillContent"
19423
+ };
19424
+ } catch (error) {
19425
+ this.logger?.error("Failed to get skill content", error);
19426
+ return {
19427
+ content: "",
19428
+ error: error instanceof Error ? error.message : "Unknown error"
19429
+ };
19430
+ }
19431
+ },
19432
+ getMarketplaceSkills: async () => {
19433
+ try {
19434
+ if (this.provider && this.provider.getMarketplaceSkills) {
19435
+ const result = await this.provider.getMarketplaceSkills();
19436
+ this.logger?.info("Marketplace skills retrieved", {
19437
+ resultCount: result.results.length,
19438
+ hasError: !!result.error
19439
+ });
19440
+ return result;
19441
+ }
19442
+ return {
19443
+ results: [],
19444
+ error: "Provider does not support getMarketplaceSkills"
19445
+ };
19446
+ } catch (error) {
19447
+ this.logger?.error("Failed to get marketplace skills", error);
19448
+ return {
19449
+ results: [],
19450
+ error: error instanceof Error ? error.message : "Unknown error"
19451
+ };
19452
+ }
19453
+ },
19454
+ getMarketplaceSkillContent: async (params) => {
19455
+ try {
19456
+ if (this.provider && this.provider.getMarketplaceSkillContent) return await this.provider.getMarketplaceSkillContent(params);
19457
+ return {
19458
+ content: "",
19459
+ error: "Provider does not support getMarketplaceSkillContent"
19460
+ };
19461
+ } catch (error) {
19462
+ this.logger?.error("Failed to get marketplace skill content", error);
19463
+ return {
19464
+ content: "",
19465
+ error: error instanceof Error ? error.message : "Unknown error"
19466
+ };
19467
+ }
19468
+ },
19469
+ installMarketplaceSkill: async (params) => {
19470
+ try {
19471
+ if (this.provider && this.provider.installMarketplaceSkill) return await this.provider.installMarketplaceSkill(params);
19472
+ return {
19473
+ success: false,
19474
+ skillName: params.skillName,
19475
+ errorMessage: "Provider does not support installMarketplaceSkill"
19476
+ };
19477
+ } catch (error) {
19478
+ this.logger?.error("Failed to install marketplace skill", error);
19479
+ return {
19480
+ success: false,
19481
+ skillName: params.skillName,
19482
+ errorMessage: error instanceof Error ? error.message : "Unknown error"
19483
+ };
19484
+ }
19485
+ },
18320
19486
  batchTogglePlugins: async (request) => {
18321
19487
  try {
18322
19488
  if (this.provider && this.provider.batchTogglePlugins) {
@@ -18361,10 +19527,10 @@ var AgentClient = class {
18361
19527
  return [];
18362
19528
  }
18363
19529
  },
18364
- installPlugins: async (pluginNames, marketplaceName, installScope, marketplaceSource) => {
19530
+ installPlugins: async (pluginNames, marketplaceName, installScope, marketplaceSource, workspacePath) => {
18365
19531
  try {
18366
19532
  if (this.provider && "installPlugins" in this.provider && typeof this.provider.installPlugins === "function") {
18367
- const result = await this.provider.installPlugins(pluginNames, marketplaceName, installScope, marketplaceSource);
19533
+ const result = await this.provider.installPlugins(pluginNames, marketplaceName, installScope, marketplaceSource, workspacePath);
18368
19534
  this.logger?.info("Install plugins", {
18369
19535
  pluginNames,
18370
19536
  marketplaceName,
@@ -18385,37 +19551,399 @@ var AgentClient = class {
18385
19551
  };
18386
19552
  }
18387
19553
  },
18388
- getSupportScenes: async () => {
19554
+ uninstallPlugin: async (pluginName, marketplaceName, scope) => {
19555
+ try {
19556
+ if (this.provider && "uninstallPlugin" in this.provider && typeof this.provider.uninstallPlugin === "function") {
19557
+ const result = await this.provider.uninstallPlugin(pluginName, marketplaceName, scope);
19558
+ this.logger?.info("Uninstall plugin", {
19559
+ pluginName,
19560
+ marketplaceName,
19561
+ scope,
19562
+ success: result.success
19563
+ });
19564
+ return result;
19565
+ }
19566
+ this.logger?.warn("Provider does not support uninstallPlugin");
19567
+ return {
19568
+ success: false,
19569
+ error: "Provider does not support uninstallPlugin"
19570
+ };
19571
+ } catch (error) {
19572
+ this.logger?.error("Failed to uninstall plugin", error);
19573
+ return {
19574
+ success: false,
19575
+ error: error instanceof Error ? error.message : "Unknown error"
19576
+ };
19577
+ }
19578
+ },
19579
+ updatePlugin: async (pluginName, marketplaceName) => {
18389
19580
  try {
18390
- if (this.provider && "getSupportScenes" in this.provider && typeof this.provider.getSupportScenes === "function") {
18391
- const result = await this.provider.getSupportScenes();
18392
- this.logger?.info("Got support scenes", { count: result?.length ?? 0 });
19581
+ if (this.provider && "updatePlugin" in this.provider && typeof this.provider.updatePlugin === "function") {
19582
+ const result = await this.provider.updatePlugin(pluginName, marketplaceName);
19583
+ this.logger?.info("Update plugin", {
19584
+ pluginName,
19585
+ marketplaceName,
19586
+ success: result.success
19587
+ });
18393
19588
  return result;
18394
19589
  }
19590
+ this.logger?.warn("Provider does not support updatePlugin");
19591
+ return {
19592
+ success: false,
19593
+ error: "Provider does not support updatePlugin"
19594
+ };
19595
+ } catch (error) {
19596
+ this.logger?.error("Failed to update plugin", error);
19597
+ return {
19598
+ success: false,
19599
+ error: error instanceof Error ? error.message : "Unknown error"
19600
+ };
19601
+ }
19602
+ },
19603
+ getPluginMarketplaces: async (forceRefresh) => {
19604
+ try {
19605
+ if (this.provider && "getPluginMarketplaces" in this.provider && typeof this.provider.getPluginMarketplaces === "function") {
19606
+ const result = await this.provider.getPluginMarketplaces(forceRefresh);
19607
+ this.logger?.info("Got plugin marketplaces", { count: result?.length ?? 0 });
19608
+ return result;
19609
+ }
19610
+ this.logger?.warn("Provider does not support getPluginMarketplaces");
19611
+ return [];
19612
+ } catch (error) {
19613
+ this.logger?.error("Failed to get plugin marketplaces", error);
19614
+ return [];
19615
+ }
19616
+ },
19617
+ getMarketplacePlugins: async (marketplaceName, forceRefresh, searchText) => {
19618
+ try {
19619
+ if (this.provider && "getMarketplacePlugins" in this.provider && typeof this.provider.getMarketplacePlugins === "function") {
19620
+ const result = await this.provider.getMarketplacePlugins(marketplaceName, forceRefresh, searchText);
19621
+ this.logger?.info("Got marketplace plugins", {
19622
+ marketplaceName,
19623
+ count: result?.length ?? 0
19624
+ });
19625
+ return result;
19626
+ }
19627
+ this.logger?.warn("Provider does not support getMarketplacePlugins");
19628
+ return [];
19629
+ } catch (error) {
19630
+ this.logger?.error("Failed to get marketplace plugins", error);
19631
+ return [];
19632
+ }
19633
+ },
19634
+ getPluginDetail: async (pluginName, marketplaceName) => {
19635
+ try {
19636
+ if (this.provider && "getPluginDetail" in this.provider && typeof this.provider.getPluginDetail === "function") {
19637
+ const result = await this.provider.getPluginDetail(pluginName, marketplaceName);
19638
+ this.logger?.info("Got plugin detail", {
19639
+ pluginName,
19640
+ marketplaceName
19641
+ });
19642
+ return result;
19643
+ }
19644
+ this.logger?.warn("Provider does not support getPluginDetail");
19645
+ return null;
19646
+ } catch (error) {
19647
+ this.logger?.error("Failed to get plugin detail", error);
19648
+ return null;
19649
+ }
19650
+ },
19651
+ addPluginMarketplace: async (source, name) => {
19652
+ try {
19653
+ if (this.provider && "addPluginMarketplace" in this.provider && typeof this.provider.addPluginMarketplace === "function") {
19654
+ const result = await this.provider.addPluginMarketplace(source, name);
19655
+ this.logger?.info("Add plugin marketplace", {
19656
+ source,
19657
+ name,
19658
+ success: result.success
19659
+ });
19660
+ return result;
19661
+ }
19662
+ this.logger?.warn("Provider does not support addPluginMarketplace");
19663
+ return {
19664
+ success: false,
19665
+ error: "Provider does not support addPluginMarketplace"
19666
+ };
19667
+ } catch (error) {
19668
+ this.logger?.error("Failed to add plugin marketplace", error);
19669
+ return {
19670
+ success: false,
19671
+ error: error instanceof Error ? error.message : "Unknown error"
19672
+ };
19673
+ }
19674
+ },
19675
+ removePluginMarketplace: async (marketplaceName) => {
19676
+ try {
19677
+ if (this.provider && "removePluginMarketplace" in this.provider && typeof this.provider.removePluginMarketplace === "function") {
19678
+ const result = await this.provider.removePluginMarketplace(marketplaceName);
19679
+ this.logger?.info("Remove plugin marketplace", {
19680
+ marketplaceName,
19681
+ success: result.success
19682
+ });
19683
+ return result;
19684
+ }
19685
+ this.logger?.warn("Provider does not support removePluginMarketplace");
19686
+ return {
19687
+ success: false,
19688
+ error: "Provider does not support removePluginMarketplace"
19689
+ };
19690
+ } catch (error) {
19691
+ this.logger?.error("Failed to remove plugin marketplace", error);
19692
+ return {
19693
+ success: false,
19694
+ error: error instanceof Error ? error.message : "Unknown error"
19695
+ };
19696
+ }
19697
+ },
19698
+ refreshPluginMarketplace: async (marketplaceName) => {
19699
+ try {
19700
+ if (this.provider && "refreshPluginMarketplace" in this.provider && typeof this.provider.refreshPluginMarketplace === "function") {
19701
+ const result = await this.provider.refreshPluginMarketplace(marketplaceName);
19702
+ this.logger?.info("Refresh plugin marketplace", {
19703
+ marketplaceName,
19704
+ success: result.success
19705
+ });
19706
+ return result;
19707
+ }
19708
+ this.logger?.warn("Provider does not support refreshPluginMarketplace");
19709
+ return {
19710
+ success: false,
19711
+ error: "Provider does not support refreshPluginMarketplace"
19712
+ };
19713
+ } catch (error) {
19714
+ this.logger?.error("Failed to refresh plugin marketplace", error);
19715
+ return {
19716
+ success: false,
19717
+ error: error instanceof Error ? error.message : "Unknown error"
19718
+ };
19719
+ }
19720
+ },
19721
+ openFolderInNewWindow: async (folderPath) => {
19722
+ try {
19723
+ if (this.provider && "openFolderInNewWindow" in this.provider && typeof this.provider.openFolderInNewWindow === "function") {
19724
+ await this.provider.openFolderInNewWindow(folderPath);
19725
+ this.logger?.info("Opened folder in new window", { folderPath });
19726
+ } else {
19727
+ this.logger?.warn("Provider does not support openFolderInNewWindow");
19728
+ throw new Error("Provider does not support openFolderInNewWindow");
19729
+ }
19730
+ } catch (error) {
19731
+ this.logger?.error("Failed to open folder in new window", error);
19732
+ throw error;
19733
+ }
19734
+ },
19735
+ openFolder: async (folderPath) => {
19736
+ try {
19737
+ if (this.provider && "openFolder" in this.provider && typeof this.provider.openFolder === "function") {
19738
+ const result = await this.provider.openFolder(folderPath);
19739
+ this.logger?.info("Opened folder in system file manager", { folderPath });
19740
+ return result;
19741
+ } else {
19742
+ this.logger?.warn("Provider does not support openFolder");
19743
+ throw new Error("Provider does not support openFolder");
19744
+ }
19745
+ } catch (error) {
19746
+ this.logger?.error("Failed to open folder", error);
19747
+ throw error;
19748
+ }
19749
+ },
19750
+ getSupportScenes: async (locale) => {
19751
+ try {
19752
+ if (this.provider && "getSupportScenes" in this.provider && typeof this.provider.getSupportScenes === "function") return await this.provider.getSupportScenes(locale);
18395
19753
  this.logger?.warn("Provider does not support getSupportScenes");
18396
19754
  return [];
18397
19755
  } catch (error) {
18398
- this.logger?.error("Failed to get support scenes", error);
19756
+ this.logger?.error("Failed to get support scenes", error);
19757
+ return [];
19758
+ }
19759
+ },
19760
+ getProductScenes: async (locale) => {
19761
+ try {
19762
+ if (this.provider?.getProductScenes) {
19763
+ const result = await this.provider.getProductScenes(locale);
19764
+ this.logger?.info("Got product scenes", { count: result?.length ?? 0 });
19765
+ return result;
19766
+ }
19767
+ this.logger?.warn("Provider does not support getProductScenes");
19768
+ return [];
19769
+ } catch (error) {
19770
+ this.logger?.error("Failed to get product scenes", error);
18399
19771
  return [];
18400
19772
  }
18401
19773
  },
18402
- getAvailableCommands: async (sessionId) => {
19774
+ getAvailableCommands: async (params) => {
18403
19775
  try {
18404
19776
  if (this.provider && "getAvailableCommands" in this.provider && typeof this.provider.getAvailableCommands === "function") {
18405
- const result = await this.provider.getAvailableCommands(sessionId);
19777
+ const result = await this.provider.getAvailableCommands(params);
18406
19778
  this.logger?.info("Got available commands from provider", {
18407
- sessionId: sessionId ?? "(default)",
19779
+ sessionId: params?.sessionId ?? "(default)",
18408
19780
  count: result?.length ?? 0
18409
19781
  });
18410
19782
  return result;
18411
19783
  }
18412
- this.logger?.warn("Provider does not support getAvailableCommands", { sessionId });
19784
+ this.logger?.warn("Provider does not support getAvailableCommands", { params });
18413
19785
  return [];
18414
19786
  } catch (error) {
18415
19787
  this.logger?.error("Failed to get available commands", error);
18416
19788
  return [];
18417
19789
  }
18418
19790
  },
19791
+ reportTelemetry: async (eventName, payload) => {
19792
+ try {
19793
+ if (this.provider?.reportTelemetry) await this.provider.reportTelemetry(eventName, payload);
19794
+ else this.logger?.warn("Provider does not support reportTelemetry");
19795
+ } catch (error) {
19796
+ this.logger?.error("Failed to report telemetry", error);
19797
+ }
19798
+ },
19799
+ getProductConfiguration: async () => {
19800
+ try {
19801
+ if (this.provider?.getProductConfiguration) return await this.provider.getProductConfiguration();
19802
+ this.logger?.warn("Provider does not support getProductConfiguration");
19803
+ return {};
19804
+ } catch (error) {
19805
+ this.logger?.error("Failed to get product configuration", error);
19806
+ return {};
19807
+ }
19808
+ },
19809
+ getUserInfo: async () => {
19810
+ this.logger?.info("[AgentClient.sessions] getUserInfo() called");
19811
+ try {
19812
+ if (this.provider?.getUserInfo) {
19813
+ const result = await this.provider.getUserInfo();
19814
+ this.logger?.info("[AgentClient.sessions] getUserInfo() result:", JSON.stringify(result));
19815
+ return result;
19816
+ }
19817
+ this.logger?.warn("Provider does not support getUserInfo");
19818
+ return {};
19819
+ } catch (error) {
19820
+ this.logger?.error("Failed to get user info", error);
19821
+ return {};
19822
+ }
19823
+ },
19824
+ respondToSampling: async (sessionId, response) => {
19825
+ try {
19826
+ if (this.provider?.respondToSampling) {
19827
+ await this.provider.respondToSampling(sessionId, response);
19828
+ this.logger?.info("Responded to sampling request", {
19829
+ sessionId,
19830
+ requestId: response.id,
19831
+ approved: response.approved
19832
+ });
19833
+ } else this.logger?.warn("Provider does not support respondToSampling");
19834
+ } catch (error) {
19835
+ this.logger?.error("Failed to respond to sampling request", error);
19836
+ throw error;
19837
+ }
19838
+ },
19839
+ respondToRoots: async (sessionId, response) => {
19840
+ try {
19841
+ if (this.provider?.respondToRoots) {
19842
+ await this.provider.respondToRoots(sessionId, response);
19843
+ this.logger?.info("Responded to roots request", {
19844
+ sessionId,
19845
+ requestId: response.id,
19846
+ approved: response.approved
19847
+ });
19848
+ } else this.logger?.warn("Provider does not support respondToRoots");
19849
+ } catch (error) {
19850
+ this.logger?.error("Failed to respond to roots request", error);
19851
+ throw error;
19852
+ }
19853
+ },
19854
+ subscribeSamplingRequests: (serverName, callback) => {
19855
+ if (this.provider?.subscribeSamplingRequests) {
19856
+ this.logger?.info("Subscribing to sampling requests", { serverName });
19857
+ return this.provider.subscribeSamplingRequests(serverName, callback);
19858
+ }
19859
+ this.logger?.warn("Provider does not support subscribeSamplingRequests");
19860
+ return () => {};
19861
+ },
19862
+ subscribeRootsRequests: (serverName, callback) => {
19863
+ if (this.provider?.subscribeRootsRequests) {
19864
+ this.logger?.info("Subscribing to roots requests", { serverName });
19865
+ return this.provider.subscribeRootsRequests(serverName, callback);
19866
+ }
19867
+ this.logger?.warn("Provider does not support subscribeRootsRequests");
19868
+ return () => {};
19869
+ },
19870
+ getMcpServers: async () => {
19871
+ if (this.provider?.getMcpServers) {
19872
+ this.logger?.info("Getting MCP servers list");
19873
+ return this.provider.getMcpServers();
19874
+ }
19875
+ this.logger?.warn("Provider does not support getMcpServers");
19876
+ return [];
19877
+ },
19878
+ toggleMcpServer: async (serverName, enabled) => {
19879
+ if (this.provider?.toggleMcpServer) {
19880
+ this.logger?.info("Toggling MCP server", {
19881
+ serverName,
19882
+ enabled
19883
+ });
19884
+ await this.provider.toggleMcpServer(serverName, enabled);
19885
+ } else {
19886
+ this.logger?.warn("Provider does not support toggleMcpServer");
19887
+ throw new Error("toggleMcpServer not supported by provider");
19888
+ }
19889
+ },
19890
+ reconnectMcpServer: async (serverName, forceHttpCallback) => {
19891
+ if (this.provider?.reconnectMcpServer) {
19892
+ this.logger?.info("Reconnecting MCP server", {
19893
+ serverName,
19894
+ forceHttpCallback
19895
+ });
19896
+ await this.provider.reconnectMcpServer(serverName, forceHttpCallback);
19897
+ } else {
19898
+ this.logger?.warn("Provider does not support reconnectMcpServer");
19899
+ throw new Error("reconnectMcpServer not supported by provider");
19900
+ }
19901
+ },
19902
+ deleteMcpServer: async (serverName) => {
19903
+ if (this.provider?.deleteMcpServer) {
19904
+ this.logger?.info("Deleting MCP server", { serverName });
19905
+ await this.provider.deleteMcpServer(serverName);
19906
+ } else {
19907
+ this.logger?.warn("Provider does not support deleteMcpServer");
19908
+ throw new Error("deleteMcpServer not supported by provider");
19909
+ }
19910
+ },
19911
+ openMcpConfig: async () => {
19912
+ if (this.provider?.openMcpConfig) {
19913
+ this.logger?.info("Opening MCP config");
19914
+ await this.provider.openMcpConfig();
19915
+ } else {
19916
+ this.logger?.warn("Provider does not support openMcpConfig");
19917
+ throw new Error("openMcpConfig not supported by provider");
19918
+ }
19919
+ },
19920
+ getMcpConfigContent: async () => {
19921
+ if (this.provider?.getMcpConfigContent) {
19922
+ this.logger?.info("Getting MCP config content");
19923
+ return await this.provider.getMcpConfigContent();
19924
+ } else {
19925
+ this.logger?.warn("Provider does not support getMcpConfigContent");
19926
+ throw new Error("getMcpConfigContent not supported by provider");
19927
+ }
19928
+ },
19929
+ saveMcpConfigContent: async (content) => {
19930
+ if (this.provider?.saveMcpConfigContent) {
19931
+ this.logger?.info("Saving MCP config content");
19932
+ await this.provider.saveMcpConfigContent(content);
19933
+ } else {
19934
+ this.logger?.warn("Provider does not support saveMcpConfigContent");
19935
+ throw new Error("saveMcpConfigContent not supported by provider");
19936
+ }
19937
+ },
19938
+ clipboardReadText: async () => {
19939
+ if (this.provider?.clipboardReadText) {
19940
+ this.logger?.info("Reading clipboard text");
19941
+ return await this.provider.clipboardReadText();
19942
+ } else {
19943
+ this.logger?.warn("Provider does not support clipboardReadText");
19944
+ throw new Error("clipboardReadText not supported by provider");
19945
+ }
19946
+ },
18419
19947
  models: this.createModelsResource()
18420
19948
  };
18421
19949
  }
@@ -18641,10 +20169,6 @@ const oauthRepositoryService = new OAuthRepositoryService();
18641
20169
  * 判断当前账号是否是 SSO 账号
18642
20170
  * 通过 account.accountType === 'sso' 来判断,这种不行,因为未登录之前account 为空
18643
20171
  */
18644
- const isSSODomain = () => {
18645
- const { hostname } = window.location;
18646
- return hostname.includes(".sso.copilot") || hostname.includes("sso.codebuddy.cn") || hostname.includes(".sso.copilot-staging") || hostname.includes(".staging-sso.codebuddy.cn");
18647
- };
18648
20172
  /**
18649
20173
  * 根据路径获取完整 URL
18650
20174
  * - SSO 账号需要跳转到对应的预发/生产域名
@@ -18652,16 +20176,7 @@ const isSSODomain = () => {
18652
20176
  * @param path 路径,如 '/login'、'/logout'、'/home' 等
18653
20177
  * @returns 完整的 URL 地址
18654
20178
  */
18655
- const getFullUrl = (path) => {
18656
- const { hostname, protocol } = window.location;
18657
- if (isSSODomain()) {
18658
- const isCodebuddy = hostname.includes("codebuddy.cn");
18659
- const isStaging = hostname.includes("staging");
18660
- if (isCodebuddy) return isStaging ? `${protocol}//staging.codebuddy.cn${path}` : `${protocol}//www.codebuddy.cn${path}`;
18661
- else return isStaging ? `${protocol}//staging-copilot.tencent.com${path}` : `${protocol}//copilot.tencent.com${path}`;
18662
- }
18663
- return `${window.location.origin}${path}`;
18664
- };
20179
+ const getFullUrl = (path) => `${window.location.origin}${path}`;
18665
20180
  /** 获取当前域名的账号选择页面 URL */
18666
20181
  const getSelectAccountUrl = () => `${window.location.origin}/login/select`;
18667
20182
  /** localStorage 中存储选中账号 ID 的 key */
@@ -18694,16 +20209,34 @@ const getPackageName = (packageCode) => CommodityCodeText[packageCode] || "";
18694
20209
  * 注意:getAgents 和 getModels 方法已废弃并移除,
18695
20210
  * 请使用 IAgentAdapter 中的对应方法
18696
20211
  */
18697
- var BackendProvider = class {
20212
+ var BackendProvider = class BackendProvider {
18698
20213
  constructor(config) {
18699
20214
  httpService.setBaseURL(config.baseUrl);
18700
20215
  if (config.authToken) httpService.setAuthToken(config.authToken);
18701
- httpService.onUnauthorized(() => {
18702
- console.log("[BackendProvider] User unauthorized (401/403), triggering logout");
18703
- this.logout().catch((error) => {
18704
- console.error("[BackendProvider] Logout failed in 401 handler:", error);
20216
+ httpService.onUnauthorized(() => this.handleUnauthorized());
20217
+ }
20218
+ /**
20219
+ * 处理 401 未授权错误
20220
+ * 先尝试刷新 token,失败后再执行登出流程
20221
+ *
20222
+ * @throws 如果 token 刷新失败,抛出错误通知 HttpService 不要重试
20223
+ */
20224
+ async handleUnauthorized() {
20225
+ console.log("[BackendProvider] User unauthorized (401), attempting token refresh first");
20226
+ try {
20227
+ if (await this.refreshToken()) {
20228
+ console.log("[BackendProvider] Token refresh successful after 401, user still logged in");
20229
+ return;
20230
+ }
20231
+ throw new Error("Token refresh returned null");
20232
+ } catch (error) {
20233
+ console.error("[BackendProvider] Token refresh failed after 401:", error);
20234
+ console.log("[BackendProvider] Token refresh failed, triggering logout");
20235
+ this.logout().catch((logoutError) => {
20236
+ console.error("[BackendProvider] Logout failed in 401 handler:", logoutError);
18705
20237
  });
18706
- });
20238
+ throw error;
20239
+ }
18707
20240
  }
18708
20241
  /**
18709
20242
  * 获取当前账号信息
@@ -18967,10 +20500,11 @@ var BackendProvider = class {
18967
20500
  if (!time) return 0;
18968
20501
  return new Date(time).getTime();
18969
20502
  };
18970
- const dailyCredits = [CommodityCode.free, CommodityCode.freeMon];
20503
+ const dailyCredits = [CommodityCode.free];
18971
20504
  const planResources = resources.map((r) => {
18972
20505
  const isDaily = dailyCredits.includes(r.PackageCode);
18973
20506
  const endTime = isDaily ? r.CycleEndTime : r.DeductionEndTime;
20507
+ const refreshAt = parseTime(r.CycleEndTime) + 1e3;
18974
20508
  return {
18975
20509
  id: r.ResourceId,
18976
20510
  name: isDaily ? "plan.addonCredits" : getPackageName(r.PackageCode),
@@ -18980,7 +20514,7 @@ var BackendProvider = class {
18980
20514
  used: Math.max(0, Number(r.CycleCapacitySizePrecise) - Number(r.CycleCapacityRemainPrecise)) || 0,
18981
20515
  left: Number(r.CycleCapacityRemainPrecise) || 0,
18982
20516
  expireAt: parseTime(endTime),
18983
- refreshAt: isDaily ? void 0 : parseTime(r.CycleEndTime)
20517
+ refreshAt: isDaily ? void 0 : refreshAt
18984
20518
  };
18985
20519
  }).sort((a, b) => {
18986
20520
  const getPriority = (code) => {
@@ -18988,10 +20522,11 @@ var BackendProvider = class {
18988
20522
  CommodityCode.proMon,
18989
20523
  CommodityCode.proMonPlus,
18990
20524
  CommodityCode.proYear,
20525
+ CommodityCode.freeMon,
18991
20526
  CommodityCode.extra
18992
20527
  ].includes(code)) return 1;
18993
20528
  if ([CommodityCode.gift, CommodityCode.activity].includes(code)) return 2;
18994
- if ([CommodityCode.free, CommodityCode.freeMon].includes(code)) return 3;
20529
+ if ([CommodityCode.free].includes(code)) return 3;
18995
20530
  return 4;
18996
20531
  };
18997
20532
  return getPriority(a.packageCode) - getPriority(b.packageCode);
@@ -19116,34 +20651,65 @@ var BackendProvider = class {
19116
20651
  }
19117
20652
  /**
19118
20653
  * 登出账号
19119
- * Web 环境: 通过 iframe 访问登出 URL 清除 cookie
20654
+ *
20655
+ * 策略:
20656
+ * - IOA 企业:用 iframe 走 SSO/SAML SLO 登出链路(涉及跨域重定向),通过轮询 iframe URL 变化检测完成
20657
+ * - 非 IOA 企业:直接用 httpService 请求 /console/logout,速度快
19120
20658
  */
19121
20659
  async logout() {
19122
- const url = `${httpService.getAxiosInstance().defaults.baseURL}/console/logout`;
20660
+ const account = accountService.getAccount();
20661
+ if (account?.enterpriseId && ["esoikz80kd8g", "etahzsqej0n4"].includes(account.enterpriseId)) await this.logoutViaIframe();
20662
+ else await this.logoutViaHttp();
20663
+ localStorage.removeItem(SELECTED_ACCOUNT_KEY);
20664
+ accountService.clearAccount();
20665
+ }
20666
+ /**
20667
+ * IOA 企业登出:通过 iframe 走 SSO/SAML SLO 登出链路
20668
+ * 轮询 iframe URL 变化检测完成,兜底超时 5 秒
20669
+ */
20670
+ async logoutViaIframe() {
20671
+ const logoutUrl = `${httpService.getAxiosInstance().defaults.baseURL}/console/logout`;
19123
20672
  try {
19124
20673
  await new Promise((resolve) => {
19125
20674
  const iframe = document.createElement("iframe");
19126
20675
  iframe.style.cssText = "position:fixed;top:-9999px;left:-9999px;width:1px;height:1px;border:none;";
19127
- iframe.src = url;
19128
- const timeout = setTimeout(() => {
19129
- cleanup();
19130
- resolve();
19131
- }, 5e3);
19132
- const cleanup = () => {
20676
+ iframe.src = logoutUrl;
20677
+ let pollTimer;
20678
+ let settled = false;
20679
+ const done = () => {
20680
+ if (settled) return;
20681
+ settled = true;
20682
+ clearInterval(pollTimer);
19133
20683
  clearTimeout(timeout);
19134
20684
  if (iframe.parentNode) iframe.parentNode.removeChild(iframe);
19135
- };
19136
- iframe.onerror = () => {
19137
- cleanup();
19138
20685
  resolve();
19139
20686
  };
20687
+ let wasRedirecting = false;
20688
+ pollTimer = setInterval(() => {
20689
+ try {
20690
+ const href = iframe.contentWindow?.location?.href;
20691
+ if (wasRedirecting && href) done();
20692
+ } catch {
20693
+ wasRedirecting = true;
20694
+ }
20695
+ }, 100);
20696
+ const timeout = setTimeout(done, 5e3);
20697
+ iframe.onerror = done;
19140
20698
  document.body.appendChild(iframe);
19141
20699
  });
19142
20700
  } catch (error) {
19143
- console.error("[BackendProvider] logout failed:", error);
20701
+ console.error("[BackendProvider] logout via iframe failed:", error);
20702
+ }
20703
+ }
20704
+ /**
20705
+ * 非 IOA 企业登出:直接 HTTP 请求 /console/logout
20706
+ */
20707
+ async logoutViaHttp() {
20708
+ try {
20709
+ await httpService.get("/console/logout");
20710
+ } catch (error) {
20711
+ console.error("[BackendProvider] logout via http failed:", error);
19144
20712
  }
19145
- localStorage.removeItem(SELECTED_ACCOUNT_KEY);
19146
- accountService.clearAccount();
19147
20713
  }
19148
20714
  /**
19149
20715
  * 批量切换插件状态
@@ -19221,6 +20787,132 @@ var BackendProvider = class {
19221
20787
  async getRepositories(connector, page = 0, perPage = 100) {
19222
20788
  return oauthRepositoryService.getRepositories(connector, page, perPage);
19223
20789
  }
20790
+ /**
20791
+ * 保存待发送的输入内容到后端
20792
+ * API 端点: POST /api/v1/code-id
20793
+ */
20794
+ async savePendingInput(code) {
20795
+ try {
20796
+ const result = await httpService.post("/api/v1/code-id", { code });
20797
+ return result?.codeId || result?.data?.codeId || null;
20798
+ } catch (e) {
20799
+ console.warn("[BackendProvider] savePendingInput failed:", e);
20800
+ return null;
20801
+ }
20802
+ }
20803
+ /**
20804
+ * 从后端加载待发送的输入内容
20805
+ * API 端点: GET /api/v1/code?id=xxx
20806
+ */
20807
+ async loadPendingInput(codeId) {
20808
+ try {
20809
+ const result = await httpService.get(`/api/v1/code?id=${encodeURIComponent(codeId)}`);
20810
+ return result?.code || result?.data?.code || null;
20811
+ } catch (e) {
20812
+ console.warn("[BackendProvider] loadPendingInput failed:", e);
20813
+ return null;
20814
+ }
20815
+ }
20816
+ /**
20817
+ * 获取每日签到状态
20818
+ * API 端点: POST /billing/meter/checkin-status
20819
+ */
20820
+ async getCheckinStatus() {
20821
+ try {
20822
+ const result = await httpService.post("/billing/meter/checkin-status", {});
20823
+ if (result?.code === 0 && result?.data) return result.data;
20824
+ return null;
20825
+ } catch (error) {
20826
+ console.error("[BackendProvider] getCheckinStatus failed:", error);
20827
+ return null;
20828
+ }
20829
+ }
20830
+ /**
20831
+ * 执行每日签到
20832
+ * API 端点: POST /billing/meter/daily-checkin
20833
+ */
20834
+ async claimDailyCheckin() {
20835
+ const result = await httpService.post("/billing/meter/daily-checkin", {});
20836
+ if (result?.code === 0 && result?.data) return result.data;
20837
+ throw new Error(result?.msg || "Checkin failed");
20838
+ }
20839
+ static {
20840
+ this.SKILLHUB_BASE_URL = "https://lightmake.site";
20841
+ }
20842
+ static {
20843
+ this.SKILLHUB_FETCH_TIMEOUT = 1e4;
20844
+ }
20845
+ async skillHubFetch(url, init) {
20846
+ const controller = new AbortController();
20847
+ const timer = setTimeout(() => controller.abort(), BackendProvider.SKILLHUB_FETCH_TIMEOUT);
20848
+ try {
20849
+ return await fetch(url, {
20850
+ ...init,
20851
+ signal: controller.signal
20852
+ });
20853
+ } finally {
20854
+ clearTimeout(timer);
20855
+ }
20856
+ }
20857
+ async getSkillHubList(params = {}) {
20858
+ const qs = new URLSearchParams();
20859
+ if (params.page) qs.set("page", String(params.page));
20860
+ if (params.pageSize) qs.set("pageSize", String(params.pageSize));
20861
+ if (params.sortBy) qs.set("sortBy", params.sortBy);
20862
+ if (params.order) qs.set("order", params.order);
20863
+ if (params.keyword) qs.set("keyword", params.keyword);
20864
+ if (params.category) qs.set("category", params.category);
20865
+ const res = await this.skillHubFetch(`${BackendProvider.SKILLHUB_BASE_URL}/api/skills?${qs.toString()}`);
20866
+ if (!res.ok) throw new Error(`SkillHub list: ${res.status}`);
20867
+ return res.json();
20868
+ }
20869
+ async getSkillHubCategories() {
20870
+ const res = await this.skillHubFetch(`${BackendProvider.SKILLHUB_BASE_URL}/api/v1/categories`);
20871
+ if (!res.ok) throw new Error(`SkillHub categories: ${res.status}`);
20872
+ return res.json();
20873
+ }
20874
+ async getSkillHubSearch(q, limit = 20) {
20875
+ const qs = new URLSearchParams({
20876
+ q,
20877
+ limit: String(limit)
20878
+ });
20879
+ const res = await this.skillHubFetch(`${BackendProvider.SKILLHUB_BASE_URL}/api/v1/search?${qs.toString()}`);
20880
+ if (!res.ok) throw new Error(`SkillHub search: ${res.status}`);
20881
+ return res.json();
20882
+ }
20883
+ async getSkillHubDetail(slug) {
20884
+ const res = await this.skillHubFetch(`${BackendProvider.SKILLHUB_BASE_URL}/api/v1/skills/${encodeURIComponent(slug)}`);
20885
+ if (!res.ok) throw new Error(`SkillHub detail: ${res.status}`);
20886
+ return res.json();
20887
+ }
20888
+ async getSkillHubExists(slugs) {
20889
+ const res = await this.skillHubFetch(`${BackendProvider.SKILLHUB_BASE_URL}/api/v1/skills/exists`, {
20890
+ method: "POST",
20891
+ headers: { "Content-Type": "application/json" },
20892
+ body: JSON.stringify({ slugs })
20893
+ });
20894
+ if (!res.ok) throw new Error(`SkillHub exists: ${res.status}`);
20895
+ return res.json();
20896
+ }
20897
+ async reportSkillHubStats(slug, inc) {
20898
+ try {
20899
+ await this.skillHubFetch(`${BackendProvider.SKILLHUB_BASE_URL}/api/v1/skills/${encodeURIComponent(slug)}/stats/inc`, {
20900
+ method: "POST",
20901
+ headers: { "Content-Type": "application/json" },
20902
+ body: JSON.stringify(inc)
20903
+ });
20904
+ } catch {}
20905
+ }
20906
+ async installSkillHubSkill(_slug, _version, _name) {
20907
+ return {
20908
+ success: false,
20909
+ skillName: _slug,
20910
+ errorMessage: "SkillHub install requires IDE mode (no IPC channel available)"
20911
+ };
20912
+ }
20913
+ async getSkillHubInstalledMetas() {
20914
+ return [];
20915
+ }
19224
20916
  };
19225
20917
  /**
19226
20918
  * 创建 BackendProvider 实例
@@ -19259,10 +20951,26 @@ const BACKEND_REQUEST_TYPES = {
19259
20951
  REVOKE_ALL: "backend:revoke-all",
19260
20952
  GET_FILE: "backend:get-file",
19261
20953
  RELOAD_WINDOW: "backend:reload-window",
20954
+ SAVE_LOCALE: "backend:save-locale",
19262
20955
  CLOSE_AGENT_MANAGER: "backend:close-agent-manager",
19263
20956
  OPEN_EXTERNAL: "backend:open-external",
20957
+ OPEN_LOCAL_FILE: "backend:open-local-file",
20958
+ GET_LOCAL_CUSTOM_MODELS: "backend:get-local-custom-models",
20959
+ SAVE_LOCAL_CUSTOM_MODEL: "backend:save-local-custom-model",
20960
+ DELETE_LOCAL_CUSTOM_MODEL: "backend:delete-local-custom-model",
19264
20961
  BATCH_TOGGLE_PLUGINS: "backend:batch-toggle-plugins",
19265
- GET_SUPPORT_SCENES: "backend:get-support-scenes"
20962
+ GET_SUPPORT_SCENES: "backend:get-support-scenes",
20963
+ GET_ACCOUNT_USAGE: "backend:get-account-usage",
20964
+ GET_CHECKIN_STATUS: "backend:get-checkin-status",
20965
+ CLAIM_DAILY_CHECKIN: "backend:claim-daily-checkin",
20966
+ GET_ACTIVITY_BANNER: "backend:get-activity-banner",
20967
+ SKILLHUB_LIST: "backend:skillhub-list",
20968
+ SKILLHUB_CATEGORIES: "backend:skillhub-categories",
20969
+ SKILLHUB_SEARCH: "backend:skillhub-search",
20970
+ SKILLHUB_DETAIL: "backend:skillhub-detail",
20971
+ SKILLHUB_DOWNLOAD_URL: "backend:skillhub-download-url",
20972
+ SKILLHUB_EXISTS: "backend:skillhub-exists",
20973
+ SKILLHUB_REPORT_STATS: "backend:skillhub-report-stats"
19266
20974
  };
19267
20975
  /**
19268
20976
  * 生成唯一请求 ID
@@ -19281,6 +20989,25 @@ var IPCBackendProvider = class {
19281
20989
  this.debug = config.debug ?? false;
19282
20990
  this.timeoutMs = config.timeoutMs ?? 3e4;
19283
20991
  this.log("Initialized with IWidgetChannel");
20992
+ this.setupSessionChangeListener();
20993
+ }
20994
+ /**
20995
+ * 设置会话变化监听器
20996
+ * 监听来自 Extension Host (BackendBridgeService) 推送的 auth:session-changed 事件
20997
+ * 并更新本地 accountService
20998
+ */
20999
+ setupSessionChangeListener() {
21000
+ this.log("Setting up session change listener");
21001
+ this.channel.on("auth:session-changed", (data) => {
21002
+ this.log("Received auth:session-changed event from Extension Host:", data);
21003
+ const account = data?.account || null;
21004
+ accountService.setAccount(account);
21005
+ this.log("Updated accountService with new session", {
21006
+ hasAccount: !!account,
21007
+ accountNickname: account?.nickname
21008
+ });
21009
+ });
21010
+ this.log("Session change listener setup complete");
19284
21011
  }
19285
21012
  /**
19286
21013
  * 发送统一格式的后端请求
@@ -19309,12 +21036,14 @@ var IPCBackendProvider = class {
19309
21036
  */
19310
21037
  async getAccount() {
19311
21038
  this.log("Getting account via IPC");
21039
+ const startTime = performance.now();
19312
21040
  try {
19313
21041
  const account = await this.sendBackendRequest(BACKEND_REQUEST_TYPES.GET_ACCOUNT);
21042
+ this.log(`getAccount IPC completed in ${(performance.now() - startTime).toFixed(0)}ms`);
19314
21043
  accountService.setAccount(account);
19315
21044
  return account;
19316
21045
  } catch (error) {
19317
- this.log("Get account failed:", error);
21046
+ this.log(`getAccount IPC failed after ${(performance.now() - startTime).toFixed(0)}ms:`, error);
19318
21047
  accountService.setAccount(null);
19319
21048
  return null;
19320
21049
  }
@@ -19543,6 +21272,20 @@ var IPCBackendProvider = class {
19543
21272
  }
19544
21273
  }
19545
21274
  /**
21275
+ * Save locale to argv.json without restarting the app.
21276
+ * The change takes effect on next manual restart.
21277
+ * @param params locale to save
21278
+ */
21279
+ async saveLocale(params) {
21280
+ this.log("Saving locale to argv.json via IPC", params);
21281
+ try {
21282
+ await this.sendBackendRequest(BACKEND_REQUEST_TYPES.SAVE_LOCALE, params);
21283
+ } catch (error) {
21284
+ this.log("Save locale request failed:", error);
21285
+ throw error;
21286
+ }
21287
+ }
21288
+ /**
19546
21289
  * 关闭 Agent Manager 面板
19547
21290
  * IDE 环境: 通过 IPC 通知 IDE 关闭 Agent Manager(用于返回 IDE)
19548
21291
  */
@@ -19570,6 +21313,41 @@ var IPCBackendProvider = class {
19570
21313
  }
19571
21314
  }
19572
21315
  /**
21316
+ * 打开本地文件
21317
+ * IDE 环境: 通过 IPC 通知 IDE 打开本地配置文件
21318
+ * @param filePath 要打开的文件路径
21319
+ */
21320
+ async openLocalFile(filePath) {
21321
+ this.log("Opening local file via IPC:", filePath);
21322
+ try {
21323
+ if (!await this.sendBackendRequest(BACKEND_REQUEST_TYPES.OPEN_LOCAL_FILE, { filePath })) throw new Error(`Failed to open local file: ${filePath}`);
21324
+ } catch (error) {
21325
+ this.log("Open local file request failed:", error);
21326
+ throw error;
21327
+ }
21328
+ }
21329
+ /**
21330
+ * 获取用户级本地自定义模型
21331
+ */
21332
+ async getLocalCustomModels() {
21333
+ this.log("Getting local custom models via IPC");
21334
+ return await this.sendBackendRequest(BACKEND_REQUEST_TYPES.GET_LOCAL_CUSTOM_MODELS);
21335
+ }
21336
+ /**
21337
+ * 保存用户级本地自定义模型
21338
+ */
21339
+ async saveLocalCustomModel(request) {
21340
+ this.log("Saving local custom model via IPC:", request);
21341
+ return await this.sendBackendRequest(BACKEND_REQUEST_TYPES.SAVE_LOCAL_CUSTOM_MODEL, request);
21342
+ }
21343
+ /**
21344
+ * 删除用户级本地自定义模型
21345
+ */
21346
+ async deleteLocalCustomModel(id) {
21347
+ this.log("Deleting local custom model via IPC:", id);
21348
+ return await this.sendBackendRequest(BACKEND_REQUEST_TYPES.DELETE_LOCAL_CUSTOM_MODEL, { id });
21349
+ }
21350
+ /**
19573
21351
  * 批量切换插件状态
19574
21352
  * IDE 环境: 通过 IPC 调用 Extension Host 的 PluginService
19575
21353
  */
@@ -19603,6 +21381,187 @@ var IPCBackendProvider = class {
19603
21381
  }
19604
21382
  }
19605
21383
  /**
21384
+ * 获取账号用量信息(积分/Credits)
21385
+ * IDE 环境: 通过 IPC 实时获取用量信息,每次打开菜单时调用
21386
+ *
21387
+ * 调用链:
21388
+ * 1. agent-ui: IPCBackendProvider.getAccountUsage()
21389
+ * 2. Agent Manager renderer: BackendService.getAccountUsage()
21390
+ * 3. Main Process: codebuddy:getAccountUsage IPC handler
21391
+ * 4. 返回 { usageLeft, usageTotal, editionType, refreshAt } 等字段
21392
+ */
21393
+ async getAccountUsage() {
21394
+ this.log("Getting account usage via IPC");
21395
+ try {
21396
+ return await this.sendBackendRequest(BACKEND_REQUEST_TYPES.GET_ACCOUNT_USAGE);
21397
+ } catch (error) {
21398
+ this.log("Get account usage failed:", error);
21399
+ return null;
21400
+ }
21401
+ }
21402
+ /**
21403
+ * 获取每日签到状态
21404
+ * IDE 环境: 通过 IPC 获取签到状态
21405
+ */
21406
+ async getCheckinStatus() {
21407
+ this.log("Getting checkin status via IPC");
21408
+ try {
21409
+ return await this.sendBackendRequest(BACKEND_REQUEST_TYPES.GET_CHECKIN_STATUS);
21410
+ } catch (error) {
21411
+ this.log("Get checkin status failed:", error);
21412
+ return null;
21413
+ }
21414
+ }
21415
+ /**
21416
+ * 执行每日签到
21417
+ * IDE 环境: 通过 IPC 执行签到
21418
+ */
21419
+ async claimDailyCheckin() {
21420
+ this.log("Claiming daily checkin via IPC");
21421
+ try {
21422
+ return await this.sendBackendRequest(BACKEND_REQUEST_TYPES.CLAIM_DAILY_CHECKIN);
21423
+ } catch (error) {
21424
+ this.log("Claim daily checkin failed:", error);
21425
+ throw error;
21426
+ }
21427
+ }
21428
+ /**
21429
+ * 获取活动 Banner
21430
+ * IDE 环境: 通过 IPC 获取活动 Banner
21431
+ */
21432
+ async getActivityBanner() {
21433
+ this.log("Getting activity banner via IPC");
21434
+ try {
21435
+ return await this.sendBackendRequest(BACKEND_REQUEST_TYPES.GET_ACTIVITY_BANNER);
21436
+ } catch (error) {
21437
+ this.log("Get activity banner failed:", error);
21438
+ return null;
21439
+ }
21440
+ }
21441
+ /**
21442
+ * 获取 SkillHub 技能列表
21443
+ * IDE 环境: 通过 IPC 获取技能列表
21444
+ */
21445
+ async getSkillHubList(params) {
21446
+ this.log("Getting SkillHub list via IPC", params);
21447
+ try {
21448
+ return await this.sendBackendRequest(BACKEND_REQUEST_TYPES.SKILLHUB_LIST, params);
21449
+ } catch (error) {
21450
+ this.log("Get SkillHub list failed:", error);
21451
+ throw error;
21452
+ }
21453
+ }
21454
+ /**
21455
+ * 获取 SkillHub 分类列表
21456
+ * IDE 环境: 通过 IPC 获取分类列表
21457
+ */
21458
+ async getSkillHubCategories() {
21459
+ this.log("Getting SkillHub categories via IPC");
21460
+ try {
21461
+ return await this.sendBackendRequest(BACKEND_REQUEST_TYPES.SKILLHUB_CATEGORIES);
21462
+ } catch (error) {
21463
+ this.log("Get SkillHub categories failed:", error);
21464
+ throw error;
21465
+ }
21466
+ }
21467
+ /**
21468
+ * 搜索 SkillHub 技能
21469
+ * IDE 环境: 通过 IPC 搜索技能
21470
+ */
21471
+ async getSkillHubSearch(q, limit = 20) {
21472
+ this.log("Searching SkillHub via IPC", {
21473
+ q,
21474
+ limit
21475
+ });
21476
+ try {
21477
+ return await this.sendBackendRequest(BACKEND_REQUEST_TYPES.SKILLHUB_SEARCH, {
21478
+ q,
21479
+ limit
21480
+ });
21481
+ } catch (error) {
21482
+ this.log("SkillHub search failed:", error);
21483
+ throw error;
21484
+ }
21485
+ }
21486
+ /**
21487
+ * 获取 SkillHub 技能详情
21488
+ * IDE 环境: 通过 IPC 获取技能详情
21489
+ */
21490
+ async getSkillHubDetail(slug) {
21491
+ this.log("Getting SkillHub detail via IPC", { slug });
21492
+ try {
21493
+ return await this.sendBackendRequest(BACKEND_REQUEST_TYPES.SKILLHUB_DETAIL, { slug });
21494
+ } catch (error) {
21495
+ this.log("Get SkillHub detail failed:", error);
21496
+ throw error;
21497
+ }
21498
+ }
21499
+ /**
21500
+ * 批量检查 SkillHub 技能是否存在
21501
+ * IDE 环境: 通过 IPC 检查技能是否存在
21502
+ */
21503
+ async getSkillHubExists(slugs) {
21504
+ this.log("Checking SkillHub exists via IPC", { slugs });
21505
+ try {
21506
+ return await this.sendBackendRequest(BACKEND_REQUEST_TYPES.SKILLHUB_EXISTS, { slugs });
21507
+ } catch (error) {
21508
+ this.log("SkillHub exists check failed:", error);
21509
+ throw error;
21510
+ }
21511
+ }
21512
+ /**
21513
+ * 上报 SkillHub 技能统计
21514
+ * IDE 环境: 通过 IPC 上报统计
21515
+ */
21516
+ async reportSkillHubStats(slug, inc) {
21517
+ this.log("Reporting SkillHub stats via IPC", {
21518
+ slug,
21519
+ inc
21520
+ });
21521
+ try {
21522
+ await this.sendBackendRequest(BACKEND_REQUEST_TYPES.SKILLHUB_REPORT_STATS, {
21523
+ slug,
21524
+ inc
21525
+ });
21526
+ } catch (error) {
21527
+ this.log("Report SkillHub stats failed:", error);
21528
+ }
21529
+ }
21530
+ /**
21531
+ * 安装 SkillHub 技能
21532
+ * IDE 环境: 通过 IPC 安装技能(下载 zip → 解压到本地)
21533
+ */
21534
+ async installSkillHubSkill(slug, version, name) {
21535
+ this.log("Installing SkillHub skill via IPC", {
21536
+ slug,
21537
+ version,
21538
+ name
21539
+ });
21540
+ try {
21541
+ return await this.sendBackendRequest("backend:skillhub-install", {
21542
+ slug,
21543
+ version,
21544
+ name
21545
+ });
21546
+ } catch (error) {
21547
+ this.log("Install SkillHub skill failed:", error);
21548
+ throw error;
21549
+ }
21550
+ }
21551
+ /**
21552
+ * 获取本地已安装的 SkillHub 技能元信息
21553
+ * IDE 环境: 通过 IPC 获取元信息
21554
+ */
21555
+ async getSkillHubInstalledMetas() {
21556
+ this.log("Getting SkillHub installed metas via IPC");
21557
+ try {
21558
+ return await this.sendBackendRequest("backend:skillhub-installed-metas");
21559
+ } catch (error) {
21560
+ this.log("Get SkillHub installed metas failed:", error);
21561
+ return [];
21562
+ }
21563
+ }
21564
+ /**
19606
21565
  * 调试日志
19607
21566
  */
19608
21567
  log(...args) {
@@ -19622,10 +21581,12 @@ exports.AgentClient = AgentClient;
19622
21581
  exports.BackendProvider = BackendProvider;
19623
21582
  exports.CloudAgentConnection = CloudAgentConnection;
19624
21583
  exports.CloudAgentProvider = CloudAgentProvider;
19625
- exports.E2BFilesystem = E2BFilesystem;
21584
+ exports.E2BFilesystem = require_e2b_filesystem.E2BFilesystem;
19626
21585
  exports.HttpService = HttpService;
19627
21586
  exports.IPCBackendProvider = IPCBackendProvider;
21587
+ exports.SessionError = SessionError;
19628
21588
  exports.SessionManager = SessionManager;
21589
+ exports.__toESM = __toESM;
19629
21590
  exports.createBackendProvider = createBackendProvider;
19630
21591
  exports.createIPCBackendProvider = createIPCBackendProvider;
19631
21592
  exports.httpService = httpService;