@tencent-ai/cloud-agent-sdk 0.2.13 → 0.2.14-next.cb03fb2.20260319

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");
@@ -1913,6 +1913,9 @@ var StreamableHttpClient = class {
1913
1913
  headers: this.options.headers,
1914
1914
  reconnect: this.options.reconnect,
1915
1915
  fetch: this.options.fetch,
1916
+ heartbeatTimeout: this.options.heartbeatTimeout,
1917
+ postTimeout: this.options.postTimeout,
1918
+ connectionTimeout: this.options.connectionTimeout,
1916
1919
  onConnect: (connectionId) => {
1917
1920
  this.options.logger?.debug(`Transport connected: ${connectionId}`);
1918
1921
  },
@@ -1987,10 +1990,6 @@ var StreamableHttpClient = class {
1987
1990
  },
1988
1991
  requestPermission: async (params) => this.handleRequestPermission(params),
1989
1992
  extNotification: async (method, params) => {
1990
- console.log("[ACP-Client] extNotification callback invoked:", {
1991
- method,
1992
- paramsKeys: Object.keys(params)
1993
- });
1994
1993
  await this.handleExtNotification(method, params);
1995
1994
  },
1996
1995
  extMethod: async (method, params) => this.handleExtMethod(method, params)
@@ -1998,10 +1997,15 @@ var StreamableHttpClient = class {
1998
1997
  }
1999
1998
  /**
2000
1999
  * Create a new session
2000
+ *
2001
+ * Retries on transient network errors (e.g., proxy connection reset)
2002
+ * since session/new is idempotent and safe to retry.
2001
2003
  */
2002
2004
  async createSession(cwd) {
2003
2005
  this.ensureInitialized("createSession");
2004
- try {
2006
+ const maxRetries = 2;
2007
+ let lastError;
2008
+ for (let attempt = 0; attempt <= maxRetries; attempt++) try {
2005
2009
  const response = await this.connection.newSession({
2006
2010
  cwd,
2007
2011
  mcpServers: []
@@ -2009,8 +2013,16 @@ var StreamableHttpClient = class {
2009
2013
  this.options.logger?.info(`Session created: ${response.sessionId}`);
2010
2014
  return response;
2011
2015
  } 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);
2016
+ lastError = err instanceof Error ? err : new Error(String(err));
2017
+ if (attempt < maxRetries && isRetryableNetworkError(err)) {
2018
+ const delay = 500 * Math.pow(2, attempt);
2019
+ this.options.logger?.warn(`session/new network error, retrying in ${delay}ms (attempt ${attempt + 1}/${maxRetries}): ${lastError.message}`);
2020
+ await new Promise((resolve) => setTimeout(resolve, delay));
2021
+ continue;
2022
+ }
2023
+ throw new SessionError(`Failed to create session: ${lastError.message}`, void 0, lastError);
2013
2024
  }
2025
+ throw new SessionError(`Failed to create session: ${lastError?.message}`, void 0, lastError);
2014
2026
  }
2015
2027
  /**
2016
2028
  * Load an existing session
@@ -2234,6 +2246,18 @@ var StreamableHttpClient = class {
2234
2246
  if (this.state !== "initialized") throw new InvalidStateError(operation, this.state, ["initialized"]);
2235
2247
  }
2236
2248
  };
2249
+ /**
2250
+ * Check if an error is a retryable network-level error.
2251
+ * Only network failures (TypeError from fetch) are retried, NOT HTTP errors (4xx/5xx).
2252
+ */
2253
+ function isRetryableNetworkError(error) {
2254
+ if (error instanceof TypeError) return true;
2255
+ if (error instanceof Error) {
2256
+ const msg = error.message.toLowerCase();
2257
+ 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");
2258
+ }
2259
+ return false;
2260
+ }
2237
2261
 
2238
2262
  //#endregion
2239
2263
  //#region ../agent-provider/src/common/providers/cloud-agent-provider/cloud-connection.ts
@@ -2269,7 +2293,7 @@ var CloudAgentConnection = class {
2269
2293
  fetch: config.fetch,
2270
2294
  clientCapabilities: config.clientCapabilities,
2271
2295
  onSessionUpdate: (update) => {
2272
- if (!this._isStreaming) this.emit("sessionUpdate", update);
2296
+ if (!this._isStreaming && this.isOwnSessionNotification(update)) this.emit("sessionUpdate", update);
2273
2297
  },
2274
2298
  onArtifact: (artifact, event) => {
2275
2299
  console.log("[CloudConnection] onArtifact callback:", {
@@ -2283,10 +2307,41 @@ var CloudAgentConnection = class {
2283
2307
  },
2284
2308
  onUsageUpdate: (usage) => {
2285
2309
  this.emit("usageUpdate", usage);
2310
+ },
2311
+ onExtNotification: (method, params) => {
2312
+ console.log("[CloudConnection] Received extNotification:", {
2313
+ method,
2314
+ paramsKeys: Object.keys(params)
2315
+ });
2316
+ if (method === ExtensionMethod.COMMAND) {
2317
+ const action = params.action;
2318
+ const commandParams = params.params;
2319
+ console.log("[CloudConnection] Emitting command event:", {
2320
+ action,
2321
+ paramsKeys: commandParams ? Object.keys(commandParams) : []
2322
+ });
2323
+ this.emit("command", {
2324
+ action,
2325
+ params: commandParams
2326
+ });
2327
+ }
2286
2328
  }
2287
2329
  });
2288
2330
  this.setupEventForwarding();
2289
2331
  }
2332
+ /**
2333
+ * Check whether a notification belongs to this connection's own session.
2334
+ *
2335
+ * CloudConnection.createSession() overrides sessionId to agentId, so the
2336
+ * rest of the client stack uses agentId as the canonical session
2337
+ * identifier. Notifications whose sessionId differs from agentId
2338
+ * originate from sub-agent sessions running inside the same sandbox and
2339
+ * should be silently ignored at this layer — the adapter layer handles
2340
+ * sub-agent messages independently via parentToolUseId in _meta.
2341
+ */
2342
+ isOwnSessionNotification(notification) {
2343
+ return notification.sessionId === this.agentId;
2344
+ }
2290
2345
  setupEventForwarding() {
2291
2346
  this.client.on("connecting", () => {
2292
2347
  this.emit("connecting", void 0);
@@ -2447,6 +2502,7 @@ var CloudAgentConnection = class {
2447
2502
  let resolveUpdate = null;
2448
2503
  let done = false;
2449
2504
  const listener = (update) => {
2505
+ if (!this.isOwnSessionNotification(update)) return;
2450
2506
  if (resolveUpdate) {
2451
2507
  resolveUpdate(update);
2452
2508
  resolveUpdate = null;
@@ -2529,6 +2585,16 @@ var CloudAgentConnection = class {
2529
2585
  get sessionConnectionInfo() {
2530
2586
  return this._sessionConnectionInfo;
2531
2587
  }
2588
+ async reportTelemetry(eventName, payload) {
2589
+ try {
2590
+ await this.client.extMethod("reportTelemetry", {
2591
+ eventName,
2592
+ payload
2593
+ });
2594
+ } catch (error) {
2595
+ console.warn("[CloudAgentConnection] reportTelemetry failed:", error);
2596
+ }
2597
+ }
2532
2598
  async extMethod(method, params) {
2533
2599
  return this.client.extMethod(method, params);
2534
2600
  }
@@ -3131,7 +3197,7 @@ var utils_default = {
3131
3197
  *
3132
3198
  * @returns {Error} The created error.
3133
3199
  */
3134
- function AxiosError(message, code, config, request, response) {
3200
+ function AxiosError$1(message, code, config, request, response) {
3135
3201
  Error.call(this);
3136
3202
  if (Error.captureStackTrace) Error.captureStackTrace(this, this.constructor);
3137
3203
  else this.stack = (/* @__PURE__ */ new Error()).stack;
@@ -3145,7 +3211,7 @@ function AxiosError(message, code, config, request, response) {
3145
3211
  this.status = response.status ? response.status : null;
3146
3212
  }
3147
3213
  }
3148
- utils_default.inherits(AxiosError, Error, { toJSON: function toJSON() {
3214
+ utils_default.inherits(AxiosError$1, Error, { toJSON: function toJSON() {
3149
3215
  return {
3150
3216
  message: this.message,
3151
3217
  name: this.name,
@@ -3160,7 +3226,7 @@ utils_default.inherits(AxiosError, Error, { toJSON: function toJSON() {
3160
3226
  status: this.status
3161
3227
  };
3162
3228
  } });
3163
- const prototype$1 = AxiosError.prototype;
3229
+ const prototype$1 = AxiosError$1.prototype;
3164
3230
  const descriptors = {};
3165
3231
  [
3166
3232
  "ERR_BAD_OPTION_VALUE",
@@ -3178,22 +3244,22 @@ const descriptors = {};
3178
3244
  ].forEach((code) => {
3179
3245
  descriptors[code] = { value: code };
3180
3246
  });
3181
- Object.defineProperties(AxiosError, descriptors);
3247
+ Object.defineProperties(AxiosError$1, descriptors);
3182
3248
  Object.defineProperty(prototype$1, "isAxiosError", { value: true });
3183
- AxiosError.from = (error, code, config, request, response, customProps) => {
3249
+ AxiosError$1.from = (error, code, config, request, response, customProps) => {
3184
3250
  const axiosError = Object.create(prototype$1);
3185
3251
  utils_default.toFlatObject(error, axiosError, function filter(obj) {
3186
3252
  return obj !== Error.prototype;
3187
3253
  }, (prop) => {
3188
3254
  return prop !== "isAxiosError";
3189
3255
  });
3190
- AxiosError.call(axiosError, error.message, code, config, request, response);
3256
+ AxiosError$1.call(axiosError, error.message, code, config, request, response);
3191
3257
  axiosError.cause = error;
3192
3258
  axiosError.name = error.name;
3193
3259
  customProps && Object.assign(axiosError, customProps);
3194
3260
  return axiosError;
3195
3261
  };
3196
- var AxiosError_default = AxiosError;
3262
+ var AxiosError_default = AxiosError$1;
3197
3263
 
3198
3264
  //#endregion
3199
3265
  //#region ../../node_modules/delayed-stream/lib/delayed_stream.js
@@ -11920,7 +11986,7 @@ const predicates = utils_default.toFlatObject(utils_default, {}, null, function
11920
11986
  *
11921
11987
  * @returns
11922
11988
  */
11923
- function toFormData(obj, formData, options) {
11989
+ function toFormData$1(obj, formData, options) {
11924
11990
  if (!utils_default.isObject(obj)) throw new TypeError("target must be an object");
11925
11991
  formData = formData || new (FormData_default || FormData)();
11926
11992
  options = utils_default.toFlatObject(options, {
@@ -11991,7 +12057,7 @@ function toFormData(obj, formData, options) {
11991
12057
  build(obj);
11992
12058
  return formData;
11993
12059
  }
11994
- var toFormData_default = toFormData;
12060
+ var toFormData_default = toFormData$1;
11995
12061
 
11996
12062
  //#endregion
11997
12063
  //#region ../agent-provider/node_modules/axios/lib/helpers/AxiosURLSearchParams.js
@@ -12515,7 +12581,7 @@ function buildAccessors(obj, header) {
12515
12581
  });
12516
12582
  });
12517
12583
  }
12518
- var AxiosHeaders = class {
12584
+ var AxiosHeaders$1 = class {
12519
12585
  constructor(headers) {
12520
12586
  headers && this.set(headers);
12521
12587
  }
@@ -12653,7 +12719,7 @@ var AxiosHeaders = class {
12653
12719
  return this;
12654
12720
  }
12655
12721
  };
12656
- AxiosHeaders.accessor([
12722
+ AxiosHeaders$1.accessor([
12657
12723
  "Content-Type",
12658
12724
  "Content-Length",
12659
12725
  "Accept",
@@ -12661,7 +12727,7 @@ AxiosHeaders.accessor([
12661
12727
  "User-Agent",
12662
12728
  "Authorization"
12663
12729
  ]);
12664
- utils_default.reduceDescriptors(AxiosHeaders.prototype, ({ value }, key) => {
12730
+ utils_default.reduceDescriptors(AxiosHeaders$1.prototype, ({ value }, key) => {
12665
12731
  let mapped = key[0].toUpperCase() + key.slice(1);
12666
12732
  return {
12667
12733
  get: () => value,
@@ -12670,8 +12736,8 @@ utils_default.reduceDescriptors(AxiosHeaders.prototype, ({ value }, key) => {
12670
12736
  }
12671
12737
  };
12672
12738
  });
12673
- utils_default.freezeMethods(AxiosHeaders);
12674
- var AxiosHeaders_default = AxiosHeaders;
12739
+ utils_default.freezeMethods(AxiosHeaders$1);
12740
+ var AxiosHeaders_default = AxiosHeaders$1;
12675
12741
 
12676
12742
  //#endregion
12677
12743
  //#region ../agent-provider/node_modules/axios/lib/core/transformData.js
@@ -12697,7 +12763,7 @@ function transformData(fns, response) {
12697
12763
 
12698
12764
  //#endregion
12699
12765
  //#region ../agent-provider/node_modules/axios/lib/cancel/isCancel.js
12700
- function isCancel(value) {
12766
+ function isCancel$1(value) {
12701
12767
  return !!(value && value.__CANCEL__);
12702
12768
  }
12703
12769
 
@@ -12712,12 +12778,12 @@ function isCancel(value) {
12712
12778
  *
12713
12779
  * @returns {CanceledError} The created error.
12714
12780
  */
12715
- function CanceledError(message, config, request) {
12781
+ function CanceledError$1(message, config, request) {
12716
12782
  AxiosError_default.call(this, message == null ? "canceled" : message, AxiosError_default.ERR_CANCELED, config, request);
12717
12783
  this.name = "CanceledError";
12718
12784
  }
12719
- utils_default.inherits(CanceledError, AxiosError_default, { __CANCEL__: true });
12720
- var CanceledError_default = CanceledError;
12785
+ utils_default.inherits(CanceledError$1, AxiosError_default, { __CANCEL__: true });
12786
+ var CanceledError_default = CanceledError$1;
12721
12787
 
12722
12788
  //#endregion
12723
12789
  //#region ../agent-provider/node_modules/axios/lib/core/settle.js
@@ -14119,7 +14185,9 @@ var require_follow_redirects = /* @__PURE__ */ __commonJSMin(((exports, module)
14119
14185
 
14120
14186
  //#endregion
14121
14187
  //#region ../agent-provider/node_modules/axios/lib/env/data.js
14122
- const VERSION = "1.10.0";
14188
+ var import_follow_redirects = /* @__PURE__ */ __toESM(require_follow_redirects(), 1);
14189
+ var import_proxy_from_env = /* @__PURE__ */ __toESM(require_proxy_from_env(), 1);
14190
+ const VERSION$1 = "1.10.0";
14123
14191
 
14124
14192
  //#endregion
14125
14193
  //#region ../agent-provider/node_modules/axios/lib/helpers/parseProtocol.js
@@ -14482,8 +14550,6 @@ const asyncDecorator = (fn) => (...args) => utils_default.asap(() => fn(...args)
14482
14550
 
14483
14551
  //#endregion
14484
14552
  //#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
14553
  const zlibOptions = {
14488
14554
  flush: zlib.default.constants.Z_SYNC_FLUSH,
14489
14555
  finishFlush: zlib.default.constants.Z_SYNC_FLUSH
@@ -14649,7 +14715,7 @@ var http_default = isHttpAdapterSupported && function httpAdapter(config) {
14649
14715
  }
14650
14716
  if (supportedProtocols.indexOf(protocol) === -1) return reject(new AxiosError_default("Unsupported protocol " + protocol, AxiosError_default.ERR_BAD_REQUEST, config));
14651
14717
  const headers = AxiosHeaders_default.from(config.headers).normalize();
14652
- headers.set("User-Agent", "axios/" + VERSION, false);
14718
+ headers.set("User-Agent", "axios/" + VERSION$1, false);
14653
14719
  const { onUploadProgress, onDownloadProgress } = config;
14654
14720
  const maxRate = config.maxRate;
14655
14721
  let maxUploadRate = void 0;
@@ -14659,7 +14725,7 @@ var http_default = isHttpAdapterSupported && function httpAdapter(config) {
14659
14725
  data = formDataToStream_default(data, (formHeaders) => {
14660
14726
  headers.set(formHeaders);
14661
14727
  }, {
14662
- tag: `axios-${VERSION}-boundary`,
14728
+ tag: `axios-${VERSION$1}-boundary`,
14663
14729
  boundary: userBoundary && userBoundary[1] || void 0
14664
14730
  });
14665
14731
  } else if (utils_default.isFormData(data) && utils_default.isFunction(data.getHeaders)) {
@@ -14924,7 +14990,7 @@ const headersToObject = (thing) => thing instanceof AxiosHeaders_default ? { ...
14924
14990
  *
14925
14991
  * @returns {Object} New object resulting from merging config2 to config1
14926
14992
  */
14927
- function mergeConfig(config1, config2) {
14993
+ function mergeConfig$1(config1, config2) {
14928
14994
  config2 = config2 || {};
14929
14995
  const config = {};
14930
14996
  function getMergedValue(target, source, prop, caseless) {
@@ -14990,7 +15056,7 @@ function mergeConfig(config1, config2) {
14990
15056
  //#endregion
14991
15057
  //#region ../agent-provider/node_modules/axios/lib/helpers/resolveConfig.js
14992
15058
  var resolveConfig_default = (config) => {
14993
- const newConfig = mergeConfig({}, config);
15059
+ const newConfig = mergeConfig$1({}, config);
14994
15060
  let { data, withXSRFToken, xsrfHeaderName, xsrfCookieName, headers, auth } = newConfig;
14995
15061
  newConfig.headers = headers = AxiosHeaders_default.from(headers);
14996
15062
  newConfig.url = buildURL(buildFullPath(newConfig.baseURL, newConfig.url, newConfig.allowAbsoluteUrls), config.params, config.paramsSerializer);
@@ -15421,7 +15487,7 @@ function dispatchRequest(config) {
15421
15487
  response.headers = AxiosHeaders_default.from(response.headers);
15422
15488
  return response;
15423
15489
  }, function onAdapterRejection(reason) {
15424
- if (!isCancel(reason)) {
15490
+ if (!isCancel$1(reason)) {
15425
15491
  throwIfCancellationRequested(config);
15426
15492
  if (reason && reason.response) {
15427
15493
  reason.response.data = transformData.call(config, config.transformResponse, reason.response);
@@ -15459,7 +15525,7 @@ const deprecatedWarnings = {};
15459
15525
  */
15460
15526
  validators$1.transitional = function transitional(validator, version, message) {
15461
15527
  function formatMessage(opt, desc) {
15462
- return "[Axios v" + VERSION + "] Transitional option '" + opt + "'" + desc + (message ? ". " + message : "");
15528
+ return "[Axios v" + VERSION$1 + "] Transitional option '" + opt + "'" + desc + (message ? ". " + message : "");
15463
15529
  }
15464
15530
  return (value, opt, opts) => {
15465
15531
  if (validator === false) throw new AxiosError_default(formatMessage(opt, " has been removed" + (version ? " in " + version : "")), AxiosError_default.ERR_DEPRECATED);
@@ -15516,7 +15582,7 @@ const validators = validator_default.validators;
15516
15582
  *
15517
15583
  * @return {Axios} A new instance of Axios
15518
15584
  */
15519
- var Axios = class {
15585
+ var Axios$1 = class {
15520
15586
  constructor(instanceConfig) {
15521
15587
  this.defaults = instanceConfig || {};
15522
15588
  this.interceptors = {
@@ -15553,7 +15619,7 @@ var Axios = class {
15553
15619
  config = config || {};
15554
15620
  config.url = configOrUrl;
15555
15621
  } else config = configOrUrl || {};
15556
- config = mergeConfig(this.defaults, config);
15622
+ config = mergeConfig$1(this.defaults, config);
15557
15623
  const { transitional, paramsSerializer, headers } = config;
15558
15624
  if (transitional !== void 0) validator_default.assertOptions(transitional, {
15559
15625
  silentJSONParsing: validators.transitional(validators.boolean),
@@ -15632,7 +15698,7 @@ var Axios = class {
15632
15698
  return promise;
15633
15699
  }
15634
15700
  getUri(config) {
15635
- config = mergeConfig(this.defaults, config);
15701
+ config = mergeConfig$1(this.defaults, config);
15636
15702
  return buildURL(buildFullPath(config.baseURL, config.url, config.allowAbsoluteUrls), config.params, config.paramsSerializer);
15637
15703
  }
15638
15704
  };
@@ -15642,8 +15708,8 @@ utils_default.forEach([
15642
15708
  "head",
15643
15709
  "options"
15644
15710
  ], function forEachMethodNoData(method) {
15645
- Axios.prototype[method] = function(url, config) {
15646
- return this.request(mergeConfig(config || {}, {
15711
+ Axios$1.prototype[method] = function(url, config) {
15712
+ return this.request(mergeConfig$1(config || {}, {
15647
15713
  method,
15648
15714
  url,
15649
15715
  data: (config || {}).data
@@ -15657,7 +15723,7 @@ utils_default.forEach([
15657
15723
  ], function forEachMethodWithData(method) {
15658
15724
  function generateHTTPMethod(isForm) {
15659
15725
  return function httpMethod(url, data, config) {
15660
- return this.request(mergeConfig(config || {}, {
15726
+ return this.request(mergeConfig$1(config || {}, {
15661
15727
  method,
15662
15728
  headers: isForm ? { "Content-Type": "multipart/form-data" } : {},
15663
15729
  url,
@@ -15665,10 +15731,10 @@ utils_default.forEach([
15665
15731
  }));
15666
15732
  };
15667
15733
  }
15668
- Axios.prototype[method] = generateHTTPMethod();
15669
- Axios.prototype[method + "Form"] = generateHTTPMethod(true);
15734
+ Axios$1.prototype[method] = generateHTTPMethod();
15735
+ Axios$1.prototype[method + "Form"] = generateHTTPMethod(true);
15670
15736
  });
15671
- var Axios_default = Axios;
15737
+ var Axios_default = Axios$1;
15672
15738
 
15673
15739
  //#endregion
15674
15740
  //#region ../agent-provider/node_modules/axios/lib/cancel/CancelToken.js
@@ -15679,7 +15745,7 @@ var Axios_default = Axios;
15679
15745
  *
15680
15746
  * @returns {CancelToken}
15681
15747
  */
15682
- var CancelToken = class CancelToken {
15748
+ var CancelToken$1 = class CancelToken$1 {
15683
15749
  constructor(executor) {
15684
15750
  if (typeof executor !== "function") throw new TypeError("executor must be a function.");
15685
15751
  let resolvePromise;
@@ -15751,14 +15817,14 @@ var CancelToken = class CancelToken {
15751
15817
  static source() {
15752
15818
  let cancel;
15753
15819
  return {
15754
- token: new CancelToken(function executor(c) {
15820
+ token: new CancelToken$1(function executor(c) {
15755
15821
  cancel = c;
15756
15822
  }),
15757
15823
  cancel
15758
15824
  };
15759
15825
  }
15760
15826
  };
15761
- var CancelToken_default = CancelToken;
15827
+ var CancelToken_default = CancelToken$1;
15762
15828
 
15763
15829
  //#endregion
15764
15830
  //#region ../agent-provider/node_modules/axios/lib/helpers/spread.js
@@ -15783,7 +15849,7 @@ var CancelToken_default = CancelToken;
15783
15849
  *
15784
15850
  * @returns {Function}
15785
15851
  */
15786
- function spread(callback) {
15852
+ function spread$1(callback) {
15787
15853
  return function wrap(arr) {
15788
15854
  return callback.apply(null, arr);
15789
15855
  };
@@ -15798,13 +15864,13 @@ function spread(callback) {
15798
15864
  *
15799
15865
  * @returns {boolean} True if the payload is an error thrown by Axios, otherwise false
15800
15866
  */
15801
- function isAxiosError(payload) {
15867
+ function isAxiosError$1(payload) {
15802
15868
  return utils_default.isObject(payload) && payload.isAxiosError === true;
15803
15869
  }
15804
15870
 
15805
15871
  //#endregion
15806
15872
  //#region ../agent-provider/node_modules/axios/lib/helpers/HttpStatusCode.js
15807
- const HttpStatusCode = {
15873
+ const HttpStatusCode$1 = {
15808
15874
  Continue: 100,
15809
15875
  SwitchingProtocols: 101,
15810
15876
  Processing: 102,
@@ -15869,10 +15935,10 @@ const HttpStatusCode = {
15869
15935
  NotExtended: 510,
15870
15936
  NetworkAuthenticationRequired: 511
15871
15937
  };
15872
- Object.entries(HttpStatusCode).forEach(([key, value]) => {
15873
- HttpStatusCode[value] = key;
15938
+ Object.entries(HttpStatusCode$1).forEach(([key, value]) => {
15939
+ HttpStatusCode$1[value] = key;
15874
15940
  });
15875
- var HttpStatusCode_default = HttpStatusCode;
15941
+ var HttpStatusCode_default = HttpStatusCode$1;
15876
15942
 
15877
15943
  //#endregion
15878
15944
  //#region ../agent-provider/node_modules/axios/lib/axios.js
@@ -15889,7 +15955,7 @@ function createInstance(defaultConfig) {
15889
15955
  utils_default.extend(instance, Axios_default.prototype, context, { allOwnKeys: true });
15890
15956
  utils_default.extend(instance, context, null, { allOwnKeys: true });
15891
15957
  instance.create = function create(instanceConfig) {
15892
- return createInstance(mergeConfig(defaultConfig, instanceConfig));
15958
+ return createInstance(mergeConfig$1(defaultConfig, instanceConfig));
15893
15959
  };
15894
15960
  return instance;
15895
15961
  }
@@ -15897,17 +15963,17 @@ const axios = createInstance(defaults_default);
15897
15963
  axios.Axios = Axios_default;
15898
15964
  axios.CanceledError = CanceledError_default;
15899
15965
  axios.CancelToken = CancelToken_default;
15900
- axios.isCancel = isCancel;
15901
- axios.VERSION = VERSION;
15966
+ axios.isCancel = isCancel$1;
15967
+ axios.VERSION = VERSION$1;
15902
15968
  axios.toFormData = toFormData_default;
15903
15969
  axios.AxiosError = AxiosError_default;
15904
15970
  axios.Cancel = axios.CanceledError;
15905
15971
  axios.all = function all(promises) {
15906
15972
  return Promise.all(promises);
15907
15973
  };
15908
- axios.spread = spread;
15909
- axios.isAxiosError = isAxiosError;
15910
- axios.mergeConfig = mergeConfig;
15974
+ axios.spread = spread$1;
15975
+ axios.isAxiosError = isAxiosError$1;
15976
+ axios.mergeConfig = mergeConfig$1;
15911
15977
  axios.AxiosHeaders = AxiosHeaders_default;
15912
15978
  axios.formToJSON = (thing) => formDataToJSON_default(utils_default.isHTMLForm(thing) ? new FormData(thing) : thing);
15913
15979
  axios.getAdapter = adapters_default.getAdapter;
@@ -15915,6 +15981,10 @@ axios.HttpStatusCode = HttpStatusCode_default;
15915
15981
  axios.default = axios;
15916
15982
  var axios_default = axios;
15917
15983
 
15984
+ //#endregion
15985
+ //#region ../agent-provider/node_modules/axios/index.js
15986
+ const { Axios, AxiosError, CanceledError, isCancel, CancelToken, VERSION, all, Cancel, isAxiosError, spread, toFormData, AxiosHeaders, HttpStatusCode, formToJSON, getAdapter, mergeConfig } = axios_default;
15987
+
15918
15988
  //#endregion
15919
15989
  //#region ../agent-provider/src/http/http-service.ts
15920
15990
  /**
@@ -15923,7 +15993,7 @@ var axios_default = axios;
15923
15993
  * 特性:
15924
15994
  * - 单例模式,全局唯一实例,延迟初始化(首次使用时自动创建)
15925
15995
  * - 支持拦截器注册(其他模块可注入 header)
15926
- * - 统一 401/403 处理
15996
+ * - 统一 401 处理(支持自动刷新 token 并重试)
15927
15997
  * - 自动携带凭证(withCredentials)
15928
15998
  * - 类型安全
15929
15999
  *
@@ -15963,6 +16033,8 @@ var HttpService = class HttpService {
15963
16033
  */
15964
16034
  constructor(config = {}) {
15965
16035
  this.unauthorizedCallbacks = /* @__PURE__ */ new Set();
16036
+ this.isRefreshing = false;
16037
+ this.refreshSubscribers = [];
15966
16038
  this.config = config;
15967
16039
  this.axiosInstance = axios_default.create({
15968
16040
  baseURL: config.baseURL?.replace(/\/$/, "") || "",
@@ -16003,18 +16075,54 @@ var HttpService = class HttpService {
16003
16075
  }, (error) => Promise.reject(error));
16004
16076
  }
16005
16077
  /**
16006
- * 注册默认响应拦截器(处理 401/403)
16078
+ * 注册默认响应拦截器(处理 401,支持自动重试)
16007
16079
  */
16008
16080
  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();
16081
+ this.axiosInstance.interceptors.response.use((response) => response, async (error) => {
16082
+ const originalRequest = error.config;
16083
+ if (error.response?.status === 401 && originalRequest && !originalRequest._retry) {
16084
+ if (originalRequest.url?.includes("/console/accounts")) {
16085
+ console.warn("[HttpService] Unauthorized 401 on refresh endpoint, not retrying");
16086
+ return Promise.reject(error);
16087
+ }
16088
+ console.warn("[HttpService] Unauthorized 401, attempting token refresh and retry");
16089
+ originalRequest._retry = true;
16090
+ if (this.isRefreshing) return new Promise((resolve, reject) => {
16091
+ this.refreshSubscribers.push((success) => {
16092
+ if (success) this.axiosInstance.request(originalRequest).then(resolve).catch(reject);
16093
+ else reject(error);
16094
+ });
16095
+ });
16096
+ this.isRefreshing = true;
16097
+ try {
16098
+ await this.triggerUnauthorizedCallbacks();
16099
+ this.onRefreshSuccess();
16100
+ return this.axiosInstance.request(originalRequest);
16101
+ } catch (refreshError) {
16102
+ this.onRefreshFailure();
16103
+ return Promise.reject(error);
16104
+ } finally {
16105
+ this.isRefreshing = false;
16106
+ }
16013
16107
  }
16014
16108
  return Promise.reject(error);
16015
16109
  });
16016
16110
  }
16017
16111
  /**
16112
+ * token 刷新成功,通知所有等待的请求
16113
+ */
16114
+ onRefreshSuccess() {
16115
+ this.refreshSubscribers.forEach((callback) => callback(true));
16116
+ this.refreshSubscribers = [];
16117
+ }
16118
+ /**
16119
+ * token 刷新失败,通知所有等待的请求
16120
+ */
16121
+ onRefreshFailure() {
16122
+ this.refreshSubscribers.forEach((callback) => callback(false));
16123
+ this.refreshSubscribers = [];
16124
+ }
16125
+ /**
16018
16126
  * 注册请求拦截器
16019
16127
  * @param onFulfilled 请求成功拦截器
16020
16128
  * @param onRejected 请求失败拦截器
@@ -16091,16 +16199,18 @@ var HttpService = class HttpService {
16091
16199
  this.unauthorizedCallbacks.delete(callback);
16092
16200
  }
16093
16201
  /**
16094
- * 触发所有 401 回调
16202
+ * 触发所有 401 回调并等待完成
16203
+ * @returns Promise,等待所有回调完成
16204
+ * @throws 如果任何回调失败,则抛出错误
16095
16205
  */
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
- });
16206
+ async triggerUnauthorizedCallbacks() {
16207
+ const callbacks = Array.from(this.unauthorizedCallbacks);
16208
+ const failedResults = (await Promise.allSettled(callbacks.map((callback) => callback()))).filter((r) => r.status === "rejected");
16209
+ if (failedResults.length > 0) {
16210
+ const errors = failedResults.map((r) => r.reason);
16211
+ console.error("[HttpService] Some unauthorized callbacks failed:", errors);
16212
+ throw errors[0];
16213
+ }
16104
16214
  }
16105
16215
  /**
16106
16216
  * 更新 authToken
@@ -16166,6 +16276,14 @@ var HttpService = class HttpService {
16166
16276
  return (await this.axiosInstance.put(url, data, config)).data;
16167
16277
  }
16168
16278
  /**
16279
+ * 通用请求方法
16280
+ * @param config axios 请求配置
16281
+ * @returns 原始 AxiosResponse
16282
+ */
16283
+ async request(config) {
16284
+ return this.axiosInstance.request(config);
16285
+ }
16286
+ /**
16169
16287
  * 获取原始 axios 实例(用于高级场景)
16170
16288
  */
16171
16289
  getAxiosInstance() {
@@ -16359,6 +16477,109 @@ const accountService = new AccountService();
16359
16477
  */
16360
16478
  if (typeof window !== "undefined") window.__genieAccountService = accountService;
16361
16479
 
16480
+ //#endregion
16481
+ //#region ../agent-provider/src/common/utils/lru-cache.ts
16482
+ /**
16483
+ * LRU (Least Recently Used) Cache
16484
+ * 当缓存达到容量上限时,自动淘汰最久未使用的数据
16485
+ *
16486
+ * @template K - Key 类型
16487
+ * @template V - Value 类型
16488
+ */
16489
+ var LRUCache = class {
16490
+ /**
16491
+ * 创建 LRU 缓存实例
16492
+ * @param capacity - 缓存容量上限
16493
+ */
16494
+ constructor(capacity) {
16495
+ if (capacity <= 0) throw new Error("Cache capacity must be greater than 0");
16496
+ this.capacity = capacity;
16497
+ this.cache = /* @__PURE__ */ new Map();
16498
+ }
16499
+ /**
16500
+ * 获取缓存值
16501
+ * @param key - 键
16502
+ * @returns 值,如果不存在返回 undefined
16503
+ */
16504
+ get(key) {
16505
+ if (!this.cache.has(key)) return;
16506
+ const value = this.cache.get(key);
16507
+ this.cache.delete(key);
16508
+ this.cache.set(key, value);
16509
+ return value;
16510
+ }
16511
+ /**
16512
+ * 设置缓存值
16513
+ * @param key - 键
16514
+ * @param value - 值
16515
+ */
16516
+ set(key, value) {
16517
+ if (this.cache.has(key)) this.cache.delete(key);
16518
+ else if (this.cache.size >= this.capacity) {
16519
+ const firstKey = this.cache.keys().next().value;
16520
+ this.cache.delete(firstKey);
16521
+ }
16522
+ this.cache.set(key, value);
16523
+ }
16524
+ /**
16525
+ * 检查 key 是否存在
16526
+ * @param key - 键
16527
+ * @returns 是否存在
16528
+ */
16529
+ has(key) {
16530
+ return this.cache.has(key);
16531
+ }
16532
+ /**
16533
+ * 删除指定 key
16534
+ * @param key - 键
16535
+ * @returns 是否删除成功
16536
+ */
16537
+ delete(key) {
16538
+ return this.cache.delete(key);
16539
+ }
16540
+ /**
16541
+ * 清空缓存
16542
+ */
16543
+ clear() {
16544
+ this.cache.clear();
16545
+ }
16546
+ /**
16547
+ * 获取当前缓存大小
16548
+ * @returns 当前缓存的元素数量
16549
+ */
16550
+ get size() {
16551
+ return this.cache.size;
16552
+ }
16553
+ /**
16554
+ * 获取缓存容量
16555
+ * @returns 缓存容量上限
16556
+ */
16557
+ get maxSize() {
16558
+ return this.capacity;
16559
+ }
16560
+ /**
16561
+ * 获取所有 key
16562
+ * @returns key 数组
16563
+ */
16564
+ keys() {
16565
+ return Array.from(this.cache.keys());
16566
+ }
16567
+ /**
16568
+ * 获取所有 value
16569
+ * @returns value 数组
16570
+ */
16571
+ values() {
16572
+ return Array.from(this.cache.values());
16573
+ }
16574
+ /**
16575
+ * 遍历缓存
16576
+ * @param callback - 回调函数
16577
+ */
16578
+ forEach(callback) {
16579
+ this.cache.forEach((value, key) => callback(value, key));
16580
+ }
16581
+ };
16582
+
16362
16583
  //#endregion
16363
16584
  //#region ../agent-provider/src/common/utils/concurrency.ts
16364
16585
  /**
@@ -16460,20 +16681,32 @@ var CosUploadService = class {
16460
16681
  * 上传单个文件到 COS
16461
16682
  *
16462
16683
  * @param file - 要上传的文件
16684
+ * @param abortSignal - 可选的 AbortSignal,用于取消上传
16463
16685
  * @returns 上传结果,包含访问 URL 或错误信息
16464
16686
  */
16465
- async uploadFile(file) {
16687
+ async uploadFile(file, abortSignal) {
16466
16688
  const filename = file.name;
16467
16689
  this.logger?.info(`[CosUploadService] Uploading file: ${filename}`);
16468
16690
  try {
16691
+ if (abortSignal?.aborted) return {
16692
+ success: false,
16693
+ error: "Upload cancelled",
16694
+ aborted: true
16695
+ };
16469
16696
  const objectKey = this.generateObjectKey(filename);
16470
16697
  this.logger?.debug(`[CosUploadService] Generated objectKey: ${objectKey}`);
16471
16698
  const presignedItem = (await this.getPresignedUrls([objectKey])).items[0];
16472
16699
  if (!presignedItem) throw new Error("No presigned URL item returned");
16700
+ if (abortSignal?.aborted) return {
16701
+ success: false,
16702
+ error: "Upload cancelled",
16703
+ aborted: true
16704
+ };
16473
16705
  const uploadResponse = await fetch(presignedItem.upload_url, {
16474
16706
  method: "PUT",
16475
16707
  body: file,
16476
- headers: { "Content-Type": file.type || "application/octet-stream" }
16708
+ headers: { "Content-Type": file.type || "application/octet-stream" },
16709
+ signal: abortSignal
16477
16710
  });
16478
16711
  if (!uploadResponse.ok) {
16479
16712
  const errorText = await uploadResponse.text().catch(() => uploadResponse.statusText);
@@ -16487,6 +16720,11 @@ var CosUploadService = class {
16487
16720
  objectKey
16488
16721
  };
16489
16722
  } catch (error) {
16723
+ if (error instanceof Error && error.name === "AbortError") return {
16724
+ success: false,
16725
+ error: "Upload cancelled",
16726
+ aborted: true
16727
+ };
16490
16728
  const errorMessage = error instanceof Error ? error.message : "Unknown error";
16491
16729
  this.logger?.error(`[CosUploadService] Upload failed: ${filename}`, error);
16492
16730
  return {
@@ -16501,14 +16739,25 @@ var CosUploadService = class {
16501
16739
  * 使用并发控制,限制同时上传的文件数量
16502
16740
  *
16503
16741
  * @param files - 要上传的文件数组
16742
+ * @param abortSignal - 可选的 AbortSignal,用于取消上传
16504
16743
  * @returns 所有文件的上传结果
16505
16744
  */
16506
- async uploadFiles(files) {
16745
+ async uploadFiles(files, abortSignal) {
16507
16746
  if (files.length === 0) return {
16508
16747
  success: true,
16509
16748
  urls: [],
16510
16749
  results: []
16511
16750
  };
16751
+ if (abortSignal?.aborted) return {
16752
+ success: false,
16753
+ error: "Upload cancelled",
16754
+ aborted: true,
16755
+ results: files.map(() => ({
16756
+ success: false,
16757
+ error: "Upload cancelled",
16758
+ aborted: true
16759
+ }))
16760
+ };
16512
16761
  this.logger?.info(`[CosUploadService] Uploading ${files.length} file(s) with concurrency ${this.uploadConcurrency}`);
16513
16762
  try {
16514
16763
  const fileInfos = files.map((file) => ({
@@ -16520,6 +16769,12 @@ var CosUploadService = class {
16520
16769
  this.logger?.debug(`[CosUploadService] Got ${presignedResponse.items.length} presigned URLs`);
16521
16770
  if (presignedResponse.items.length !== fileInfos.length) throw new Error(`Expected ${fileInfos.length} presigned URLs, got ${presignedResponse.items.length}`);
16522
16771
  const results = (await runWithConcurrencySettled(fileInfos.map(({ file }, index) => async () => {
16772
+ if (abortSignal?.aborted) return {
16773
+ success: false,
16774
+ error: "Upload cancelled",
16775
+ aborted: true,
16776
+ objectKey: fileInfos[index].objectKey
16777
+ };
16523
16778
  const presignedItem = presignedResponse.items[index];
16524
16779
  if (!presignedItem) return {
16525
16780
  success: false,
@@ -16530,7 +16785,8 @@ var CosUploadService = class {
16530
16785
  const uploadResponse = await fetch(presignedItem.upload_url, {
16531
16786
  method: "PUT",
16532
16787
  body: file,
16533
- headers: { "Content-Type": file.type || "application/octet-stream" }
16788
+ headers: { "Content-Type": file.type || "application/octet-stream" },
16789
+ signal: abortSignal
16534
16790
  });
16535
16791
  if (!uploadResponse.ok) {
16536
16792
  const errorText = await uploadResponse.text().catch(() => uploadResponse.statusText);
@@ -16547,6 +16803,12 @@ var CosUploadService = class {
16547
16803
  objectKey: presignedItem.object_key
16548
16804
  };
16549
16805
  } catch (error) {
16806
+ if (error instanceof Error && error.name === "AbortError") return {
16807
+ success: false,
16808
+ error: "Upload cancelled",
16809
+ aborted: true,
16810
+ objectKey: presignedItem.object_key
16811
+ };
16550
16812
  return {
16551
16813
  success: false,
16552
16814
  error: error instanceof Error ? error.message : "Unknown error",
@@ -16594,91 +16856,6 @@ var CosUploadService = class {
16594
16856
  }
16595
16857
  };
16596
16858
 
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
16859
  //#endregion
16683
16860
  //#region ../agent-provider/src/common/providers/cloud-agent-provider/cloud-provider.ts
16684
16861
  /**
@@ -16827,8 +17004,11 @@ var CloudAgentProvider = class CloudAgentProvider {
16827
17004
  this.filesystemCache = /* @__PURE__ */ new Map();
16828
17005
  this.connectionCache = /* @__PURE__ */ new Map();
16829
17006
  this.eventListeners = /* @__PURE__ */ new Map();
17007
+ this.productConfigCache = null;
16830
17008
  this.options = options;
16831
17009
  this.logger = options.logger;
17010
+ this.marketplaceCache = new LRUCache(200);
17011
+ this.pluginCache = new LRUCache(2e3);
16832
17012
  if (options.endpoint) httpService.setBaseURL(options.endpoint);
16833
17013
  if (options.authToken) httpService.setAuthToken(options.authToken);
16834
17014
  if (options.headers && Object.keys(options.headers).length > 0) this.requestInterceptorId = httpService.registerRequestInterceptor((config) => {
@@ -16879,7 +17059,19 @@ var CloudAgentProvider = class CloudAgentProvider {
16879
17059
  const cached = this.filesystemCache.get(agentId);
16880
17060
  if (cached) return cached;
16881
17061
  const info = await this.getSandboxInfo(agentId);
16882
- const filesystem = createAgentFilesystem(await E2BFilesystem.connect(info));
17062
+ let e2bFilesystem;
17063
+ if (this.options.filesystemFactory) e2bFilesystem = await this.options.filesystemFactory(info);
17064
+ else {
17065
+ const { E2BFilesystem } = await Promise.resolve().then(() => require("./e2b-filesystem-Cac-bpRR.cjs"));
17066
+ e2bFilesystem = await E2BFilesystem.connect(info);
17067
+ }
17068
+ if (e2bFilesystem.setReconnectFn) e2bFilesystem.setReconnectFn(async () => {
17069
+ this.logger?.debug(`Reconnecting E2B sandbox for agent: ${agentId}`);
17070
+ const newInfo = await this.getSandboxInfo(agentId);
17071
+ this.logger?.debug(`E2B sandbox reconnected for agent: ${agentId}`);
17072
+ return newInfo;
17073
+ });
17074
+ const filesystem = createAgentFilesystem(e2bFilesystem);
16883
17075
  this.filesystemCache.set(agentId, filesystem);
16884
17076
  this.logger?.debug(`Created filesystem for agent: ${agentId}`);
16885
17077
  return filesystem;
@@ -16947,15 +17139,9 @@ var CloudAgentProvider = class CloudAgentProvider {
16947
17139
  const url = this.buildGetUrl("/console/as/conversations/", params);
16948
17140
  const apiResponse = await httpService.get(url);
16949
17141
  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
17142
  return {
16957
- agents,
16958
- pagination
17143
+ agents: apiResponse.data.conversations.map((a) => this.toAgentState(a)),
17144
+ pagination: apiResponse.data.pagination
16959
17145
  };
16960
17146
  } catch (error) {
16961
17147
  this.logger?.error("Failed to list agents:", error);
@@ -16965,15 +17151,17 @@ var CloudAgentProvider = class CloudAgentProvider {
16965
17151
  /**
16966
17152
  * Create a new conversation
16967
17153
  * POST {endpoint}/console/as/conversations
16968
- * @param params - Optional session params containing _meta with tags
17154
+ * @param params - Session params containing cwd and optional configuration
16969
17155
  */
16970
17156
  async create(params) {
16971
17157
  try {
16972
- const tagsObj = (params?._meta?.["codebuddy.ai"])?.tags;
17158
+ const { options = {} } = params;
17159
+ const codebuddyMeta = options._meta?.["codebuddy.ai"];
17160
+ const tagsObj = options.tags || codebuddyMeta?.tags;
16973
17161
  const tagsArray = tagsObj ? Object.entries(tagsObj).map(([key, value]) => `${key}:${value}`) : void 0;
16974
17162
  const createPayload = {
16975
- prompt: "",
16976
- model: "deepseek-r1",
17163
+ prompt: (options.prompt || "").slice(0, 100),
17164
+ model: options.model || "deepseek-r1",
16977
17165
  ...tagsArray && tagsArray.length > 0 ? { tags: tagsArray } : {}
16978
17166
  };
16979
17167
  console.log("[CloudAgentProvider] Creating conversation with payload:", createPayload);
@@ -17027,7 +17215,14 @@ var CloudAgentProvider = class CloudAgentProvider {
17027
17215
  } catch (error) {
17028
17216
  this.logger?.debug(`Failed to fetch conversation details for ${agentId}:`, error);
17029
17217
  }
17030
- if (this.connectionCache.get(endpoint)) this.connectionCache.delete(endpoint);
17218
+ const existingConnection = this.connectionCache.get(endpoint);
17219
+ if (existingConnection) {
17220
+ this.connectionCache.delete(endpoint);
17221
+ existingConnection.removeAllListeners();
17222
+ existingConnection.disconnect().catch((err) => {
17223
+ this.logger?.debug("Failed to disconnect old connection:", err);
17224
+ });
17225
+ }
17031
17226
  const clientCapabilities = {
17032
17227
  ...this.options.clientCapabilities,
17033
17228
  _meta: {
@@ -17147,6 +17342,35 @@ var CloudAgentProvider = class CloudAgentProvider {
17147
17342
  }
17148
17343
  }
17149
17344
  /**
17345
+ * Update conversation status by ID
17346
+ * POST {endpoint}/console/as/conversations/{agentId}
17347
+ *
17348
+ * @param agentId - Conversation ID to update
17349
+ * @param status - New status for the conversation
17350
+ * @returns PatchConversationResponse containing the updated conversation ID
17351
+ *
17352
+ * @example
17353
+ * ```typescript
17354
+ * const result = await provider.updateStatus('agent-123', 'completed');
17355
+ * console.log('Updated conversation status:', result.id);
17356
+ * ```
17357
+ */
17358
+ async updateStatus(agentId, status) {
17359
+ try {
17360
+ const body = { status };
17361
+ const apiResponse = await httpService.post(`/console/as/conversations/${agentId}`, body);
17362
+ if (!apiResponse.data) {
17363
+ this.logger?.info(`Updated conversation status: ${agentId} to "${status}"`);
17364
+ return { id: agentId };
17365
+ }
17366
+ this.logger?.info(`Updated conversation status: ${apiResponse.data.id} to "${status}"`);
17367
+ return apiResponse.data;
17368
+ } catch (error) {
17369
+ this.logger?.error(`Failed to update conversation status ${agentId}:`, error);
17370
+ throw error;
17371
+ }
17372
+ }
17373
+ /**
17150
17374
  * Get available models from product configuration
17151
17375
  *
17152
17376
  * GET {endpoint}/console/enterprises/{personal|enterpriseId}/models?repos[]={repo}
@@ -17177,9 +17401,13 @@ var CloudAgentProvider = class CloudAgentProvider {
17177
17401
  this.logger?.warn("[CloudAgentProvider] No data in config response, returning empty models");
17178
17402
  return [];
17179
17403
  }
17180
- const models = apiResponse.data.models ?? [];
17181
- this.logger?.info(`[CloudAgentProvider] Retrieved ${models.length} models from /console/enterprises API`);
17182
- return models.map((model) => ({
17404
+ this.productConfigCache = apiResponse.data;
17405
+ const productConfig = apiResponse.data;
17406
+ const allModels = productConfig.models ?? [];
17407
+ const cliModelIds = (productConfig.agents ?? []).find((agent) => agent.name === "cli")?.models ?? [];
17408
+ const filteredModels = cliModelIds.length > 0 ? allModels.filter((model) => cliModelIds.includes(model.id)) : allModels;
17409
+ this.logger?.info(`[CloudAgentProvider] Retrieved ${filteredModels.length} models for cli agent (total: ${allModels.length})`);
17410
+ return filteredModels.map((model) => ({
17183
17411
  id: model.id,
17184
17412
  name: model.name ?? model.id,
17185
17413
  description: model.description,
@@ -17201,6 +17429,43 @@ var CloudAgentProvider = class CloudAgentProvider {
17201
17429
  }
17202
17430
  }
17203
17431
  /**
17432
+ * 获取产品部署类型(从缓存)
17433
+ * 需要先调用 getModels() 初始化缓存
17434
+ *
17435
+ * @returns 部署类型:'SaaS' | 'Cloud-Hosted' | 'Self-Hosted',默认为 'SaaS'
17436
+ */
17437
+ getDeploymentType() {
17438
+ return this.productConfigCache?.deploymentType ?? "SaaS";
17439
+ }
17440
+ /**
17441
+ * 获取 Credit 购买引导配置(从缓存)
17442
+ * 需要先调用 getModels() 初始化缓存
17443
+ *
17444
+ * @returns Credit 购买引导配置,key 为错误码。如果后端未返回,则使用默认配置
17445
+ */
17446
+ getCreditPurchaseActions() {
17447
+ return this.productConfigCache?.config?.creditPurchaseActions ?? {
17448
+ "14018": {
17449
+ labelZh: "获取 Credits",
17450
+ labelEn: "Get credits",
17451
+ url: "https://www.codebuddy.cn/profile/plan",
17452
+ showButton: true
17453
+ },
17454
+ "6004": {
17455
+ labelZh: "升级专业版",
17456
+ labelEn: "Upgrade to Pro",
17457
+ url: "https://www.codebuddy.cn/profile/plan",
17458
+ showButton: true
17459
+ },
17460
+ "6005": {
17461
+ labelZh: "升级专业版",
17462
+ labelEn: "Upgrade to Pro",
17463
+ url: "https://www.codebuddy.cn/profile/plan",
17464
+ showButton: true
17465
+ }
17466
+ };
17467
+ }
17468
+ /**
17204
17469
  * Generate a unique request ID
17205
17470
  */
17206
17471
  generateRequestId() {
@@ -17283,7 +17548,7 @@ var CloudAgentProvider = class CloudAgentProvider {
17283
17548
  /**
17284
17549
  * Upload files to cloud storage via COS presigned URL
17285
17550
  *
17286
- * @param params - files array (File objects in browser)
17551
+ * @param params - files array (File objects in browser), optional abortSignal
17287
17552
  * @returns Response with corresponding cloud URLs
17288
17553
  */
17289
17554
  async uploadFile(params) {
@@ -17293,12 +17558,13 @@ var CloudAgentProvider = class CloudAgentProvider {
17293
17558
  success: false,
17294
17559
  error: "No valid File objects provided"
17295
17560
  };
17296
- const result = await this.cosUploadService.uploadFiles(files);
17561
+ const result = await this.cosUploadService.uploadFiles(files, params.abortSignal);
17297
17562
  return {
17298
17563
  success: result.success,
17299
17564
  urls: result.urls,
17300
17565
  expireSeconds: result.expireSeconds,
17301
- error: result.error
17566
+ error: result.error,
17567
+ aborted: result.aborted
17302
17568
  };
17303
17569
  }
17304
17570
  /**
@@ -17340,20 +17606,22 @@ var CloudAgentProvider = class CloudAgentProvider {
17340
17606
  }
17341
17607
  /**
17342
17608
  * 获取支持的场景列表
17343
- * API 端点: GET /console/as/support/scenes
17609
+ * API 端点: GET /v2/as/support/scenes (不鉴权)
17344
17610
  * 用于 Welcome 页面的 QuickActions 快捷操作
17345
17611
  *
17612
+ * @param locale - 可选,语言环境(如 'zh-CN', 'en-US'),用于获取对应语言的场景数据
17346
17613
  * @returns Promise<SupportScene[]> 支持的场景列表
17347
17614
  */
17348
- async getSupportScenes() {
17615
+ async getSupportScenes(locale) {
17349
17616
  try {
17350
- const apiResponse = await httpService.get("/console/as/support/scenes");
17617
+ const url = this.buildGetUrl("/v2/as/support/scenes", locale ? { locale } : void 0);
17618
+ const apiResponse = await httpService.get(url);
17351
17619
  if (!apiResponse.data) {
17352
17620
  this.logger?.warn("[CloudAgentProvider] No data in support scenes response");
17353
17621
  return [];
17354
17622
  }
17355
17623
  const scenes = apiResponse.data.scenes || [];
17356
- this.logger?.info(`[CloudAgentProvider] Retrieved ${scenes.length} support scenes`);
17624
+ this.logger?.info(`[CloudAgentProvider] Retrieved ${scenes.length} support scenes${locale ? ` for locale: ${locale}` : ""}`);
17357
17625
  return scenes;
17358
17626
  } catch (error) {
17359
17627
  this.logger?.error("[CloudAgentProvider] Failed to get support scenes:", error);
@@ -17369,7 +17637,8 @@ var CloudAgentProvider = class CloudAgentProvider {
17369
17637
  type: "cloud",
17370
17638
  status,
17371
17639
  createdAt: data.createdAt ? new Date(data.createdAt) : void 0,
17372
- capabilities: this.options.clientCapabilities
17640
+ capabilities: this.options.clientCapabilities,
17641
+ isUserDefinedTitle: data.isUserDefinedTitle
17373
17642
  };
17374
17643
  }
17375
17644
  /**
@@ -17385,55 +17654,498 @@ var CloudAgentProvider = class CloudAgentProvider {
17385
17654
  const queryString = searchParams.toString();
17386
17655
  return queryString ? `${path}?${queryString}` : path;
17387
17656
  }
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
17657
  /**
17425
- * Create an ActiveSessionImpl instance
17658
+ * 获取已安装插件列表
17659
+ * GET /console/as/user/plugins/installed
17660
+ */
17661
+ async getInstalledPlugins(forceRefresh) {
17662
+ try {
17663
+ const result = ((await httpService.get("/console/as/user/plugins/installed")).data?.plugins || []).map((p) => ({
17664
+ name: p.plugin_name,
17665
+ marketplaceName: p.marketplace_name,
17666
+ status: p.enabled ? "enabled" : "disabled",
17667
+ description: p.description,
17668
+ version: p.version,
17669
+ installScope: p.scope === "local" ? "project" : p.scope,
17670
+ installedScopes: [p.scope],
17671
+ installId: p.id
17672
+ }));
17673
+ result.forEach((plugin) => {
17674
+ this.pluginCache.set(plugin.name, plugin);
17675
+ });
17676
+ return result;
17677
+ } catch (error) {
17678
+ this.logger?.error("[CloudAgentProvider] getInstalledPlugins failed:", error);
17679
+ throw error;
17680
+ }
17681
+ }
17682
+ /**
17683
+ * 安装插件
17684
+ * POST /console/as/user/plugins/install
17426
17685
  *
17427
- * @param sessionId - Session ID
17428
- * @param agentId - Agent ID
17429
- * @param connection - Already connected AgentConnection
17430
- * @param options - Additional options
17686
+ * @param pluginNames - 插件名称数组
17687
+ * @param marketplaceNameOrId - 市场名称或 ID
17431
17688
  */
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;
17689
+ async installPlugins(pluginNames, marketplaceNameOrId, installScope, marketplaceSource, workspacePath) {
17690
+ try {
17691
+ const marketplaceId = await this.findMarketplaceId(marketplaceNameOrId);
17692
+ if (!marketplaceId) return {
17693
+ success: false,
17694
+ error: `Marketplace not found: ${marketplaceNameOrId}`
17695
+ };
17696
+ const failed = (await Promise.allSettled(pluginNames.map((pluginName) => httpService.post("/console/as/user/plugins/install", {
17697
+ plugin_name: pluginName,
17698
+ marketplace_id: marketplaceId,
17699
+ version: "latest"
17700
+ })))).filter((r) => r.status === "rejected");
17701
+ if (failed.length > 0) {
17702
+ const errors = failed.map((r) => r.reason?.message || "Unknown error");
17703
+ return {
17704
+ success: false,
17705
+ error: `安装失败 ${failed.length} 个插件: ${errors.join(", ")}`
17706
+ };
17707
+ }
17708
+ return { success: true };
17709
+ } catch (error) {
17710
+ return {
17711
+ success: false,
17712
+ error: this.extractErrorMessage(error)
17713
+ };
17714
+ }
17715
+ }
17716
+ /**
17717
+ * 卸载插件
17718
+ * POST /console/as/user/plugins/installed/:id/uninstall
17719
+ *
17720
+ * 完整链路:
17721
+ * CloudAgentProvider.uninstallPlugin()
17722
+ * -> HTTP POST /console/as/user/plugins/installed/:id/uninstall
17723
+ * -> agentserver: PluginInstallService.Uninstall()
17724
+ * -> 软删除 DB + 异步同步到活跃沙箱
17725
+ *
17726
+ * @param pluginName - 插件名称
17727
+ * @param marketplaceName - 市场名称(用于标识唯一插件)
17728
+ * @param scope - 卸载范围 ('user' | 'project' | 'project-local')
17729
+ */
17730
+ async uninstallPlugin(pluginName, marketplaceName, scope) {
17731
+ try {
17732
+ const installId = await this.findPluginInstallId(pluginName);
17733
+ if (!installId) return {
17734
+ success: false,
17735
+ error: `Plugin not found or not installed: ${pluginName}`
17736
+ };
17737
+ await httpService.post(`/console/as/user/plugins/installed/${installId}/uninstall`);
17738
+ return { success: true };
17739
+ } catch (error) {
17740
+ return {
17741
+ success: false,
17742
+ error: this.extractErrorMessage(error)
17743
+ };
17744
+ }
17745
+ }
17746
+ /**
17747
+ * 获取插件市场列表
17748
+ * GET /console/as/marketplace/sources
17749
+ */
17750
+ async getPluginMarketplaces(forceRefresh) {
17751
+ try {
17752
+ const result = ((await httpService.get("/console/as/marketplace/sources")).data?.sources || []).map((src) => ({
17753
+ id: src.id,
17754
+ name: src.name,
17755
+ type: this.mapSourceType(src.source_type),
17756
+ source: { url: src.url },
17757
+ description: src.name,
17758
+ isBuiltin: src.is_default
17759
+ }));
17760
+ result.forEach((m) => {
17761
+ const marketplaceInfo = {
17762
+ id: m.id,
17763
+ name: m.name
17764
+ };
17765
+ this.marketplaceCache.set(m.name, marketplaceInfo);
17766
+ this.marketplaceCache.set(m.id, marketplaceInfo);
17767
+ });
17768
+ return result;
17769
+ } catch (error) {
17770
+ this.logger?.error("[CloudAgentProvider] getPluginMarketplaces failed:", error);
17771
+ throw error;
17772
+ }
17773
+ }
17774
+ /**
17775
+ * 获取市场下的插件列表
17776
+ * - 有 searchText: GET /console/as/marketplace/plugins/search (跨所有市场搜索)
17777
+ * - 无 searchText: GET /console/as/marketplace/plugins (指定市场)
17778
+ *
17779
+ * @param marketplaceNameOrId - 市场名称或 ID(优先使用 ID,如果是名称则从缓存查询 ID)
17780
+ * @param forceRefresh - 是否强制刷新
17781
+ * @param searchText - 搜索关键字(如果提供,则跨所有市场搜索)
17782
+ */
17783
+ async getMarketplacePlugins(marketplaceNameOrId, forceRefresh, searchText) {
17784
+ try {
17785
+ if (searchText) return ((await httpService.get("/console/as/marketplace/plugins/search", { params: {
17786
+ q: searchText,
17787
+ page: 1,
17788
+ page_size: 100
17789
+ } })).data?.plugins || []).map((p) => this.mapPluginData(p));
17790
+ const sourceId = await this.findMarketplaceId(marketplaceNameOrId);
17791
+ if (!sourceId) {
17792
+ this.logger?.warn(`[CloudAgentProvider] Marketplace not found: ${marketplaceNameOrId}`);
17793
+ return [];
17794
+ }
17795
+ const params = {
17796
+ source_id: sourceId,
17797
+ page: 1,
17798
+ page_size: 100
17799
+ };
17800
+ return ((await httpService.get("/console/as/marketplace/plugins", { params })).data?.plugins || []).map((p) => this.mapPluginData(p));
17801
+ } catch (error) {
17802
+ this.logger?.error("[CloudAgentProvider] getMarketplacePlugins failed:", error);
17803
+ throw error;
17804
+ }
17805
+ }
17806
+ /**
17807
+ * 获取插件详情
17808
+ * GET /console/as/marketplace/plugins/:name/detail
17809
+ *
17810
+ * @param pluginName - 插件名称
17811
+ * @param marketplaceNameOrId - 市场名称或 ID(优先使用 ID,如果是名称则从缓存查询 ID)
17812
+ */
17813
+ async getPluginDetail(pluginName, marketplaceNameOrId) {
17814
+ try {
17815
+ const sourceId = await this.findMarketplaceId(marketplaceNameOrId);
17816
+ if (!sourceId) {
17817
+ this.logger?.warn(`[CloudAgentProvider] Marketplace not found: ${marketplaceNameOrId}`);
17818
+ return null;
17819
+ }
17820
+ const p = (await httpService.get(`/console/as/marketplace/plugins/${pluginName}/detail`, { params: { source_id: sourceId } })).data?.plugin;
17821
+ if (!p) return null;
17822
+ const capabilities = p.capabilities ? this.parseCapabilities(p.capabilities) : {};
17823
+ const tags = p.tags ? JSON.parse(p.tags) : [];
17824
+ return {
17825
+ name: p.name,
17826
+ marketplaceName: p.marketplace_name,
17827
+ description: p.description,
17828
+ version: p.version,
17829
+ iconUrl: p.icon_url,
17830
+ tags,
17831
+ installed: p.installed,
17832
+ status: p.enabled ? "enabled" : p.installed ? "disabled" : "not-installed",
17833
+ readme: p.readme,
17834
+ author: p.author,
17835
+ homepage: p.homepage,
17836
+ repositoryUrl: p.repository_url,
17837
+ license: p.license,
17838
+ ...capabilities
17839
+ };
17840
+ } catch (error) {
17841
+ this.logger?.error("[CloudAgentProvider] getPluginDetail failed:", error);
17842
+ throw error;
17843
+ }
17844
+ }
17845
+ /**
17846
+ * 添加插件市场
17847
+ * POST /console/as/marketplace/sources
17848
+ */
17849
+ async addPluginMarketplace(sourceUrl, name) {
17850
+ try {
17851
+ const body = {
17852
+ source_type: sourceUrl.startsWith("http") ? "url" : "github",
17853
+ url: sourceUrl,
17854
+ name: name || sourceUrl
17855
+ };
17856
+ const sourceData = (await httpService.post("/console/as/marketplace/sources", body)).data?.source;
17857
+ if (!sourceData) throw new Error("Invalid response from server");
17858
+ const marketplaceInfo = {
17859
+ id: sourceData.id,
17860
+ name: sourceData.name
17861
+ };
17862
+ this.marketplaceCache.set(sourceData.name, marketplaceInfo);
17863
+ this.marketplaceCache.set(sourceData.id, marketplaceInfo);
17864
+ return {
17865
+ success: true,
17866
+ marketplace: {
17867
+ id: sourceData.id,
17868
+ name: sourceData.name,
17869
+ type: this.mapSourceType(sourceData.source_type),
17870
+ source: { url: sourceData.url },
17871
+ isBuiltin: sourceData.is_default
17872
+ }
17873
+ };
17874
+ } catch (error) {
17875
+ return {
17876
+ success: false,
17877
+ error: this.extractErrorMessage(error)
17878
+ };
17879
+ }
17880
+ }
17881
+ /**
17882
+ * 删除插件市场
17883
+ * POST /console/as/marketplace/sources/:id/delete
17884
+ */
17885
+ async removePluginMarketplace(marketplaceNameOrId) {
17886
+ try {
17887
+ const marketplaceId = await this.findMarketplaceId(marketplaceNameOrId);
17888
+ if (!marketplaceId) return {
17889
+ success: false,
17890
+ error: `Marketplace not found: ${marketplaceNameOrId}`
17891
+ };
17892
+ await httpService.post(`/console/as/marketplace/sources/${marketplaceId}/delete`, {});
17893
+ return { success: true };
17894
+ } catch (error) {
17895
+ return {
17896
+ success: false,
17897
+ error: this.extractErrorMessage(error)
17898
+ };
17899
+ }
17900
+ }
17901
+ /**
17902
+ * 刷新插件市场
17903
+ * POST /console/as/marketplace/sources/:id/check-updates
17904
+ */
17905
+ async refreshPluginMarketplace(marketplaceNameOrId) {
17906
+ try {
17907
+ const marketplaceId = await this.findMarketplaceId(marketplaceNameOrId);
17908
+ if (!marketplaceId) return {
17909
+ success: false,
17910
+ error: `Marketplace not found: ${marketplaceNameOrId}`
17911
+ };
17912
+ return {
17913
+ success: true,
17914
+ plugins: (await httpService.post(`/console/as/marketplace/sources/${marketplaceId}/check-updates`, {})).data?.updated_plugins || []
17915
+ };
17916
+ } catch (error) {
17917
+ return {
17918
+ success: false,
17919
+ error: this.extractErrorMessage(error)
17920
+ };
17921
+ }
17922
+ }
17923
+ /**
17924
+ * 批量切换插件启用/禁用状态
17925
+ * POST /console/as/user/plugins/installed/:id/toggle
17926
+ */
17927
+ async batchTogglePlugins(request) {
17928
+ try {
17929
+ const results = await Promise.allSettled(request.items.map(async (item) => {
17930
+ const installId = await this.findPluginInstallId(item.pluginName);
17931
+ if (!installId) throw new Error(`Plugin not found or not installed: ${item.pluginName}`);
17932
+ const enabled = item.operation === "enable";
17933
+ await httpService.post(`/console/as/user/plugins/installed/${installId}/toggle`, { enabled });
17934
+ return item;
17935
+ }));
17936
+ const succeededPlugins = [];
17937
+ const failedPlugins = [];
17938
+ results.forEach((r, i) => {
17939
+ const item = request.items[i];
17940
+ if (r.status === "fulfilled") succeededPlugins.push(item);
17941
+ else failedPlugins.push({
17942
+ ...item,
17943
+ error: r.reason?.message || "Unknown error"
17944
+ });
17945
+ });
17946
+ return {
17947
+ success: failedPlugins.length === 0,
17948
+ succeededPlugins,
17949
+ failedPlugins
17950
+ };
17951
+ } catch (error) {
17952
+ return {
17953
+ success: false,
17954
+ succeededPlugins: [],
17955
+ failedPlugins: request.items.map((item) => ({
17956
+ ...item,
17957
+ error: this.extractErrorMessage(error)
17958
+ }))
17959
+ };
17960
+ }
17961
+ }
17962
+ /**
17963
+ * 将后端插件数据映射为前端格式
17964
+ */
17965
+ mapPluginData(p) {
17966
+ const capabilities = p.capabilities ? this.parseCapabilities(p.capabilities) : {};
17967
+ let tags = [];
17968
+ if (p.tags) {
17969
+ if (Array.isArray(p.tags)) tags = p.tags;
17970
+ else if (typeof p.tags === "string") try {
17971
+ const parsed = JSON.parse(p.tags);
17972
+ tags = Array.isArray(parsed) ? parsed : [parsed];
17973
+ } catch {
17974
+ tags = p.tags.split(",").map((t) => t.trim()).filter((t) => t);
17975
+ }
17976
+ }
17977
+ return {
17978
+ name: p.name,
17979
+ marketplaceName: p.marketplace_name,
17980
+ description: p.description,
17981
+ version: p.version,
17982
+ iconUrl: p.icon_url,
17983
+ tags,
17984
+ installed: p.installed,
17985
+ status: p.enabled ? "enabled" : p.installed ? "disabled" : "not-installed",
17986
+ installedScopes: p.installed ? [p.installed_scope] : [],
17987
+ ...capabilities
17988
+ };
17989
+ }
17990
+ /**
17991
+ * 从缓存中查找插件的 install_id
17992
+ * 如果缓存未命中,则调用 API 获取并缓存
17993
+ *
17994
+ * @param pluginName - 插件名称
17995
+ * @returns install_id 或 null
17996
+ */
17997
+ async findPluginInstallId(pluginName) {
17998
+ const cached = this.pluginCache.get(pluginName);
17999
+ if (cached) return cached.installId;
18000
+ await this.getInstalledPlugins();
18001
+ return this.pluginCache.get(pluginName)?.installId || null;
18002
+ }
18003
+ /**
18004
+ * 从缓存中查找 marketplace ID
18005
+ * 如果缓存未命中,则调用 API 获取并缓存
18006
+ */
18007
+ async findMarketplaceId(nameOrId) {
18008
+ const cached = this.marketplaceCache.get(nameOrId);
18009
+ if (cached) return cached.id;
18010
+ await this.getPluginMarketplaces();
18011
+ return this.marketplaceCache.get(nameOrId)?.id || null;
18012
+ }
18013
+ /**
18014
+ * 提取 API 错误信息
18015
+ * 从 AxiosError 中提取详细的错误信息,包括 HTTP 状态码、错误码和错误消息
18016
+ */
18017
+ extractErrorMessage(error) {
18018
+ if (error instanceof AxiosError) {
18019
+ const status = error.response?.status;
18020
+ const apiResponse = error.response?.data;
18021
+ const parts = [];
18022
+ if (status) parts.push(`HTTP ${status}`);
18023
+ if (apiResponse?.code) parts.push(`Code ${apiResponse.code}`);
18024
+ if (apiResponse?.msg) parts.push(apiResponse.msg);
18025
+ else if (error.message) parts.push(error.message);
18026
+ const errorMessage = parts.join(" - ");
18027
+ this.logger?.error("[CloudAgentProvider] API Error:", {
18028
+ status,
18029
+ code: apiResponse?.code,
18030
+ msg: apiResponse?.msg,
18031
+ requestId: apiResponse?.requestId,
18032
+ url: error.config?.url,
18033
+ method: error.config?.method
18034
+ });
18035
+ return errorMessage;
18036
+ }
18037
+ if (error instanceof Error) return error.message;
18038
+ return "Unknown error";
18039
+ }
18040
+ /**
18041
+ * 映射后端 source_type 到前端类型
18042
+ */
18043
+ mapSourceType(sourceType) {
18044
+ switch (sourceType) {
18045
+ case "github": return "github";
18046
+ case "official": return "custom";
18047
+ default: return "custom";
18048
+ }
18049
+ }
18050
+ /**
18051
+ * 解析 capabilities JSON 字符串
18052
+ */
18053
+ parseCapabilities(capabilitiesStr) {
18054
+ try {
18055
+ const cap = JSON.parse(capabilitiesStr);
18056
+ return {
18057
+ commands: cap.commands,
18058
+ skills: cap.skills,
18059
+ mcpServers: cap.mcp,
18060
+ agents: cap.agents,
18061
+ hooks: cap.hooks,
18062
+ rules: cap.rules
18063
+ };
18064
+ } catch {
18065
+ return {};
18066
+ }
18067
+ }
18068
+ /**
18069
+ * 上报 telemetry 事件(Cloud 模式)
18070
+ * 通过 HTTP POST 发送到 /v2/report
18071
+ * 注入用户信息和浏览器环境等公共字段
18072
+ */
18073
+ async reportTelemetry(eventName, payload) {
18074
+ try {
18075
+ const account = accountService.getAccount();
18076
+ const commonFields = {};
18077
+ if (account) {
18078
+ commonFields.userId = account.uid;
18079
+ commonFields.userNickname = account.nickname;
18080
+ if (account.enterpriseId) commonFields.enterpriseId = account.enterpriseId;
18081
+ if (account.enterpriseUserName) commonFields.username = account.enterpriseUserName;
18082
+ }
18083
+ if (typeof navigator !== "undefined") {
18084
+ commonFields.userAgent = navigator.userAgent;
18085
+ commonFields.os = navigator.platform;
18086
+ }
18087
+ const events = [{
18088
+ eventCode: eventName,
18089
+ timestamp: Date.now(),
18090
+ reportDelay: 0,
18091
+ ...commonFields,
18092
+ ...payload
18093
+ }];
18094
+ await httpService.post("/v2/report", events);
18095
+ } catch (error) {
18096
+ this.logger?.warn("reportTelemetry() failed:", error);
18097
+ }
18098
+ }
18099
+ };
18100
+
18101
+ //#endregion
18102
+ //#region ../agent-provider/src/common/providers/local-agent-provider/local-connection.ts
18103
+ /**
18104
+ * Local Agent Connection
18105
+ * Wraps AcpJsonRpcClient to implement AgentConnection interface
18106
+ *
18107
+ * Uses IWidgetChannel for IPC communication with ExtensionHost
18108
+ * Migrated from ipc-agent-provider for unified local agent access
18109
+ */
18110
+
18111
+ //#endregion
18112
+ //#region ../agent-provider/src/common/client/session.ts
18113
+ /**
18114
+ * ActiveSessionImpl - Implements the ActiveSession interface
18115
+ *
18116
+ * This class wraps an AgentConnection and provides the session-centric API.
18117
+ * It is created by SessionManager when creating or loading sessions.
18118
+ *
18119
+ * @example
18120
+ * ```typescript
18121
+ * // Created by client.sessions.new() or client.sessions.load()
18122
+ * const session = await client.sessions.new({ cwd: '/workspace' });
18123
+ *
18124
+ * // Access agent state
18125
+ * console.log(session.agentState.status);
18126
+ *
18127
+ * // Send prompt
18128
+ * const response = await session.prompts.send({ content: 'Hello!' });
18129
+ *
18130
+ * // Cleanup
18131
+ * session.disconnect();
18132
+ * ```
18133
+ */
18134
+ var ActiveSessionImpl = class {
18135
+ /**
18136
+ * Create an ActiveSessionImpl instance
18137
+ *
18138
+ * @param sessionId - Session ID
18139
+ * @param agentId - Agent ID
18140
+ * @param connection - Already connected AgentConnection
18141
+ * @param options - Additional options
18142
+ */
18143
+ constructor(sessionId, agentId, connection, options = {}) {
18144
+ this._availableCommands = [];
18145
+ this.listeners = /* @__PURE__ */ new Map();
18146
+ this.onceListeners = /* @__PURE__ */ new Map();
18147
+ this.connectionListeners = [];
18148
+ this._id = sessionId;
17437
18149
  this._agentId = agentId;
17438
18150
  this.connection = connection;
17439
18151
  this.logger = options.logger;
@@ -17458,6 +18170,18 @@ var ActiveSessionImpl = class {
17458
18170
  return this._agentId;
17459
18171
  }
17460
18172
  /**
18173
+ * Actual workspace path (set from newSession response _meta)
18174
+ */
18175
+ get cwd() {
18176
+ return this._cwd;
18177
+ }
18178
+ /**
18179
+ * Set actual workspace path (called by SessionManager after createSession)
18180
+ */
18181
+ setCwd(cwd) {
18182
+ this._cwd = cwd;
18183
+ }
18184
+ /**
17461
18185
  * Agent state (live connection state)
17462
18186
  * Returns LocalAgentState or CloudAgentState based on transport type
17463
18187
  */
@@ -17651,10 +18375,10 @@ var ActiveSessionImpl = class {
17651
18375
  return this.connection.cancelQuestion(toolCallId, reason);
17652
18376
  }
17653
18377
  /**
17654
- * Callback for tool operations (skip or cancel)
18378
+ * Callback for tool operations (approve / skip / cancel)
17655
18379
  * @param toolCallId Tool call ID
17656
18380
  * @param toolName Tool name
17657
- * @param action Action to perform ('skip' or 'cancel')
18381
+ * @param action Action to perform ('approve' / 'skip' / 'cancel')
17658
18382
  */
17659
18383
  async toolCallback(toolCallId, toolName, action) {
17660
18384
  return await this.getConnectionOrThrow().toolCallback(this._id, toolCallId, toolName, action);
@@ -17698,6 +18422,7 @@ var ActiveSessionImpl = class {
17698
18422
  * ```
17699
18423
  */
17700
18424
  async setSessionModel(modelId) {
18425
+ this._currentModelId = modelId;
17701
18426
  await this.getConnectionOrThrow().setSessionModel(this._id, modelId);
17702
18427
  }
17703
18428
  /**
@@ -17775,11 +18500,23 @@ var ActiveSessionImpl = class {
17775
18500
  * Disconnect from the session/agent
17776
18501
  */
17777
18502
  disconnect() {
18503
+ this.removeConnectionListeners();
17778
18504
  this.connection.disconnect();
17779
18505
  this.removeAllListeners();
17780
18506
  this.logger?.info(`Session ${this._id}: Disconnected`);
17781
18507
  }
17782
18508
  /**
18509
+ * Detach the session from connection events without disconnecting the connection.
18510
+ * This should be called when the session is being replaced but the connection is shared.
18511
+ * Unlike disconnect(), this only removes event listeners without closing the connection.
18512
+ */
18513
+ detach() {
18514
+ this.logger?.info(`Session ${this._id}: Detaching from connection events`);
18515
+ this.removeConnectionListeners();
18516
+ this.removeAllListeners();
18517
+ this.logger?.info(`Session ${this._id}: Detached successfully`);
18518
+ }
18519
+ /**
17783
18520
  * Symbol.dispose for 'using' keyword support
17784
18521
  * Automatically disconnects and cleans up when session goes out of scope
17785
18522
  *
@@ -17798,60 +18535,85 @@ var ActiveSessionImpl = class {
17798
18535
  if (!this.connection.isInitialized) throw new Error(`Session ${this._id}: Connection not initialized.`);
17799
18536
  return this.connection;
17800
18537
  }
18538
+ /**
18539
+ * 在 connection 上注册 listener 并保存引用,便于 disconnect 时移除
18540
+ */
18541
+ addConnectionListener(connection, event, listener) {
18542
+ connection.on(event, listener);
18543
+ this.connectionListeners.push({
18544
+ event,
18545
+ listener
18546
+ });
18547
+ }
18548
+ /**
18549
+ * 从 connection 上移除所有本 session 注册的 listener
18550
+ */
18551
+ removeConnectionListeners() {
18552
+ for (const { event, listener } of this.connectionListeners) this.connection.off(event, listener);
18553
+ this.connectionListeners = [];
18554
+ }
17801
18555
  setupConnectionEvents(connection) {
17802
- connection.on("connected", () => {
18556
+ this.addConnectionListener(connection, "connected", () => {
17803
18557
  this.emit("connected", void 0);
17804
18558
  });
17805
- connection.on("disconnected", () => {
18559
+ this.addConnectionListener(connection, "disconnected", () => {
17806
18560
  this.emit("disconnected", void 0);
17807
18561
  });
17808
- connection.on("error", (error) => {
18562
+ this.addConnectionListener(connection, "error", (error) => {
17809
18563
  this.emit("error", error);
17810
18564
  });
17811
- connection.on("sessionUpdate", (update) => {
18565
+ this.addConnectionListener(connection, "sessionUpdate", (update) => {
18566
+ const notificationSessionId = update?.sessionId;
18567
+ if (notificationSessionId && notificationSessionId !== this._id) {
18568
+ console.log(`[RT-DEBUG][AgentMgr:Session] sessionUpdate SKIPPED: notifSessionId mismatch, notif=${notificationSessionId?.substring(0, 8)}, my=${this._id?.substring(0, 8)}`);
18569
+ return;
18570
+ }
17812
18571
  this.emit("sessionUpdate", update);
17813
18572
  });
17814
- connection.on("artifactCreated", (artifact) => {
17815
- console.log("[Session] Forwarding artifactCreated:", {
17816
- artifactUri: artifact.uri,
17817
- artifactType: artifact.type
17818
- });
18573
+ this.addConnectionListener(connection, "artifactCreated", (artifact) => {
18574
+ if (!this.shouldForwardArtifact(artifact)) return;
17819
18575
  this.emit("artifactCreated", artifact);
17820
18576
  });
17821
- connection.on("artifactUpdated", (artifact) => {
17822
- console.log("[Session] Forwarding artifactUpdated:", {
17823
- artifactUri: artifact.uri,
17824
- artifactType: artifact.type
17825
- });
18577
+ this.addConnectionListener(connection, "artifactUpdated", (artifact) => {
18578
+ if (!this.shouldForwardArtifact(artifact)) return;
17826
18579
  this.emit("artifactUpdated", artifact);
17827
18580
  });
17828
- connection.on("artifactDeleted", (artifact) => {
17829
- console.log("[Session] Forwarding artifactDeleted:", { artifactUri: artifact.uri });
18581
+ this.addConnectionListener(connection, "artifactDeleted", (artifact) => {
18582
+ if (!this.shouldForwardArtifact(artifact)) return;
17830
18583
  this.emit("artifactDeleted", artifact);
17831
18584
  });
17832
- connection.on("permissionRequest", (request) => {
18585
+ this.addConnectionListener(connection, "permissionRequest", (request) => {
17833
18586
  this.emit("permissionRequest", request);
17834
18587
  });
17835
- connection.on("questionRequest", (request) => {
18588
+ this.addConnectionListener(connection, "questionRequest", (request) => {
17836
18589
  this.emit("questionRequest", request);
17837
18590
  });
17838
- connection.on("questionCancelled", () => {
18591
+ this.addConnectionListener(connection, "questionCancelled", () => {
17839
18592
  this.prompts.cancel();
17840
18593
  });
17841
- connection.on("usageUpdate", (usage) => {
18594
+ this.addConnectionListener(connection, "usageUpdate", (usage) => {
17842
18595
  this.emit("usageUpdate", usage);
17843
18596
  });
17844
- connection.on("checkpointCreated", (checkpoint) => {
18597
+ this.addConnectionListener(connection, "checkpointCreated", (checkpoint) => {
18598
+ const originSessionId = checkpoint.__sessionId;
18599
+ if (originSessionId && originSessionId !== this._id) return;
17845
18600
  this.emit("checkpointCreated", checkpoint);
17846
18601
  });
17847
- connection.on("checkpointUpdated", (checkpoint) => {
18602
+ this.addConnectionListener(connection, "checkpointUpdated", (checkpoint) => {
18603
+ const originSessionId = checkpoint.__sessionId;
18604
+ if (originSessionId && originSessionId !== this._id) return;
17848
18605
  this.emit("checkpointUpdated", checkpoint);
17849
18606
  });
17850
- connection.on("command", (command) => {
17851
- console.log("[Session] Forwarding command:", {
17852
- action: command.action,
17853
- paramsKeys: command.params ? Object.keys(command.params) : []
17854
- });
18607
+ this.addConnectionListener(connection, "command", (command) => {
18608
+ const originSessionId = command.__sessionId;
18609
+ if (originSessionId && originSessionId !== this._id) {
18610
+ console.log("[Session] Command not forwarded:", {
18611
+ command,
18612
+ originSessionId,
18613
+ sessionId: this._id
18614
+ });
18615
+ return;
18616
+ }
17855
18617
  this.emit("command", command);
17856
18618
  });
17857
18619
  }
@@ -17861,6 +18623,15 @@ var ActiveSessionImpl = class {
17861
18623
  _meta: response._meta ?? void 0
17862
18624
  };
17863
18625
  }
18626
+ /**
18627
+ * 判断 artifact 是否应该转发给当前 session
18628
+ * 所有类型的 artifact 都按 __sessionId 严格隔离
18629
+ */
18630
+ shouldForwardArtifact(artifact) {
18631
+ const originSessionId = artifact.__sessionId;
18632
+ if (!originSessionId || originSessionId !== this._id) return false;
18633
+ return true;
18634
+ }
17864
18635
  };
17865
18636
 
17866
18637
  //#endregion
@@ -17915,7 +18686,8 @@ var SessionManager = class {
17915
18686
  createdAt: agent.createdAt,
17916
18687
  lastActivityAt: agent.updatedAt,
17917
18688
  cwd: agent.type === "local" ? agent.cwd : void 0,
17918
- isPlayground: agent.isPlayground
18689
+ isPlayground: agent.isPlayground,
18690
+ isUserDefinedTitle: agent.isUserDefinedTitle
17919
18691
  }));
17920
18692
  console.log("[SessionManager] Returning sessions:", {
17921
18693
  count: sessions.length,
@@ -17942,13 +18714,26 @@ var SessionManager = class {
17942
18714
  if (this.provider.create) {
17943
18715
  agentId = await this.provider.create(params);
17944
18716
  this.logger?.debug(`Created new agent: ${agentId}`);
18717
+ if (params.options?.onSessionPrepared) {
18718
+ const initialPrompt = params.options?.prompt;
18719
+ const initialTitle = initialPrompt?.slice(0, 50) || "";
18720
+ params.options.onSessionPrepared({
18721
+ id: agentId,
18722
+ agentId,
18723
+ name: initialTitle + (initialPrompt && initialPrompt.length > 50 ? "..." : ""),
18724
+ status: "connecting",
18725
+ cwd: params.cwd || "",
18726
+ createdAt: /* @__PURE__ */ new Date()
18727
+ });
18728
+ this.logger?.debug(`Called onSessionPrepared for: ${agentId}`);
18729
+ }
17945
18730
  } else throw new Error("Provider does not support creating agents. Use sessions.load() with an existing sessionId.");
17946
18731
  const connection = await this.provider.connect(agentId);
17947
18732
  this.logger?.debug(`Connected to agent: ${agentId}`);
17948
18733
  const response = await connection.createSession({
17949
- _meta: params._meta,
18734
+ _meta: params.options?._meta,
17950
18735
  cwd: params.cwd,
17951
- mcpServers: params.mcpServers
18736
+ mcpServers: params.options?.mcpServers
17952
18737
  });
17953
18738
  if (this.provider.registerSession) {
17954
18739
  this.provider.registerSession(response.sessionId, agentId);
@@ -17963,6 +18748,8 @@ var SessionManager = class {
17963
18748
  session.setModes(response.modes?.availableModes, response.modes?.currentModeId);
17964
18749
  const availableModels = this.extractAvailableModels(response);
17965
18750
  if (availableModels) session.setModels(availableModels, response.models?.currentModelId);
18751
+ const responseCwd = response._meta?.["codebuddy.ai"]?.cwd;
18752
+ if (responseCwd) session.setCwd(responseCwd);
17966
18753
  this.logger?.info(`Session created: ${response.sessionId}`);
17967
18754
  return session;
17968
18755
  }
@@ -18129,6 +18916,26 @@ var AgentClient = class {
18129
18916
  throw error;
18130
18917
  }
18131
18918
  },
18919
+ updateStatus: async (sessionId, status) => {
18920
+ this.logger?.debug("AgentClient.sessions.updateStatus called", {
18921
+ sessionId,
18922
+ status
18923
+ });
18924
+ try {
18925
+ if (this.provider.updateStatus) {
18926
+ const result = await this.provider.updateStatus(sessionId, status);
18927
+ this.logger?.info("Session status updated successfully", {
18928
+ sessionId,
18929
+ status
18930
+ });
18931
+ return result;
18932
+ }
18933
+ throw new Error("Provider does not support updateStatus method");
18934
+ } catch (error) {
18935
+ this.logger?.error("Failed to update session status", error);
18936
+ throw error;
18937
+ }
18938
+ },
18132
18939
  move: async (sessionId) => {
18133
18940
  this.logger?.debug("AgentClient.sessions.move called", { sessionId });
18134
18941
  try {
@@ -18161,6 +18968,16 @@ var AgentClient = class {
18161
18968
  };
18162
18969
  }
18163
18970
  },
18971
+ requestYieldAfterCurrentStep: async (sessionId) => {
18972
+ try {
18973
+ if (this.provider?.requestYieldAfterCurrentStep) return await this.provider.requestYieldAfterCurrentStep(sessionId);
18974
+ this.logger?.warn("Provider does not support requestYieldAfterCurrentStep");
18975
+ return false;
18976
+ } catch (error) {
18977
+ this.logger?.error("Failed to request yield after current step", error);
18978
+ return false;
18979
+ }
18980
+ },
18164
18981
  getCurrentWorkspaces: async (filter) => {
18165
18982
  this.logger?.debug("AgentClient.sessions.getCurrentWorkspaces called", filter);
18166
18983
  try {
@@ -18176,15 +18993,109 @@ var AgentClient = class {
18176
18993
  return [];
18177
18994
  }
18178
18995
  },
18179
- on: (event, handler) => {
18180
- if (this.provider.on) this.provider.on(event, handler);
18181
- else this.logger?.warn(`Provider does not support event registration: ${String(event)}`);
18182
- },
18183
- off: (event, handler) => {
18184
- if (this.provider.off) this.provider.off(event, handler);
18185
- else this.logger?.warn(`Provider does not support event unregistration: ${String(event)}`);
18186
- },
18187
- openWorkspace: async (params) => {
18996
+ getAutomationSnapshot: async () => {
18997
+ try {
18998
+ if (this.provider?.getAutomationSnapshot) return await this.provider.getAutomationSnapshot();
18999
+ this.logger?.warn("Provider does not support getAutomationSnapshot");
19000
+ } catch (error) {
19001
+ this.logger?.error("Failed to get automation snapshot", error);
19002
+ }
19003
+ return {
19004
+ automations: [],
19005
+ inbox: [],
19006
+ runtimeState: {},
19007
+ updatedAt: Date.now()
19008
+ };
19009
+ },
19010
+ updateAutomation: async (payload) => {
19011
+ try {
19012
+ if (this.provider?.updateAutomation) return await this.provider.updateAutomation(payload);
19013
+ this.logger?.warn("Provider does not support updateAutomation");
19014
+ } catch (error) {
19015
+ this.logger?.error("Failed to update automation", error);
19016
+ return {
19017
+ success: false,
19018
+ message: error instanceof Error ? error.message : "Unknown error"
19019
+ };
19020
+ }
19021
+ return {
19022
+ success: false,
19023
+ message: "Provider does not support updateAutomation"
19024
+ };
19025
+ },
19026
+ deleteAutomation: async (id) => {
19027
+ try {
19028
+ if (this.provider?.deleteAutomation) return await this.provider.deleteAutomation(id);
19029
+ this.logger?.warn("Provider does not support deleteAutomation");
19030
+ } catch (error) {
19031
+ this.logger?.error("Failed to delete automation", error);
19032
+ return {
19033
+ success: false,
19034
+ message: error instanceof Error ? error.message : "Unknown error"
19035
+ };
19036
+ }
19037
+ return {
19038
+ success: false,
19039
+ message: "Provider does not support deleteAutomation"
19040
+ };
19041
+ },
19042
+ archiveAutomationInboxItem: async (itemId) => {
19043
+ try {
19044
+ if (this.provider?.archiveAutomationInboxItem) return await this.provider.archiveAutomationInboxItem(itemId);
19045
+ this.logger?.warn("Provider does not support archiveAutomationInboxItem");
19046
+ } catch (error) {
19047
+ this.logger?.error("Failed to archive automation inbox item", error);
19048
+ return {
19049
+ success: false,
19050
+ message: error instanceof Error ? error.message : "Unknown error"
19051
+ };
19052
+ }
19053
+ return {
19054
+ success: false,
19055
+ message: "Provider does not support archiveAutomationInboxItem"
19056
+ };
19057
+ },
19058
+ deleteAutomationInboxItem: async (itemId) => {
19059
+ try {
19060
+ if (this.provider?.deleteAutomationInboxItem) return await this.provider.deleteAutomationInboxItem(itemId);
19061
+ this.logger?.warn("Provider does not support deleteAutomationInboxItem");
19062
+ } catch (error) {
19063
+ this.logger?.error("Failed to delete automation inbox item", error);
19064
+ return {
19065
+ success: false,
19066
+ message: error instanceof Error ? error.message : "Unknown error"
19067
+ };
19068
+ }
19069
+ return {
19070
+ success: false,
19071
+ message: "Provider does not support deleteAutomationInboxItem"
19072
+ };
19073
+ },
19074
+ testAutomation: async (id) => {
19075
+ try {
19076
+ if (this.provider?.testAutomation) return await this.provider.testAutomation(id);
19077
+ this.logger?.warn("Provider does not support testAutomation");
19078
+ } catch (error) {
19079
+ this.logger?.error("Failed to test automation", error);
19080
+ return {
19081
+ success: false,
19082
+ message: error instanceof Error ? error.message : "Unknown error"
19083
+ };
19084
+ }
19085
+ return {
19086
+ success: false,
19087
+ message: "Provider does not support testAutomation"
19088
+ };
19089
+ },
19090
+ on: (event, handler) => {
19091
+ if (this.provider.on) this.provider.on(event, handler);
19092
+ else this.logger?.warn(`Provider does not support event registration: ${String(event)}`);
19093
+ },
19094
+ off: (event, handler) => {
19095
+ if (this.provider.off) this.provider.off(event, handler);
19096
+ else this.logger?.warn(`Provider does not support event unregistration: ${String(event)}`);
19097
+ },
19098
+ openWorkspace: async (params) => {
18188
19099
  try {
18189
19100
  if (this.provider && this.provider.openWorkspace) {
18190
19101
  const result = await this.provider.openWorkspace(params);
@@ -18317,6 +19228,167 @@ var AgentClient = class {
18317
19228
  };
18318
19229
  }
18319
19230
  },
19231
+ getSkillList: async (params) => {
19232
+ try {
19233
+ if (this.provider && this.provider.getSkillList) {
19234
+ const result = await this.provider.getSkillList(params);
19235
+ this.logger?.info("Skill list retrieved", {
19236
+ resultCount: result.results.length,
19237
+ hasError: !!result.error
19238
+ });
19239
+ return result;
19240
+ }
19241
+ return {
19242
+ results: [],
19243
+ error: "Provider does not support getSkillList"
19244
+ };
19245
+ } catch (error) {
19246
+ this.logger?.error("Failed to get skill list", error);
19247
+ return {
19248
+ results: [],
19249
+ error: error instanceof Error ? error.message : "Unknown error"
19250
+ };
19251
+ }
19252
+ },
19253
+ importSkill: async (params) => {
19254
+ try {
19255
+ if (this.provider && this.provider.importSkill) {
19256
+ const result = await this.provider.importSkill(params);
19257
+ this.logger?.info("Import skill completed", {
19258
+ success: result.success,
19259
+ hasError: !!result.error
19260
+ });
19261
+ return result;
19262
+ }
19263
+ return {
19264
+ success: false,
19265
+ error: "Provider does not support importSkill"
19266
+ };
19267
+ } catch (error) {
19268
+ this.logger?.error("Failed to import skill", error);
19269
+ return {
19270
+ success: false,
19271
+ error: error instanceof Error ? error.message : "Unknown error"
19272
+ };
19273
+ }
19274
+ },
19275
+ toggleSkill: async (params) => {
19276
+ try {
19277
+ if (this.provider && this.provider.toggleSkill) {
19278
+ const result = await this.provider.toggleSkill(params);
19279
+ this.logger?.info("Toggle skill completed", {
19280
+ success: result.success,
19281
+ hasError: !!result.error
19282
+ });
19283
+ return result;
19284
+ }
19285
+ return {
19286
+ success: false,
19287
+ error: "Provider does not support toggleSkill"
19288
+ };
19289
+ } catch (error) {
19290
+ this.logger?.error("Failed to toggle skill", error);
19291
+ return {
19292
+ success: false,
19293
+ error: error instanceof Error ? error.message : "Unknown error"
19294
+ };
19295
+ }
19296
+ },
19297
+ deleteSkill: async (params) => {
19298
+ try {
19299
+ if (this.provider && this.provider.deleteSkill) {
19300
+ const result = await this.provider.deleteSkill(params);
19301
+ this.logger?.info("Delete skill completed", {
19302
+ success: result.success,
19303
+ hasError: !!result.error
19304
+ });
19305
+ return result;
19306
+ }
19307
+ return {
19308
+ success: false,
19309
+ error: "Provider does not support deleteSkill"
19310
+ };
19311
+ } catch (error) {
19312
+ this.logger?.error("Failed to delete skill", error);
19313
+ return {
19314
+ success: false,
19315
+ error: error instanceof Error ? error.message : "Unknown error"
19316
+ };
19317
+ }
19318
+ },
19319
+ getSkillContent: async (params) => {
19320
+ try {
19321
+ if (this.provider && this.provider.getSkillContent) {
19322
+ const result = await this.provider.getSkillContent(params);
19323
+ this.logger?.info("Get skill content completed", { hasError: !!result.error });
19324
+ return result;
19325
+ }
19326
+ return {
19327
+ content: "",
19328
+ error: "Provider does not support getSkillContent"
19329
+ };
19330
+ } catch (error) {
19331
+ this.logger?.error("Failed to get skill content", error);
19332
+ return {
19333
+ content: "",
19334
+ error: error instanceof Error ? error.message : "Unknown error"
19335
+ };
19336
+ }
19337
+ },
19338
+ getMarketplaceSkills: async () => {
19339
+ try {
19340
+ if (this.provider && this.provider.getMarketplaceSkills) {
19341
+ const result = await this.provider.getMarketplaceSkills();
19342
+ this.logger?.info("Marketplace skills retrieved", {
19343
+ resultCount: result.results.length,
19344
+ hasError: !!result.error
19345
+ });
19346
+ return result;
19347
+ }
19348
+ return {
19349
+ results: [],
19350
+ error: "Provider does not support getMarketplaceSkills"
19351
+ };
19352
+ } catch (error) {
19353
+ this.logger?.error("Failed to get marketplace skills", error);
19354
+ return {
19355
+ results: [],
19356
+ error: error instanceof Error ? error.message : "Unknown error"
19357
+ };
19358
+ }
19359
+ },
19360
+ getMarketplaceSkillContent: async (params) => {
19361
+ try {
19362
+ if (this.provider && this.provider.getMarketplaceSkillContent) return await this.provider.getMarketplaceSkillContent(params);
19363
+ return {
19364
+ content: "",
19365
+ error: "Provider does not support getMarketplaceSkillContent"
19366
+ };
19367
+ } catch (error) {
19368
+ this.logger?.error("Failed to get marketplace skill content", error);
19369
+ return {
19370
+ content: "",
19371
+ error: error instanceof Error ? error.message : "Unknown error"
19372
+ };
19373
+ }
19374
+ },
19375
+ installMarketplaceSkill: async (params) => {
19376
+ try {
19377
+ if (this.provider && this.provider.installMarketplaceSkill) return await this.provider.installMarketplaceSkill(params);
19378
+ return {
19379
+ success: false,
19380
+ skillName: params.skillName,
19381
+ errorMessage: "Provider does not support installMarketplaceSkill"
19382
+ };
19383
+ } catch (error) {
19384
+ this.logger?.error("Failed to install marketplace skill", error);
19385
+ return {
19386
+ success: false,
19387
+ skillName: params.skillName,
19388
+ errorMessage: error instanceof Error ? error.message : "Unknown error"
19389
+ };
19390
+ }
19391
+ },
18320
19392
  batchTogglePlugins: async (request) => {
18321
19393
  try {
18322
19394
  if (this.provider && this.provider.batchTogglePlugins) {
@@ -18361,37 +19433,229 @@ var AgentClient = class {
18361
19433
  return [];
18362
19434
  }
18363
19435
  },
18364
- installPlugins: async (pluginNames, marketplaceName, installScope, marketplaceSource) => {
19436
+ installPlugins: async (pluginNames, marketplaceName, installScope, marketplaceSource, workspacePath) => {
19437
+ try {
19438
+ if (this.provider && "installPlugins" in this.provider && typeof this.provider.installPlugins === "function") {
19439
+ const result = await this.provider.installPlugins(pluginNames, marketplaceName, installScope, marketplaceSource, workspacePath);
19440
+ this.logger?.info("Install plugins", {
19441
+ pluginNames,
19442
+ marketplaceName,
19443
+ success: result.success
19444
+ });
19445
+ return result;
19446
+ }
19447
+ this.logger?.warn("Provider does not support installPlugins");
19448
+ return {
19449
+ success: false,
19450
+ error: "Provider does not support installPlugins"
19451
+ };
19452
+ } catch (error) {
19453
+ this.logger?.error("Failed to install plugins", error);
19454
+ return {
19455
+ success: false,
19456
+ error: error instanceof Error ? error.message : "Unknown error"
19457
+ };
19458
+ }
19459
+ },
19460
+ uninstallPlugin: async (pluginName, marketplaceName, scope) => {
19461
+ try {
19462
+ if (this.provider && "uninstallPlugin" in this.provider && typeof this.provider.uninstallPlugin === "function") {
19463
+ const result = await this.provider.uninstallPlugin(pluginName, marketplaceName, scope);
19464
+ this.logger?.info("Uninstall plugin", {
19465
+ pluginName,
19466
+ marketplaceName,
19467
+ scope,
19468
+ success: result.success
19469
+ });
19470
+ return result;
19471
+ }
19472
+ this.logger?.warn("Provider does not support uninstallPlugin");
19473
+ return {
19474
+ success: false,
19475
+ error: "Provider does not support uninstallPlugin"
19476
+ };
19477
+ } catch (error) {
19478
+ this.logger?.error("Failed to uninstall plugin", error);
19479
+ return {
19480
+ success: false,
19481
+ error: error instanceof Error ? error.message : "Unknown error"
19482
+ };
19483
+ }
19484
+ },
19485
+ updatePlugin: async (pluginName, marketplaceName) => {
19486
+ try {
19487
+ if (this.provider && "updatePlugin" in this.provider && typeof this.provider.updatePlugin === "function") {
19488
+ const result = await this.provider.updatePlugin(pluginName, marketplaceName);
19489
+ this.logger?.info("Update plugin", {
19490
+ pluginName,
19491
+ marketplaceName,
19492
+ success: result.success
19493
+ });
19494
+ return result;
19495
+ }
19496
+ this.logger?.warn("Provider does not support updatePlugin");
19497
+ return {
19498
+ success: false,
19499
+ error: "Provider does not support updatePlugin"
19500
+ };
19501
+ } catch (error) {
19502
+ this.logger?.error("Failed to update plugin", error);
19503
+ return {
19504
+ success: false,
19505
+ error: error instanceof Error ? error.message : "Unknown error"
19506
+ };
19507
+ }
19508
+ },
19509
+ getPluginMarketplaces: async (forceRefresh) => {
19510
+ try {
19511
+ if (this.provider && "getPluginMarketplaces" in this.provider && typeof this.provider.getPluginMarketplaces === "function") {
19512
+ const result = await this.provider.getPluginMarketplaces(forceRefresh);
19513
+ this.logger?.info("Got plugin marketplaces", { count: result?.length ?? 0 });
19514
+ return result;
19515
+ }
19516
+ this.logger?.warn("Provider does not support getPluginMarketplaces");
19517
+ return [];
19518
+ } catch (error) {
19519
+ this.logger?.error("Failed to get plugin marketplaces", error);
19520
+ return [];
19521
+ }
19522
+ },
19523
+ getMarketplacePlugins: async (marketplaceName, forceRefresh, searchText) => {
19524
+ try {
19525
+ if (this.provider && "getMarketplacePlugins" in this.provider && typeof this.provider.getMarketplacePlugins === "function") {
19526
+ const result = await this.provider.getMarketplacePlugins(marketplaceName, forceRefresh, searchText);
19527
+ this.logger?.info("Got marketplace plugins", {
19528
+ marketplaceName,
19529
+ count: result?.length ?? 0
19530
+ });
19531
+ return result;
19532
+ }
19533
+ this.logger?.warn("Provider does not support getMarketplacePlugins");
19534
+ return [];
19535
+ } catch (error) {
19536
+ this.logger?.error("Failed to get marketplace plugins", error);
19537
+ return [];
19538
+ }
19539
+ },
19540
+ getPluginDetail: async (pluginName, marketplaceName) => {
19541
+ try {
19542
+ if (this.provider && "getPluginDetail" in this.provider && typeof this.provider.getPluginDetail === "function") {
19543
+ const result = await this.provider.getPluginDetail(pluginName, marketplaceName);
19544
+ this.logger?.info("Got plugin detail", {
19545
+ pluginName,
19546
+ marketplaceName
19547
+ });
19548
+ return result;
19549
+ }
19550
+ this.logger?.warn("Provider does not support getPluginDetail");
19551
+ return null;
19552
+ } catch (error) {
19553
+ this.logger?.error("Failed to get plugin detail", error);
19554
+ return null;
19555
+ }
19556
+ },
19557
+ addPluginMarketplace: async (source, name) => {
19558
+ try {
19559
+ if (this.provider && "addPluginMarketplace" in this.provider && typeof this.provider.addPluginMarketplace === "function") {
19560
+ const result = await this.provider.addPluginMarketplace(source, name);
19561
+ this.logger?.info("Add plugin marketplace", {
19562
+ source,
19563
+ name,
19564
+ success: result.success
19565
+ });
19566
+ return result;
19567
+ }
19568
+ this.logger?.warn("Provider does not support addPluginMarketplace");
19569
+ return {
19570
+ success: false,
19571
+ error: "Provider does not support addPluginMarketplace"
19572
+ };
19573
+ } catch (error) {
19574
+ this.logger?.error("Failed to add plugin marketplace", error);
19575
+ return {
19576
+ success: false,
19577
+ error: error instanceof Error ? error.message : "Unknown error"
19578
+ };
19579
+ }
19580
+ },
19581
+ removePluginMarketplace: async (marketplaceName) => {
19582
+ try {
19583
+ if (this.provider && "removePluginMarketplace" in this.provider && typeof this.provider.removePluginMarketplace === "function") {
19584
+ const result = await this.provider.removePluginMarketplace(marketplaceName);
19585
+ this.logger?.info("Remove plugin marketplace", {
19586
+ marketplaceName,
19587
+ success: result.success
19588
+ });
19589
+ return result;
19590
+ }
19591
+ this.logger?.warn("Provider does not support removePluginMarketplace");
19592
+ return {
19593
+ success: false,
19594
+ error: "Provider does not support removePluginMarketplace"
19595
+ };
19596
+ } catch (error) {
19597
+ this.logger?.error("Failed to remove plugin marketplace", error);
19598
+ return {
19599
+ success: false,
19600
+ error: error instanceof Error ? error.message : "Unknown error"
19601
+ };
19602
+ }
19603
+ },
19604
+ refreshPluginMarketplace: async (marketplaceName) => {
18365
19605
  try {
18366
- if (this.provider && "installPlugins" in this.provider && typeof this.provider.installPlugins === "function") {
18367
- const result = await this.provider.installPlugins(pluginNames, marketplaceName, installScope, marketplaceSource);
18368
- this.logger?.info("Install plugins", {
18369
- pluginNames,
19606
+ if (this.provider && "refreshPluginMarketplace" in this.provider && typeof this.provider.refreshPluginMarketplace === "function") {
19607
+ const result = await this.provider.refreshPluginMarketplace(marketplaceName);
19608
+ this.logger?.info("Refresh plugin marketplace", {
18370
19609
  marketplaceName,
18371
19610
  success: result.success
18372
19611
  });
18373
19612
  return result;
18374
19613
  }
18375
- this.logger?.warn("Provider does not support installPlugins");
19614
+ this.logger?.warn("Provider does not support refreshPluginMarketplace");
18376
19615
  return {
18377
19616
  success: false,
18378
- error: "Provider does not support installPlugins"
19617
+ error: "Provider does not support refreshPluginMarketplace"
18379
19618
  };
18380
19619
  } catch (error) {
18381
- this.logger?.error("Failed to install plugins", error);
19620
+ this.logger?.error("Failed to refresh plugin marketplace", error);
18382
19621
  return {
18383
19622
  success: false,
18384
19623
  error: error instanceof Error ? error.message : "Unknown error"
18385
19624
  };
18386
19625
  }
18387
19626
  },
18388
- getSupportScenes: async () => {
19627
+ openFolderInNewWindow: async (folderPath) => {
19628
+ try {
19629
+ if (this.provider && "openFolderInNewWindow" in this.provider && typeof this.provider.openFolderInNewWindow === "function") {
19630
+ await this.provider.openFolderInNewWindow(folderPath);
19631
+ this.logger?.info("Opened folder in new window", { folderPath });
19632
+ } else {
19633
+ this.logger?.warn("Provider does not support openFolderInNewWindow");
19634
+ throw new Error("Provider does not support openFolderInNewWindow");
19635
+ }
19636
+ } catch (error) {
19637
+ this.logger?.error("Failed to open folder in new window", error);
19638
+ throw error;
19639
+ }
19640
+ },
19641
+ openFolder: async (folderPath) => {
18389
19642
  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 });
19643
+ if (this.provider && "openFolder" in this.provider && typeof this.provider.openFolder === "function") {
19644
+ const result = await this.provider.openFolder(folderPath);
19645
+ this.logger?.info("Opened folder in system file manager", { folderPath });
18393
19646
  return result;
19647
+ } else {
19648
+ this.logger?.warn("Provider does not support openFolder");
19649
+ throw new Error("Provider does not support openFolder");
18394
19650
  }
19651
+ } catch (error) {
19652
+ this.logger?.error("Failed to open folder", error);
19653
+ throw error;
19654
+ }
19655
+ },
19656
+ getSupportScenes: async (locale) => {
19657
+ try {
19658
+ if (this.provider && "getSupportScenes" in this.provider && typeof this.provider.getSupportScenes === "function") return await this.provider.getSupportScenes(locale);
18395
19659
  this.logger?.warn("Provider does not support getSupportScenes");
18396
19660
  return [];
18397
19661
  } catch (error) {
@@ -18399,23 +19663,193 @@ var AgentClient = class {
18399
19663
  return [];
18400
19664
  }
18401
19665
  },
18402
- getAvailableCommands: async (sessionId) => {
19666
+ getProductScenes: async (locale) => {
19667
+ try {
19668
+ if (this.provider?.getProductScenes) {
19669
+ const result = await this.provider.getProductScenes(locale);
19670
+ this.logger?.info("Got product scenes", { count: result?.length ?? 0 });
19671
+ return result;
19672
+ }
19673
+ this.logger?.warn("Provider does not support getProductScenes");
19674
+ return [];
19675
+ } catch (error) {
19676
+ this.logger?.error("Failed to get product scenes", error);
19677
+ return [];
19678
+ }
19679
+ },
19680
+ getAvailableCommands: async (params) => {
18403
19681
  try {
18404
19682
  if (this.provider && "getAvailableCommands" in this.provider && typeof this.provider.getAvailableCommands === "function") {
18405
- const result = await this.provider.getAvailableCommands(sessionId);
19683
+ const result = await this.provider.getAvailableCommands(params);
18406
19684
  this.logger?.info("Got available commands from provider", {
18407
- sessionId: sessionId ?? "(default)",
19685
+ sessionId: params?.sessionId ?? "(default)",
18408
19686
  count: result?.length ?? 0
18409
19687
  });
18410
19688
  return result;
18411
19689
  }
18412
- this.logger?.warn("Provider does not support getAvailableCommands", { sessionId });
19690
+ this.logger?.warn("Provider does not support getAvailableCommands", { params });
18413
19691
  return [];
18414
19692
  } catch (error) {
18415
19693
  this.logger?.error("Failed to get available commands", error);
18416
19694
  return [];
18417
19695
  }
18418
19696
  },
19697
+ reportTelemetry: async (eventName, payload) => {
19698
+ try {
19699
+ if (this.provider?.reportTelemetry) await this.provider.reportTelemetry(eventName, payload);
19700
+ else this.logger?.warn("Provider does not support reportTelemetry");
19701
+ } catch (error) {
19702
+ this.logger?.error("Failed to report telemetry", error);
19703
+ }
19704
+ },
19705
+ getProductConfiguration: async () => {
19706
+ try {
19707
+ if (this.provider?.getProductConfiguration) return await this.provider.getProductConfiguration();
19708
+ this.logger?.warn("Provider does not support getProductConfiguration");
19709
+ return {};
19710
+ } catch (error) {
19711
+ this.logger?.error("Failed to get product configuration", error);
19712
+ return {};
19713
+ }
19714
+ },
19715
+ getUserInfo: async () => {
19716
+ this.logger?.info("[AgentClient.sessions] getUserInfo() called");
19717
+ try {
19718
+ if (this.provider?.getUserInfo) {
19719
+ const result = await this.provider.getUserInfo();
19720
+ this.logger?.info("[AgentClient.sessions] getUserInfo() result:", JSON.stringify(result));
19721
+ return result;
19722
+ }
19723
+ this.logger?.warn("Provider does not support getUserInfo");
19724
+ return {};
19725
+ } catch (error) {
19726
+ this.logger?.error("Failed to get user info", error);
19727
+ return {};
19728
+ }
19729
+ },
19730
+ respondToSampling: async (sessionId, response) => {
19731
+ try {
19732
+ if (this.provider?.respondToSampling) {
19733
+ await this.provider.respondToSampling(sessionId, response);
19734
+ this.logger?.info("Responded to sampling request", {
19735
+ sessionId,
19736
+ requestId: response.id,
19737
+ approved: response.approved
19738
+ });
19739
+ } else this.logger?.warn("Provider does not support respondToSampling");
19740
+ } catch (error) {
19741
+ this.logger?.error("Failed to respond to sampling request", error);
19742
+ throw error;
19743
+ }
19744
+ },
19745
+ respondToRoots: async (sessionId, response) => {
19746
+ try {
19747
+ if (this.provider?.respondToRoots) {
19748
+ await this.provider.respondToRoots(sessionId, response);
19749
+ this.logger?.info("Responded to roots request", {
19750
+ sessionId,
19751
+ requestId: response.id,
19752
+ approved: response.approved
19753
+ });
19754
+ } else this.logger?.warn("Provider does not support respondToRoots");
19755
+ } catch (error) {
19756
+ this.logger?.error("Failed to respond to roots request", error);
19757
+ throw error;
19758
+ }
19759
+ },
19760
+ subscribeSamplingRequests: (serverName, callback) => {
19761
+ if (this.provider?.subscribeSamplingRequests) {
19762
+ this.logger?.info("Subscribing to sampling requests", { serverName });
19763
+ return this.provider.subscribeSamplingRequests(serverName, callback);
19764
+ }
19765
+ this.logger?.warn("Provider does not support subscribeSamplingRequests");
19766
+ return () => {};
19767
+ },
19768
+ subscribeRootsRequests: (serverName, callback) => {
19769
+ if (this.provider?.subscribeRootsRequests) {
19770
+ this.logger?.info("Subscribing to roots requests", { serverName });
19771
+ return this.provider.subscribeRootsRequests(serverName, callback);
19772
+ }
19773
+ this.logger?.warn("Provider does not support subscribeRootsRequests");
19774
+ return () => {};
19775
+ },
19776
+ getMcpServers: async () => {
19777
+ if (this.provider?.getMcpServers) {
19778
+ this.logger?.info("Getting MCP servers list");
19779
+ return this.provider.getMcpServers();
19780
+ }
19781
+ this.logger?.warn("Provider does not support getMcpServers");
19782
+ return [];
19783
+ },
19784
+ toggleMcpServer: async (serverName, enabled) => {
19785
+ if (this.provider?.toggleMcpServer) {
19786
+ this.logger?.info("Toggling MCP server", {
19787
+ serverName,
19788
+ enabled
19789
+ });
19790
+ await this.provider.toggleMcpServer(serverName, enabled);
19791
+ } else {
19792
+ this.logger?.warn("Provider does not support toggleMcpServer");
19793
+ throw new Error("toggleMcpServer not supported by provider");
19794
+ }
19795
+ },
19796
+ reconnectMcpServer: async (serverName, forceHttpCallback) => {
19797
+ if (this.provider?.reconnectMcpServer) {
19798
+ this.logger?.info("Reconnecting MCP server", {
19799
+ serverName,
19800
+ forceHttpCallback
19801
+ });
19802
+ await this.provider.reconnectMcpServer(serverName, forceHttpCallback);
19803
+ } else {
19804
+ this.logger?.warn("Provider does not support reconnectMcpServer");
19805
+ throw new Error("reconnectMcpServer not supported by provider");
19806
+ }
19807
+ },
19808
+ deleteMcpServer: async (serverName) => {
19809
+ if (this.provider?.deleteMcpServer) {
19810
+ this.logger?.info("Deleting MCP server", { serverName });
19811
+ await this.provider.deleteMcpServer(serverName);
19812
+ } else {
19813
+ this.logger?.warn("Provider does not support deleteMcpServer");
19814
+ throw new Error("deleteMcpServer not supported by provider");
19815
+ }
19816
+ },
19817
+ openMcpConfig: async () => {
19818
+ if (this.provider?.openMcpConfig) {
19819
+ this.logger?.info("Opening MCP config");
19820
+ await this.provider.openMcpConfig();
19821
+ } else {
19822
+ this.logger?.warn("Provider does not support openMcpConfig");
19823
+ throw new Error("openMcpConfig not supported by provider");
19824
+ }
19825
+ },
19826
+ getMcpConfigContent: async () => {
19827
+ if (this.provider?.getMcpConfigContent) {
19828
+ this.logger?.info("Getting MCP config content");
19829
+ return await this.provider.getMcpConfigContent();
19830
+ } else {
19831
+ this.logger?.warn("Provider does not support getMcpConfigContent");
19832
+ throw new Error("getMcpConfigContent not supported by provider");
19833
+ }
19834
+ },
19835
+ saveMcpConfigContent: async (content) => {
19836
+ if (this.provider?.saveMcpConfigContent) {
19837
+ this.logger?.info("Saving MCP config content");
19838
+ await this.provider.saveMcpConfigContent(content);
19839
+ } else {
19840
+ this.logger?.warn("Provider does not support saveMcpConfigContent");
19841
+ throw new Error("saveMcpConfigContent not supported by provider");
19842
+ }
19843
+ },
19844
+ clipboardReadText: async () => {
19845
+ if (this.provider?.clipboardReadText) {
19846
+ this.logger?.info("Reading clipboard text");
19847
+ return await this.provider.clipboardReadText();
19848
+ } else {
19849
+ this.logger?.warn("Provider does not support clipboardReadText");
19850
+ throw new Error("clipboardReadText not supported by provider");
19851
+ }
19852
+ },
18419
19853
  models: this.createModelsResource()
18420
19854
  };
18421
19855
  }
@@ -18641,10 +20075,6 @@ const oauthRepositoryService = new OAuthRepositoryService();
18641
20075
  * 判断当前账号是否是 SSO 账号
18642
20076
  * 通过 account.accountType === 'sso' 来判断,这种不行,因为未登录之前account 为空
18643
20077
  */
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
20078
  /**
18649
20079
  * 根据路径获取完整 URL
18650
20080
  * - SSO 账号需要跳转到对应的预发/生产域名
@@ -18652,16 +20082,7 @@ const isSSODomain = () => {
18652
20082
  * @param path 路径,如 '/login'、'/logout'、'/home' 等
18653
20083
  * @returns 完整的 URL 地址
18654
20084
  */
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
- };
20085
+ const getFullUrl = (path) => `${window.location.origin}${path}`;
18665
20086
  /** 获取当前域名的账号选择页面 URL */
18666
20087
  const getSelectAccountUrl = () => `${window.location.origin}/login/select`;
18667
20088
  /** localStorage 中存储选中账号 ID 的 key */
@@ -18694,16 +20115,34 @@ const getPackageName = (packageCode) => CommodityCodeText[packageCode] || "";
18694
20115
  * 注意:getAgents 和 getModels 方法已废弃并移除,
18695
20116
  * 请使用 IAgentAdapter 中的对应方法
18696
20117
  */
18697
- var BackendProvider = class {
20118
+ var BackendProvider = class BackendProvider {
18698
20119
  constructor(config) {
18699
20120
  httpService.setBaseURL(config.baseUrl);
18700
20121
  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);
20122
+ httpService.onUnauthorized(() => this.handleUnauthorized());
20123
+ }
20124
+ /**
20125
+ * 处理 401 未授权错误
20126
+ * 先尝试刷新 token,失败后再执行登出流程
20127
+ *
20128
+ * @throws 如果 token 刷新失败,抛出错误通知 HttpService 不要重试
20129
+ */
20130
+ async handleUnauthorized() {
20131
+ console.log("[BackendProvider] User unauthorized (401), attempting token refresh first");
20132
+ try {
20133
+ if (await this.refreshToken()) {
20134
+ console.log("[BackendProvider] Token refresh successful after 401, user still logged in");
20135
+ return;
20136
+ }
20137
+ throw new Error("Token refresh returned null");
20138
+ } catch (error) {
20139
+ console.error("[BackendProvider] Token refresh failed after 401:", error);
20140
+ console.log("[BackendProvider] Token refresh failed, triggering logout");
20141
+ this.logout().catch((logoutError) => {
20142
+ console.error("[BackendProvider] Logout failed in 401 handler:", logoutError);
18705
20143
  });
18706
- });
20144
+ throw error;
20145
+ }
18707
20146
  }
18708
20147
  /**
18709
20148
  * 获取当前账号信息
@@ -18967,10 +20406,11 @@ var BackendProvider = class {
18967
20406
  if (!time) return 0;
18968
20407
  return new Date(time).getTime();
18969
20408
  };
18970
- const dailyCredits = [CommodityCode.free, CommodityCode.freeMon];
20409
+ const dailyCredits = [CommodityCode.free];
18971
20410
  const planResources = resources.map((r) => {
18972
20411
  const isDaily = dailyCredits.includes(r.PackageCode);
18973
20412
  const endTime = isDaily ? r.CycleEndTime : r.DeductionEndTime;
20413
+ const refreshAt = parseTime(r.CycleEndTime) + 1e3;
18974
20414
  return {
18975
20415
  id: r.ResourceId,
18976
20416
  name: isDaily ? "plan.addonCredits" : getPackageName(r.PackageCode),
@@ -18980,7 +20420,7 @@ var BackendProvider = class {
18980
20420
  used: Math.max(0, Number(r.CycleCapacitySizePrecise) - Number(r.CycleCapacityRemainPrecise)) || 0,
18981
20421
  left: Number(r.CycleCapacityRemainPrecise) || 0,
18982
20422
  expireAt: parseTime(endTime),
18983
- refreshAt: isDaily ? void 0 : parseTime(r.CycleEndTime)
20423
+ refreshAt: isDaily ? void 0 : refreshAt
18984
20424
  };
18985
20425
  }).sort((a, b) => {
18986
20426
  const getPriority = (code) => {
@@ -18988,10 +20428,11 @@ var BackendProvider = class {
18988
20428
  CommodityCode.proMon,
18989
20429
  CommodityCode.proMonPlus,
18990
20430
  CommodityCode.proYear,
20431
+ CommodityCode.freeMon,
18991
20432
  CommodityCode.extra
18992
20433
  ].includes(code)) return 1;
18993
20434
  if ([CommodityCode.gift, CommodityCode.activity].includes(code)) return 2;
18994
- if ([CommodityCode.free, CommodityCode.freeMon].includes(code)) return 3;
20435
+ if ([CommodityCode.free].includes(code)) return 3;
18995
20436
  return 4;
18996
20437
  };
18997
20438
  return getPriority(a.packageCode) - getPriority(b.packageCode);
@@ -19116,34 +20557,65 @@ var BackendProvider = class {
19116
20557
  }
19117
20558
  /**
19118
20559
  * 登出账号
19119
- * Web 环境: 通过 iframe 访问登出 URL 清除 cookie
20560
+ *
20561
+ * 策略:
20562
+ * - IOA 企业:用 iframe 走 SSO/SAML SLO 登出链路(涉及跨域重定向),通过轮询 iframe URL 变化检测完成
20563
+ * - 非 IOA 企业:直接用 httpService 请求 /console/logout,速度快
19120
20564
  */
19121
20565
  async logout() {
19122
- const url = `${httpService.getAxiosInstance().defaults.baseURL}/console/logout`;
20566
+ const account = accountService.getAccount();
20567
+ if (account?.enterpriseId && ["esoikz80kd8g", "etahzsqej0n4"].includes(account.enterpriseId)) await this.logoutViaIframe();
20568
+ else await this.logoutViaHttp();
20569
+ localStorage.removeItem(SELECTED_ACCOUNT_KEY);
20570
+ accountService.clearAccount();
20571
+ }
20572
+ /**
20573
+ * IOA 企业登出:通过 iframe 走 SSO/SAML SLO 登出链路
20574
+ * 轮询 iframe URL 变化检测完成,兜底超时 5 秒
20575
+ */
20576
+ async logoutViaIframe() {
20577
+ const logoutUrl = `${httpService.getAxiosInstance().defaults.baseURL}/console/logout`;
19123
20578
  try {
19124
20579
  await new Promise((resolve) => {
19125
20580
  const iframe = document.createElement("iframe");
19126
20581
  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 = () => {
20582
+ iframe.src = logoutUrl;
20583
+ let pollTimer;
20584
+ let settled = false;
20585
+ const done = () => {
20586
+ if (settled) return;
20587
+ settled = true;
20588
+ clearInterval(pollTimer);
19133
20589
  clearTimeout(timeout);
19134
20590
  if (iframe.parentNode) iframe.parentNode.removeChild(iframe);
19135
- };
19136
- iframe.onerror = () => {
19137
- cleanup();
19138
20591
  resolve();
19139
20592
  };
20593
+ let wasRedirecting = false;
20594
+ pollTimer = setInterval(() => {
20595
+ try {
20596
+ const href = iframe.contentWindow?.location?.href;
20597
+ if (wasRedirecting && href) done();
20598
+ } catch {
20599
+ wasRedirecting = true;
20600
+ }
20601
+ }, 100);
20602
+ const timeout = setTimeout(done, 5e3);
20603
+ iframe.onerror = done;
19140
20604
  document.body.appendChild(iframe);
19141
20605
  });
19142
20606
  } catch (error) {
19143
- console.error("[BackendProvider] logout failed:", error);
20607
+ console.error("[BackendProvider] logout via iframe failed:", error);
20608
+ }
20609
+ }
20610
+ /**
20611
+ * 非 IOA 企业登出:直接 HTTP 请求 /console/logout
20612
+ */
20613
+ async logoutViaHttp() {
20614
+ try {
20615
+ await httpService.get("/console/logout");
20616
+ } catch (error) {
20617
+ console.error("[BackendProvider] logout via http failed:", error);
19144
20618
  }
19145
- localStorage.removeItem(SELECTED_ACCOUNT_KEY);
19146
- accountService.clearAccount();
19147
20619
  }
19148
20620
  /**
19149
20621
  * 批量切换插件状态
@@ -19221,6 +20693,132 @@ var BackendProvider = class {
19221
20693
  async getRepositories(connector, page = 0, perPage = 100) {
19222
20694
  return oauthRepositoryService.getRepositories(connector, page, perPage);
19223
20695
  }
20696
+ /**
20697
+ * 保存待发送的输入内容到后端
20698
+ * API 端点: POST /api/v1/code-id
20699
+ */
20700
+ async savePendingInput(code) {
20701
+ try {
20702
+ const result = await httpService.post("/api/v1/code-id", { code });
20703
+ return result?.codeId || result?.data?.codeId || null;
20704
+ } catch (e) {
20705
+ console.warn("[BackendProvider] savePendingInput failed:", e);
20706
+ return null;
20707
+ }
20708
+ }
20709
+ /**
20710
+ * 从后端加载待发送的输入内容
20711
+ * API 端点: GET /api/v1/code?id=xxx
20712
+ */
20713
+ async loadPendingInput(codeId) {
20714
+ try {
20715
+ const result = await httpService.get(`/api/v1/code?id=${encodeURIComponent(codeId)}`);
20716
+ return result?.code || result?.data?.code || null;
20717
+ } catch (e) {
20718
+ console.warn("[BackendProvider] loadPendingInput failed:", e);
20719
+ return null;
20720
+ }
20721
+ }
20722
+ /**
20723
+ * 获取每日签到状态
20724
+ * API 端点: POST /billing/meter/checkin-status
20725
+ */
20726
+ async getCheckinStatus() {
20727
+ try {
20728
+ const result = await httpService.post("/billing/meter/checkin-status", {});
20729
+ if (result?.code === 0 && result?.data) return result.data;
20730
+ return null;
20731
+ } catch (error) {
20732
+ console.error("[BackendProvider] getCheckinStatus failed:", error);
20733
+ return null;
20734
+ }
20735
+ }
20736
+ /**
20737
+ * 执行每日签到
20738
+ * API 端点: POST /billing/meter/daily-checkin
20739
+ */
20740
+ async claimDailyCheckin() {
20741
+ const result = await httpService.post("/billing/meter/daily-checkin", {});
20742
+ if (result?.code === 0 && result?.data) return result.data;
20743
+ throw new Error(result?.msg || "Checkin failed");
20744
+ }
20745
+ static {
20746
+ this.SKILLHUB_BASE_URL = "https://lightmake.site";
20747
+ }
20748
+ static {
20749
+ this.SKILLHUB_FETCH_TIMEOUT = 1e4;
20750
+ }
20751
+ async skillHubFetch(url, init) {
20752
+ const controller = new AbortController();
20753
+ const timer = setTimeout(() => controller.abort(), BackendProvider.SKILLHUB_FETCH_TIMEOUT);
20754
+ try {
20755
+ return await fetch(url, {
20756
+ ...init,
20757
+ signal: controller.signal
20758
+ });
20759
+ } finally {
20760
+ clearTimeout(timer);
20761
+ }
20762
+ }
20763
+ async getSkillHubList(params = {}) {
20764
+ const qs = new URLSearchParams();
20765
+ if (params.page) qs.set("page", String(params.page));
20766
+ if (params.pageSize) qs.set("pageSize", String(params.pageSize));
20767
+ if (params.sortBy) qs.set("sortBy", params.sortBy);
20768
+ if (params.order) qs.set("order", params.order);
20769
+ if (params.keyword) qs.set("keyword", params.keyword);
20770
+ if (params.category) qs.set("category", params.category);
20771
+ const res = await this.skillHubFetch(`${BackendProvider.SKILLHUB_BASE_URL}/api/skills?${qs.toString()}`);
20772
+ if (!res.ok) throw new Error(`SkillHub list: ${res.status}`);
20773
+ return res.json();
20774
+ }
20775
+ async getSkillHubCategories() {
20776
+ const res = await this.skillHubFetch(`${BackendProvider.SKILLHUB_BASE_URL}/api/v1/categories`);
20777
+ if (!res.ok) throw new Error(`SkillHub categories: ${res.status}`);
20778
+ return res.json();
20779
+ }
20780
+ async getSkillHubSearch(q, limit = 20) {
20781
+ const qs = new URLSearchParams({
20782
+ q,
20783
+ limit: String(limit)
20784
+ });
20785
+ const res = await this.skillHubFetch(`${BackendProvider.SKILLHUB_BASE_URL}/api/v1/search?${qs.toString()}`);
20786
+ if (!res.ok) throw new Error(`SkillHub search: ${res.status}`);
20787
+ return res.json();
20788
+ }
20789
+ async getSkillHubDetail(slug) {
20790
+ const res = await this.skillHubFetch(`${BackendProvider.SKILLHUB_BASE_URL}/api/v1/skills/${encodeURIComponent(slug)}`);
20791
+ if (!res.ok) throw new Error(`SkillHub detail: ${res.status}`);
20792
+ return res.json();
20793
+ }
20794
+ async getSkillHubExists(slugs) {
20795
+ const res = await this.skillHubFetch(`${BackendProvider.SKILLHUB_BASE_URL}/api/v1/skills/exists`, {
20796
+ method: "POST",
20797
+ headers: { "Content-Type": "application/json" },
20798
+ body: JSON.stringify({ slugs })
20799
+ });
20800
+ if (!res.ok) throw new Error(`SkillHub exists: ${res.status}`);
20801
+ return res.json();
20802
+ }
20803
+ async reportSkillHubStats(slug, inc) {
20804
+ try {
20805
+ await this.skillHubFetch(`${BackendProvider.SKILLHUB_BASE_URL}/api/v1/skills/${encodeURIComponent(slug)}/stats/inc`, {
20806
+ method: "POST",
20807
+ headers: { "Content-Type": "application/json" },
20808
+ body: JSON.stringify(inc)
20809
+ });
20810
+ } catch {}
20811
+ }
20812
+ async installSkillHubSkill(_slug, _version, _name) {
20813
+ return {
20814
+ success: false,
20815
+ skillName: _slug,
20816
+ errorMessage: "SkillHub install requires IDE mode (no IPC channel available)"
20817
+ };
20818
+ }
20819
+ async getSkillHubInstalledMetas() {
20820
+ return [];
20821
+ }
19224
20822
  };
19225
20823
  /**
19226
20824
  * 创建 BackendProvider 实例
@@ -19259,10 +20857,21 @@ const BACKEND_REQUEST_TYPES = {
19259
20857
  REVOKE_ALL: "backend:revoke-all",
19260
20858
  GET_FILE: "backend:get-file",
19261
20859
  RELOAD_WINDOW: "backend:reload-window",
20860
+ SAVE_LOCALE: "backend:save-locale",
19262
20861
  CLOSE_AGENT_MANAGER: "backend:close-agent-manager",
19263
20862
  OPEN_EXTERNAL: "backend:open-external",
19264
20863
  BATCH_TOGGLE_PLUGINS: "backend:batch-toggle-plugins",
19265
- GET_SUPPORT_SCENES: "backend:get-support-scenes"
20864
+ GET_SUPPORT_SCENES: "backend:get-support-scenes",
20865
+ GET_ACCOUNT_USAGE: "backend:get-account-usage",
20866
+ GET_CHECKIN_STATUS: "backend:get-checkin-status",
20867
+ CLAIM_DAILY_CHECKIN: "backend:claim-daily-checkin",
20868
+ SKILLHUB_LIST: "backend:skillhub-list",
20869
+ SKILLHUB_CATEGORIES: "backend:skillhub-categories",
20870
+ SKILLHUB_SEARCH: "backend:skillhub-search",
20871
+ SKILLHUB_DETAIL: "backend:skillhub-detail",
20872
+ SKILLHUB_DOWNLOAD_URL: "backend:skillhub-download-url",
20873
+ SKILLHUB_EXISTS: "backend:skillhub-exists",
20874
+ SKILLHUB_REPORT_STATS: "backend:skillhub-report-stats"
19266
20875
  };
19267
20876
  /**
19268
20877
  * 生成唯一请求 ID
@@ -19309,12 +20918,14 @@ var IPCBackendProvider = class {
19309
20918
  */
19310
20919
  async getAccount() {
19311
20920
  this.log("Getting account via IPC");
20921
+ const startTime = performance.now();
19312
20922
  try {
19313
20923
  const account = await this.sendBackendRequest(BACKEND_REQUEST_TYPES.GET_ACCOUNT);
20924
+ this.log(`getAccount IPC completed in ${(performance.now() - startTime).toFixed(0)}ms`);
19314
20925
  accountService.setAccount(account);
19315
20926
  return account;
19316
20927
  } catch (error) {
19317
- this.log("Get account failed:", error);
20928
+ this.log(`getAccount IPC failed after ${(performance.now() - startTime).toFixed(0)}ms:`, error);
19318
20929
  accountService.setAccount(null);
19319
20930
  return null;
19320
20931
  }
@@ -19543,6 +21154,20 @@ var IPCBackendProvider = class {
19543
21154
  }
19544
21155
  }
19545
21156
  /**
21157
+ * Save locale to argv.json without restarting the app.
21158
+ * The change takes effect on next manual restart.
21159
+ * @param params locale to save
21160
+ */
21161
+ async saveLocale(params) {
21162
+ this.log("Saving locale to argv.json via IPC", params);
21163
+ try {
21164
+ await this.sendBackendRequest(BACKEND_REQUEST_TYPES.SAVE_LOCALE, params);
21165
+ } catch (error) {
21166
+ this.log("Save locale request failed:", error);
21167
+ throw error;
21168
+ }
21169
+ }
21170
+ /**
19546
21171
  * 关闭 Agent Manager 面板
19547
21172
  * IDE 环境: 通过 IPC 通知 IDE 关闭 Agent Manager(用于返回 IDE)
19548
21173
  */
@@ -19603,6 +21228,174 @@ var IPCBackendProvider = class {
19603
21228
  }
19604
21229
  }
19605
21230
  /**
21231
+ * 获取账号用量信息(积分/Credits)
21232
+ * IDE 环境: 通过 IPC 实时获取用量信息,每次打开菜单时调用
21233
+ *
21234
+ * 调用链:
21235
+ * 1. agent-ui: IPCBackendProvider.getAccountUsage()
21236
+ * 2. Agent Manager renderer: BackendService.getAccountUsage()
21237
+ * 3. Main Process: codebuddy:getAccountUsage IPC handler
21238
+ * 4. 返回 { usageLeft, usageTotal, editionType, refreshAt } 等字段
21239
+ */
21240
+ async getAccountUsage() {
21241
+ this.log("Getting account usage via IPC");
21242
+ try {
21243
+ return await this.sendBackendRequest(BACKEND_REQUEST_TYPES.GET_ACCOUNT_USAGE);
21244
+ } catch (error) {
21245
+ this.log("Get account usage failed:", error);
21246
+ return null;
21247
+ }
21248
+ }
21249
+ /**
21250
+ * 获取每日签到状态
21251
+ * IDE 环境: 通过 IPC 获取签到状态
21252
+ */
21253
+ async getCheckinStatus() {
21254
+ this.log("Getting checkin status via IPC");
21255
+ try {
21256
+ return await this.sendBackendRequest(BACKEND_REQUEST_TYPES.GET_CHECKIN_STATUS);
21257
+ } catch (error) {
21258
+ this.log("Get checkin status failed:", error);
21259
+ return null;
21260
+ }
21261
+ }
21262
+ /**
21263
+ * 执行每日签到
21264
+ * IDE 环境: 通过 IPC 执行签到
21265
+ */
21266
+ async claimDailyCheckin() {
21267
+ this.log("Claiming daily checkin via IPC");
21268
+ try {
21269
+ return await this.sendBackendRequest(BACKEND_REQUEST_TYPES.CLAIM_DAILY_CHECKIN);
21270
+ } catch (error) {
21271
+ this.log("Claim daily checkin failed:", error);
21272
+ throw error;
21273
+ }
21274
+ }
21275
+ /**
21276
+ * 获取 SkillHub 技能列表
21277
+ * IDE 环境: 通过 IPC 获取技能列表
21278
+ */
21279
+ async getSkillHubList(params) {
21280
+ this.log("Getting SkillHub list via IPC", params);
21281
+ try {
21282
+ return await this.sendBackendRequest(BACKEND_REQUEST_TYPES.SKILLHUB_LIST, params);
21283
+ } catch (error) {
21284
+ this.log("Get SkillHub list failed:", error);
21285
+ throw error;
21286
+ }
21287
+ }
21288
+ /**
21289
+ * 获取 SkillHub 分类列表
21290
+ * IDE 环境: 通过 IPC 获取分类列表
21291
+ */
21292
+ async getSkillHubCategories() {
21293
+ this.log("Getting SkillHub categories via IPC");
21294
+ try {
21295
+ return await this.sendBackendRequest(BACKEND_REQUEST_TYPES.SKILLHUB_CATEGORIES);
21296
+ } catch (error) {
21297
+ this.log("Get SkillHub categories failed:", error);
21298
+ throw error;
21299
+ }
21300
+ }
21301
+ /**
21302
+ * 搜索 SkillHub 技能
21303
+ * IDE 环境: 通过 IPC 搜索技能
21304
+ */
21305
+ async getSkillHubSearch(q, limit = 20) {
21306
+ this.log("Searching SkillHub via IPC", {
21307
+ q,
21308
+ limit
21309
+ });
21310
+ try {
21311
+ return await this.sendBackendRequest(BACKEND_REQUEST_TYPES.SKILLHUB_SEARCH, {
21312
+ q,
21313
+ limit
21314
+ });
21315
+ } catch (error) {
21316
+ this.log("SkillHub search failed:", error);
21317
+ throw error;
21318
+ }
21319
+ }
21320
+ /**
21321
+ * 获取 SkillHub 技能详情
21322
+ * IDE 环境: 通过 IPC 获取技能详情
21323
+ */
21324
+ async getSkillHubDetail(slug) {
21325
+ this.log("Getting SkillHub detail via IPC", { slug });
21326
+ try {
21327
+ return await this.sendBackendRequest(BACKEND_REQUEST_TYPES.SKILLHUB_DETAIL, { slug });
21328
+ } catch (error) {
21329
+ this.log("Get SkillHub detail failed:", error);
21330
+ throw error;
21331
+ }
21332
+ }
21333
+ /**
21334
+ * 批量检查 SkillHub 技能是否存在
21335
+ * IDE 环境: 通过 IPC 检查技能是否存在
21336
+ */
21337
+ async getSkillHubExists(slugs) {
21338
+ this.log("Checking SkillHub exists via IPC", { slugs });
21339
+ try {
21340
+ return await this.sendBackendRequest(BACKEND_REQUEST_TYPES.SKILLHUB_EXISTS, { slugs });
21341
+ } catch (error) {
21342
+ this.log("SkillHub exists check failed:", error);
21343
+ throw error;
21344
+ }
21345
+ }
21346
+ /**
21347
+ * 上报 SkillHub 技能统计
21348
+ * IDE 环境: 通过 IPC 上报统计
21349
+ */
21350
+ async reportSkillHubStats(slug, inc) {
21351
+ this.log("Reporting SkillHub stats via IPC", {
21352
+ slug,
21353
+ inc
21354
+ });
21355
+ try {
21356
+ await this.sendBackendRequest(BACKEND_REQUEST_TYPES.SKILLHUB_REPORT_STATS, {
21357
+ slug,
21358
+ inc
21359
+ });
21360
+ } catch (error) {
21361
+ this.log("Report SkillHub stats failed:", error);
21362
+ }
21363
+ }
21364
+ /**
21365
+ * 安装 SkillHub 技能
21366
+ * IDE 环境: 通过 IPC 安装技能(下载 zip → 解压到本地)
21367
+ */
21368
+ async installSkillHubSkill(slug, version, name) {
21369
+ this.log("Installing SkillHub skill via IPC", {
21370
+ slug,
21371
+ version,
21372
+ name
21373
+ });
21374
+ try {
21375
+ return await this.sendBackendRequest("backend:skillhub-install", {
21376
+ slug,
21377
+ version,
21378
+ name
21379
+ });
21380
+ } catch (error) {
21381
+ this.log("Install SkillHub skill failed:", error);
21382
+ throw error;
21383
+ }
21384
+ }
21385
+ /**
21386
+ * 获取本地已安装的 SkillHub 技能元信息
21387
+ * IDE 环境: 通过 IPC 获取元信息
21388
+ */
21389
+ async getSkillHubInstalledMetas() {
21390
+ this.log("Getting SkillHub installed metas via IPC");
21391
+ try {
21392
+ return await this.sendBackendRequest("backend:skillhub-installed-metas");
21393
+ } catch (error) {
21394
+ this.log("Get SkillHub installed metas failed:", error);
21395
+ return [];
21396
+ }
21397
+ }
21398
+ /**
19606
21399
  * 调试日志
19607
21400
  */
19608
21401
  log(...args) {
@@ -19622,10 +21415,11 @@ exports.AgentClient = AgentClient;
19622
21415
  exports.BackendProvider = BackendProvider;
19623
21416
  exports.CloudAgentConnection = CloudAgentConnection;
19624
21417
  exports.CloudAgentProvider = CloudAgentProvider;
19625
- exports.E2BFilesystem = E2BFilesystem;
21418
+ exports.E2BFilesystem = require_e2b_filesystem.E2BFilesystem;
19626
21419
  exports.HttpService = HttpService;
19627
21420
  exports.IPCBackendProvider = IPCBackendProvider;
19628
21421
  exports.SessionManager = SessionManager;
21422
+ exports.__toESM = __toESM;
19629
21423
  exports.createBackendProvider = createBackendProvider;
19630
21424
  exports.createIPCBackendProvider = createIPCBackendProvider;
19631
21425
  exports.httpService = httpService;