@moonshot-ai/kimi-code 0.20.2 → 0.20.3

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.
Files changed (67) hide show
  1. package/dist/main.mjs +1144 -1052
  2. package/dist-web/assets/{CodeBlockNode-Cj5GCBwy.js → CodeBlockNode-QzsUDFhj.js} +1 -1
  3. package/dist-web/assets/{CodeBlockShell.vue_vue_type_style_index_0_lang-BZQYvYGg.js → CodeBlockShell.vue_vue_type_style_index_0_lang-COQWnG7I.js} +1 -1
  4. package/dist-web/assets/{Tooltip-FXn3ewBz.js → Tooltip-DjdYJu5x.js} +1 -1
  5. package/dist-web/assets/{arc---yONsFG.js → arc-BgPs0rMd.js} +1 -1
  6. package/dist-web/assets/{architectureDiagram-3BPJPVTR-Cu5NFSbj.js → architectureDiagram-3BPJPVTR-D0xfzSKA.js} +1 -1
  7. package/dist-web/assets/{blockDiagram-GPEHLZMM-eAkllecr.js → blockDiagram-GPEHLZMM-jtPOGuGl.js} +1 -1
  8. package/dist-web/assets/{c4Diagram-AAUBKEIU-BcJyf2yX.js → c4Diagram-AAUBKEIU-BPIjsoUA.js} +1 -1
  9. package/dist-web/assets/channel-DnBCccMg.js +1 -0
  10. package/dist-web/assets/{chunk-2J33WTMH-DzpuDCg4.js → chunk-2J33WTMH-ChbTHkcK.js} +1 -1
  11. package/dist-web/assets/{chunk-4BX2VUAB-DPF55Xbc.js → chunk-4BX2VUAB-br1aQrtt.js} +1 -1
  12. package/dist-web/assets/{chunk-55IACEB6-Ct2k4oQF.js → chunk-55IACEB6-CoLSy_-M.js} +1 -1
  13. package/dist-web/assets/{chunk-727SXJPM-DcWnL_ZJ.js → chunk-727SXJPM-Ch73eH6y.js} +1 -1
  14. package/dist-web/assets/{chunk-AQP2D5EJ-2N1ZTMho.js → chunk-AQP2D5EJ-7Y0GIirZ.js} +1 -1
  15. package/dist-web/assets/{chunk-FMBD7UC4-jNBVe-u1.js → chunk-FMBD7UC4-D7IRCdHF.js} +1 -1
  16. package/dist-web/assets/{chunk-ND2GUHAM-BTBgmjVQ.js → chunk-ND2GUHAM-WfKpgeWa.js} +1 -1
  17. package/dist-web/assets/{chunk-QZHKN3VN-xUCxw3pg.js → chunk-QZHKN3VN-BgQBqGri.js} +1 -1
  18. package/dist-web/assets/classDiagram-4FO5ZUOK-DezksBKS.js +1 -0
  19. package/dist-web/assets/classDiagram-v2-Q7XG4LA2-DezksBKS.js +1 -0
  20. package/dist-web/assets/{cose-bilkent-S5V4N54A-ByEZXDA-.js → cose-bilkent-S5V4N54A-Du7Q4b9R.js} +1 -1
  21. package/dist-web/assets/{dagre-BM42HDAG-BSfstE2-.js → dagre-BM42HDAG-BBLoya79.js} +1 -1
  22. package/dist-web/assets/{diagram-2AECGRRQ-CpI86-tI.js → diagram-2AECGRRQ-kByHrOvZ.js} +1 -1
  23. package/dist-web/assets/{diagram-5GNKFQAL-B4WYOJbp.js → diagram-5GNKFQAL-Dnkgbduh.js} +1 -1
  24. package/dist-web/assets/{diagram-KO2AKTUF-dmm87H0J.js → diagram-KO2AKTUF-CKfrJMO5.js} +1 -1
  25. package/dist-web/assets/{diagram-LMA3HP47-CAFHWRvJ.js → diagram-LMA3HP47-D3GoTx0o.js} +1 -1
  26. package/dist-web/assets/{diagram-OG6HWLK6-CvbELbqm.js → diagram-OG6HWLK6-B057HNTB.js} +1 -1
  27. package/dist-web/assets/{erDiagram-TEJ5UH35-BATGAYdA.js → erDiagram-TEJ5UH35-CMFH1-0F.js} +1 -1
  28. package/dist-web/assets/{flowDiagram-I6XJVG4X-BjHCXPMa.js → flowDiagram-I6XJVG4X-Ue7D_If3.js} +1 -1
  29. package/dist-web/assets/{ganttDiagram-6RSMTGT7-DyP4c3YT.js → ganttDiagram-6RSMTGT7-C3vvEQsr.js} +1 -1
  30. package/dist-web/assets/{gitGraphDiagram-PVQCEYII-NzukZ15I.js → gitGraphDiagram-PVQCEYII-D-L62M3k.js} +1 -1
  31. package/dist-web/assets/index-BOozFshs.js +284 -0
  32. package/dist-web/assets/{index-D4Er4P8I.js → index-DRCzCVsJ.js} +1 -1
  33. package/dist-web/assets/{index-Cfg9noDi.js → index-YYCI79IV.js} +2 -2
  34. package/dist-web/assets/{index-BYnLiw5r.css → index-gP3qbaq1.css} +1 -1
  35. package/dist-web/assets/{index10-C4yIRdle.js → index10-C0e1uOHF.js} +1 -1
  36. package/dist-web/assets/{index11-CqNiMTbJ.js → index11-qzoItZ5X.js} +2 -2
  37. package/dist-web/assets/{index5-DKdkj0GC.js → index5-BD3g_HrT.js} +1 -1
  38. package/dist-web/assets/{index6-DsK3MiZT.js → index6-BsyLzjzN.js} +1 -1
  39. package/dist-web/assets/{index7-DHshPD9x.js → index7-BU9c3C-0.js} +1 -1
  40. package/dist-web/assets/{index8-CeUCBmKU.js → index8-DC4X3Xlc.js} +2 -2
  41. package/dist-web/assets/{infoDiagram-5YYISTIA-6n_F_-MA.js → infoDiagram-5YYISTIA-DuKrZwyg.js} +1 -1
  42. package/dist-web/assets/{ishikawaDiagram-YF4QCWOH-CoaeNeqj.js → ishikawaDiagram-YF4QCWOH-DvYYK586.js} +1 -1
  43. package/dist-web/assets/{journeyDiagram-JHISSGLW-Bi-m1_1y.js → journeyDiagram-JHISSGLW-CijMU22u.js} +1 -1
  44. package/dist-web/assets/{kanban-definition-UN3LZRKU-DHxtNMaD.js → kanban-definition-UN3LZRKU-BmaUhICc.js} +1 -1
  45. package/dist-web/assets/{linear-CgHyf5UH.js → linear-C5DmXyYK.js} +1 -1
  46. package/dist-web/assets/{mermaid.core-CtXm064v.js → mermaid.core-CxStNiKR.js} +4 -4
  47. package/dist-web/assets/{mindmap-definition-RKZ34NQL-ClpCUmIA.js → mindmap-definition-RKZ34NQL-CH1ykt4a.js} +1 -1
  48. package/dist-web/assets/{pieDiagram-4H26LBE5-DvYtw1Bp.js → pieDiagram-4H26LBE5-D812Mhsu.js} +1 -1
  49. package/dist-web/assets/{quadrantDiagram-W4KKPZXB-Dle7c6-0.js → quadrantDiagram-W4KKPZXB-WyDSXdZ7.js} +1 -1
  50. package/dist-web/assets/{requirementDiagram-4Y6WPE33--X5AnAhp.js → requirementDiagram-4Y6WPE33-CzaQOU4P.js} +1 -1
  51. package/dist-web/assets/{sankeyDiagram-5OEKKPKP-BUszdT9f.js → sankeyDiagram-5OEKKPKP-D2mgS_7C.js} +1 -1
  52. package/dist-web/assets/{sequenceDiagram-3UESZ5HK-CDwqGrfV.js → sequenceDiagram-3UESZ5HK-CuoLev25.js} +1 -1
  53. package/dist-web/assets/{stateDiagram-AJRCARHV-Kmd6YXse.js → stateDiagram-AJRCARHV-BoTsuaL9.js} +1 -1
  54. package/dist-web/assets/stateDiagram-v2-BHNVJYJU-8LYkXLp8.js +1 -0
  55. package/dist-web/assets/{timeline-definition-PNZ67QCA-o-RAswWS.js → timeline-definition-PNZ67QCA-DkLWuglL.js} +1 -1
  56. package/dist-web/assets/{vennDiagram-CIIHVFJN-DljQ_s6w.js → vennDiagram-CIIHVFJN-DYjvU6dg.js} +1 -1
  57. package/dist-web/assets/{vue.runtime.esm-bundler-BP7sjueK.js → vue.runtime.esm-bundler-C_eIrEdV.js} +1 -1
  58. package/dist-web/assets/{wardley-L42UT6IY-CW9wuVhK.js → wardley-L42UT6IY-DSIStv05.js} +1 -1
  59. package/dist-web/assets/{wardleyDiagram-YWT4CUSO-Bh0wtRMV.js → wardleyDiagram-YWT4CUSO-DSPJWT6D.js} +1 -1
  60. package/dist-web/assets/{xychartDiagram-2RQKCTM6-BAjJ0sMH.js → xychartDiagram-2RQKCTM6-C0OPS_b1.js} +1 -1
  61. package/dist-web/index.html +3 -3
  62. package/package.json +3 -3
  63. package/dist-web/assets/channel-BTxFVrej.js +0 -1
  64. package/dist-web/assets/classDiagram-4FO5ZUOK-B47dzfoS.js +0 -1
  65. package/dist-web/assets/classDiagram-v2-Q7XG4LA2-B47dzfoS.js +0 -1
  66. package/dist-web/assets/index-CCjot4qV.js +0 -284
  67. package/dist-web/assets/stateDiagram-v2-BHNVJYJU-CvgWdsVg.js +0 -1
package/dist/main.mjs CHANGED
@@ -54411,7 +54411,7 @@ function toKimiErrorPayload(error) {
54411
54411
  const code = error.statusCode === 429 ? ErrorCodes.PROVIDER_RATE_LIMIT : error.statusCode === 401 ? ErrorCodes.PROVIDER_AUTH_ERROR : ErrorCodes.PROVIDER_API_ERROR;
54412
54412
  return {
54413
54413
  code,
54414
- message: error.message,
54414
+ message: sanitizeStatusErrorMessage(error.message),
54415
54415
  name: error.name,
54416
54416
  details: {
54417
54417
  statusCode: error.statusCode,
@@ -54455,6 +54455,19 @@ function toKimiErrorPayload(error) {
54455
54455
  };
54456
54456
  }
54457
54457
  /**
54458
+ * Provider status errors occasionally carry an HTML body instead of a
54459
+ * structured message (for example, nginx returning
54460
+ * "413 <html><head><title>413 Request Entity Too Large</title>...</html>").
54461
+ * Extract the `<title>` when present so the wire message is human readable,
54462
+ * and strip carriage returns so the text renders cleanly in terminals — a
54463
+ * trailing `\r` combined with line-end padding would otherwise overwrite
54464
+ * the whole line. The original HTML remains available in logs and `details`.
54465
+ */
54466
+ function sanitizeStatusErrorMessage(message) {
54467
+ const extracted = /<title[^>]*>([\s\S]*?)<\/title>/i.exec(message)?.[1]?.trim();
54468
+ return (extracted !== void 0 && extracted.length > 0 ? extracted : message).replaceAll("\r", "");
54469
+ }
54470
+ /**
54458
54471
  * Rehydrate a KimiErrorPayload into a KimiError. Used by SDK boundary code
54459
54472
  * receiving errors over RPC to re-surface them with a real class so
54460
54473
  * in-process consumers can still use `instanceof`.
@@ -60771,6 +60784,12 @@ const BackgroundConfigSchema = object({
60771
60784
  killGracePeriodMs: number$1().int().min(0).optional(),
60772
60785
  printWaitCeilingS: number$1().int().min(1).optional()
60773
60786
  });
60787
+ const ModelCatalogConfigSchema = object({
60788
+ /** Interval (ms) between automatic provider-model refreshes. `0` disables. */
60789
+ refreshIntervalMs: number$1().int().min(0).optional(),
60790
+ /** Refresh once shortly after the daemon starts. */
60791
+ refreshOnStart: boolean$1().optional()
60792
+ });
60774
60793
  const ExperimentalConfigSchema = record(string(), boolean$1());
60775
60794
  const HookDefSchema = object({
60776
60795
  event: _enum(HOOK_EVENT_TYPES),
@@ -60851,6 +60870,7 @@ const KimiConfigSchema = object({
60851
60870
  extraSkillDirs: array(string()).optional(),
60852
60871
  loopControl: LoopControlSchema.optional(),
60853
60872
  background: BackgroundConfigSchema.optional(),
60873
+ modelCatalog: ModelCatalogConfigSchema.optional(),
60854
60874
  experimental: ExperimentalConfigSchema.optional(),
60855
60875
  telemetry: boolean$1().optional(),
60856
60876
  raw: record(string(), unknown()).optional()
@@ -60861,6 +60881,7 @@ const ThinkingConfigPatchSchema = ThinkingConfigSchema.partial();
60861
60881
  const PermissionConfigPatchSchema = PermissionConfigSchema.partial();
60862
60882
  const LoopControlPatchSchema = LoopControlSchema.partial();
60863
60883
  const BackgroundConfigPatchSchema = BackgroundConfigSchema.partial();
60884
+ const ModelCatalogConfigPatchSchema = ModelCatalogConfigSchema.partial();
60864
60885
  const ExperimentalConfigPatchSchema = ExperimentalConfigSchema;
60865
60886
  const MoonshotServiceConfigPatchSchema = MoonshotServiceConfigSchema.partial();
60866
60887
  const ServicesConfigPatchSchema = object({
@@ -60885,6 +60906,7 @@ const KimiConfigPatchSchema = object({
60885
60906
  extraSkillDirs: array(string()).optional(),
60886
60907
  loopControl: LoopControlPatchSchema.optional(),
60887
60908
  background: BackgroundConfigPatchSchema.optional(),
60909
+ modelCatalog: ModelCatalogConfigPatchSchema.optional(),
60888
60910
  experimental: ExperimentalConfigPatchSchema.optional(),
60889
60911
  telemetry: boolean$1().optional()
60890
60912
  }).strict();
@@ -72070,28 +72092,31 @@ var FullCompaction = class {
72070
72092
  tokensAfter
72071
72093
  };
72072
72094
  this.agent.telemetry.track("compaction_finished", {
72073
- tokensBefore: result.tokensBefore,
72074
- tokensAfter: result.tokensAfter,
72095
+ source: data.source,
72096
+ tokens_before: result.tokensBefore,
72097
+ tokens_after: result.tokensAfter,
72075
72098
  duration_ms: Date.now() - startedAt,
72076
- compactedCount: result.compactedCount,
72077
- retryCount,
72099
+ compacted_count: result.compactedCount,
72100
+ retry_count: retryCount,
72078
72101
  round,
72079
- thinkingLevel: this.agent.config.thinkingLevel,
72080
- ...usage,
72081
- ...data
72102
+ thinking_level: this.agent.config.thinkingLevel,
72103
+ ...usage === null ? {} : {
72104
+ input_tokens: inputTotal(usage),
72105
+ output_tokens: usage.output
72106
+ }
72082
72107
  });
72083
72108
  this.agent.context.applyCompaction(result);
72084
72109
  return result;
72085
72110
  } catch (error) {
72086
72111
  if (isAbortError$3(error)) return;
72087
72112
  this.agent.telemetry.track("compaction_failed", {
72088
- ...data,
72089
- tokensBefore,
72113
+ source: data.source,
72114
+ tokens_before: tokensBefore,
72090
72115
  duration_ms: Date.now() - startedAt,
72091
72116
  round,
72092
- retryCount,
72093
- thinkingLevel: this.agent.config.thinkingLevel,
72094
- errorType: error instanceof Error ? error.name : "Unknown"
72117
+ retry_count: retryCount,
72118
+ thinking_level: this.agent.config.thinkingLevel,
72119
+ error_type: error instanceof Error ? error.name : "Unknown"
72095
72120
  });
72096
72121
  if (isKimiError(error) && error.code === ErrorCodes.AUTH_LOGIN_REQUIRED) throw error;
72097
72122
  throw new KimiError(ErrorCodes.COMPACTION_FAILED, String(error), { cause: error });
@@ -72179,15 +72204,21 @@ var MicroCompaction = class {
72179
72204
  const tokensBefore = rawContextTokens - previousEffect.truncatedToolResultTokensBefore + previousEffect.truncatedToolResultTokensAfter;
72180
72205
  const tokensAfter = rawContextTokens - effect.truncatedToolResultTokensBefore + effect.truncatedToolResultTokensAfter;
72181
72206
  this.agent.telemetry.track("micro_compaction_finished", {
72182
- ...config,
72183
- ...effect,
72184
- tokensBefore,
72185
- tokensAfter,
72207
+ keep_recent_messages: config.keepRecentMessages,
72208
+ min_content_tokens: config.minContentTokens,
72209
+ cache_missed_threshold_ms: config.cacheMissedThresholdMs,
72210
+ truncated_marker: config.truncatedMarker,
72211
+ min_context_usage_ratio: config.minContextUsageRatio,
72212
+ truncated_tool_result_count: effect.truncatedToolResultCount,
72213
+ truncated_tool_result_tokens_before: effect.truncatedToolResultTokensBefore,
72214
+ truncated_tool_result_tokens_after: effect.truncatedToolResultTokensAfter,
72215
+ tokens_before: tokensBefore,
72216
+ tokens_after: tokensAfter,
72186
72217
  previous_cutoff: previousCutoff,
72187
72218
  cutoff: nextCutoff,
72188
72219
  message_count: history.length,
72189
72220
  cache_age_ms: cacheAgeMs,
72190
- thinkingLevel: this.agent.config.thinkingLevel
72221
+ thinking_level: this.agent.config.thinkingLevel
72191
72222
  });
72192
72223
  }
72193
72224
  }
@@ -89424,6 +89455,29 @@ function validateToolArgs(validator, args) {
89424
89455
  return errors.map((error) => formatValidationError(error)).join("; ");
89425
89456
  }
89426
89457
  //#endregion
89458
+ //#region ../../packages/agent-core/src/loop/tool-args-parse.ts
89459
+ function parseToolCallArguments$1(raw) {
89460
+ if (raw === null || raw.length === 0) return {
89461
+ success: true,
89462
+ data: {},
89463
+ parseFailed: false
89464
+ };
89465
+ try {
89466
+ return {
89467
+ success: true,
89468
+ data: JSON.parse(raw),
89469
+ parseFailed: false
89470
+ };
89471
+ } catch (error) {
89472
+ return {
89473
+ success: true,
89474
+ data: {},
89475
+ parseFailed: true,
89476
+ error: errorMessage$5(error)
89477
+ };
89478
+ }
89479
+ }
89480
+ //#endregion
89427
89481
  //#region ../../packages/agent-core/src/loop/tool-scheduler.ts
89428
89482
  /**
89429
89483
  * Stateful execution scheduler for tool calls in one model step.
@@ -89504,7 +89558,7 @@ async function runToolCallBatch(step, response) {
89504
89558
  ...step,
89505
89559
  toolCalls: response.toolCalls
89506
89560
  };
89507
- const calls = response.toolCalls.map((toolCall) => preflightToolCall(step.tools, toolCall));
89561
+ const calls = response.toolCalls.map((toolCall) => preflightToolCall(step, toolCall));
89508
89562
  const scheduler = new ToolScheduler();
89509
89563
  const pendingResults = [];
89510
89564
  let stopTurn = false;
@@ -89541,25 +89595,23 @@ async function runToolCallBatch(step, response) {
89541
89595
  * Provider-order validation pass. It does not run hooks, spawn tools, or write
89542
89596
  * events. Validator compilation may populate the local cache.
89543
89597
  */
89544
- function preflightToolCall(tools, toolCall) {
89598
+ function preflightToolCall(step, toolCall) {
89545
89599
  const toolName = toolCall.name;
89546
89600
  const parsedArgs = parseToolCallArguments$1(toolCall.arguments);
89547
- const args = parsedArgs.success ? parsedArgs.data : {};
89548
- const tool = tools?.find((candidate) => candidate.name === toolName);
89601
+ const tool = step.tools?.find((candidate) => candidate.name === toolName);
89549
89602
  if (tool === void 0) return {
89550
89603
  kind: "rejected",
89551
89604
  toolCall,
89552
89605
  toolName,
89553
- args,
89606
+ args: parsedArgs.data,
89554
89607
  output: `Tool "${toolName}" not found`
89555
89608
  };
89556
- if (!parsedArgs.success) return {
89557
- kind: "rejected",
89558
- toolCall,
89609
+ if (parsedArgs.parseFailed) step.log?.debug("tool args JSON parse failed", {
89559
89610
  toolName,
89560
- args,
89561
- output: `Invalid args for tool "${toolName}": malformed JSON in arguments: ${parsedArgs.error}`
89562
- };
89611
+ toolCallId: toolCall.id,
89612
+ rawLength: toolCall.arguments?.length ?? 0,
89613
+ error: parsedArgs.error
89614
+ });
89563
89615
  const validationError = validateExecutableToolArgs(tool, parsedArgs.data);
89564
89616
  if (validationError !== null) return {
89565
89617
  kind: "rejected",
@@ -89576,23 +89628,6 @@ function preflightToolCall(tools, toolCall) {
89576
89628
  args: parsedArgs.data
89577
89629
  };
89578
89630
  }
89579
- function parseToolCallArguments$1(raw) {
89580
- if (raw === null || raw.length === 0) return {
89581
- success: true,
89582
- data: {}
89583
- };
89584
- try {
89585
- return {
89586
- success: true,
89587
- data: JSON.parse(raw)
89588
- };
89589
- } catch (error) {
89590
- return {
89591
- success: false,
89592
- error: errorMessage$5(error)
89593
- };
89594
- }
89595
- }
89596
89631
  function validateExecutableToolArgs(tool, args) {
89597
89632
  let validator = validators.get(tool);
89598
89633
  if (validator === void 0) try {
@@ -90972,6 +91007,39 @@ const patchConfigRequestSchema = object({
90972
91007
  telemetry: boolean$1().optional()
90973
91008
  });
90974
91009
  //#endregion
91010
+ //#region ../../packages/protocol/src/modelCatalog.ts
91011
+ const modelCatalogItemSchema = object({
91012
+ provider: string().min(1),
91013
+ model: string().min(1),
91014
+ display_name: string().min(1).optional(),
91015
+ max_context_size: number$1().int().min(1),
91016
+ capabilities: array(string()).optional()
91017
+ });
91018
+ const providerCatalogStatusSchema = _enum([
91019
+ "connected",
91020
+ "error",
91021
+ "unconfigured"
91022
+ ]);
91023
+ const providerCatalogItemSchema = object({
91024
+ id: string().min(1),
91025
+ type: string().min(1),
91026
+ base_url: string().min(1).optional(),
91027
+ default_model: string().min(1).optional(),
91028
+ has_api_key: boolean$1(),
91029
+ status: providerCatalogStatusSchema,
91030
+ models: array(string().min(1)).optional()
91031
+ });
91032
+ const providerRefreshChangeSchema = object({
91033
+ provider_id: string().min(1),
91034
+ provider_name: string().min(1),
91035
+ added: number$1().int().min(0),
91036
+ removed: number$1().int().min(0)
91037
+ });
91038
+ const providerRefreshFailureSchema = object({
91039
+ provider: string().min(1),
91040
+ reason: string().min(1)
91041
+ });
91042
+ //#endregion
90975
91043
  //#region ../../packages/protocol/src/events.ts
90976
91044
  const MCP_OAUTH_AUTHORIZATION_URL_TOOL_UPDATE = "mcp.oauth.authorization_url";
90977
91045
  const tokenUsageSchema = object({
@@ -91298,6 +91366,12 @@ object({
91298
91366
  changedFields: array(string()),
91299
91367
  config: configResponseSchema
91300
91368
  });
91369
+ const modelCatalogChangedEventSchema = object({
91370
+ type: literal("event.model_catalog.changed"),
91371
+ changed: array(providerRefreshChangeSchema),
91372
+ unchanged: array(string().min(1)),
91373
+ failed: array(providerRefreshFailureSchema)
91374
+ });
91301
91375
  const goalUpdatedEventSchema = object({
91302
91376
  type: literal("goal.updated"),
91303
91377
  snapshot: goalSnapshotSchema.nullable(),
@@ -91530,6 +91604,7 @@ const eventSchema = discriminatedUnion("type", [
91530
91604
  workspaceUpdatedEventSchema,
91531
91605
  workspaceDeletedEventSchema,
91532
91606
  sessionStatusChangedEventSchema,
91607
+ modelCatalogChangedEventSchema,
91533
91608
  goalUpdatedEventSchema,
91534
91609
  skillActivatedEventSchema,
91535
91610
  turnStartedEventSchema,
@@ -92329,39 +92404,6 @@ const fileMetaSchema = object({
92329
92404
  expires_at: isoDateTimeSchema.optional()
92330
92405
  });
92331
92406
  //#endregion
92332
- //#region ../../packages/protocol/src/modelCatalog.ts
92333
- const modelCatalogItemSchema = object({
92334
- provider: string().min(1),
92335
- model: string().min(1),
92336
- display_name: string().min(1).optional(),
92337
- max_context_size: number$1().int().min(1),
92338
- capabilities: array(string()).optional()
92339
- });
92340
- const providerCatalogStatusSchema = _enum([
92341
- "connected",
92342
- "error",
92343
- "unconfigured"
92344
- ]);
92345
- const providerCatalogItemSchema = object({
92346
- id: string().min(1),
92347
- type: string().min(1),
92348
- base_url: string().min(1).optional(),
92349
- default_model: string().min(1).optional(),
92350
- has_api_key: boolean$1(),
92351
- status: providerCatalogStatusSchema,
92352
- models: array(string().min(1)).optional()
92353
- });
92354
- const providerRefreshChangeSchema = object({
92355
- provider_id: string().min(1),
92356
- provider_name: string().min(1),
92357
- added: number$1().int().min(0),
92358
- removed: number$1().int().min(0)
92359
- });
92360
- const providerRefreshFailureSchema = object({
92361
- provider: string().min(1),
92362
- reason: string().min(1)
92363
- });
92364
- //#endregion
92365
92407
  //#region ../../packages/protocol/src/rest/fs.ts
92366
92408
  /**
92367
92409
  * POST /v1/sessions/{sid}/fs:list
@@ -93024,7 +93066,12 @@ const setDefaultModelResponseSchema = object({
93024
93066
  default_model: string().min(1),
93025
93067
  model: modelCatalogItemSchema
93026
93068
  });
93027
- const refreshOAuthProviderModelsResponseSchema = object({
93069
+ object({
93070
+ changed: array(providerRefreshChangeSchema),
93071
+ unchanged: array(string().min(1)),
93072
+ failed: array(providerRefreshFailureSchema)
93073
+ });
93074
+ const refreshProviderModelsResponseSchema = object({
93028
93075
  changed: array(providerRefreshChangeSchema),
93029
93076
  unchanged: array(string().min(1)),
93030
93077
  failed: array(providerRefreshFailureSchema)
@@ -97246,7 +97293,7 @@ var agent_default$1 = "name: agent\ndescription: Default Kimi Code agent\n\nsyst
97246
97293
  var coder_default = "extends: agent\nname: coder\npromptVars:\n roleAdditional: |\n You are now running as a subagent. All the `user` messages are sent by the main agent. The main agent cannot see your context, it can only see your last message when you finish the task. You must treat the parent agent as your caller. Do not directly ask the end user questions. If something is unclear, explain the ambiguity in your final summary to the parent agent.\nwhenToUse: |\n Use this agent for non-trivial software engineering work that may require reading files, editing code, running commands, and returning a compact but technically complete summary to the parent agent.\ntools:\n - Bash\n - Read\n - ReadMediaFile\n - Glob\n - Grep\n - Write\n - Edit\n - WebSearch\n - FetchURL\n - mcp__*\n";
97247
97294
  //#endregion
97248
97295
  //#region ../../packages/agent-core/src/profile/default/explore.yaml?raw
97249
- var explore_default = "extends: agent\nname: explore\npromptVars:\n roleAdditional: |\n You are now running as a subagent. All the `user` messages are sent by the main agent. The main agent cannot see your context, it can only see your last message when you finish the task. You must treat the parent agent as your caller. Do not directly ask the end user questions. If something is unclear, explain the ambiguity in your final summary to the parent agent.\n\n You are a codebase exploration specialist. Your role is EXCLUSIVELY to search, read, and analyze existing code and resources. You do NOT have access to file editing tools.\n\n Your strengths:\n - Rapidly finding files using glob patterns\n - Searching code and text with powerful regex patterns\n - Reading and analyzing file contents\n - Running read-only shell commands (git log, git diff, ls, find, etc.)\n\n Guidelines:\n - Use Glob for broad file pattern matching. Prefer a pattern with a literal anchor (extension or subdirectory): results are capped at a fixed number of matches, so a broad pattern like `**/*` can truncate before reaching what you need.\n - Use Grep for searching file contents with regex\n - Use Read when you know the specific file path\n - Use Bash ONLY for read-only operations (ls, git status, git log, git diff, find)\n - NEVER use Bash for any file creation or modification commands\n - Adapt your search depth based on the thoroughness level specified by the caller\n - Wherever possible, spawn multiple parallel tool calls for grepping and reading files to maximize speed\n\n If the prompt includes a <git-context> block, use it to orient yourself about the repository state before starting your investigation.\n\n You are meant to be a fast agent. Complete the search request efficiently and report your findings clearly in a structured format.\nwhenToUse: |\n Fast agent specialized for exploring codebases. Use this when you need to quickly find files by patterns (e.g. \"src/**/*.yaml\"), search code for keywords (e.g. \"database connection\"), or answer questions about the codebase (e.g. \"how does the auth module work?\"). When calling this agent, specify the desired thoroughness level: \"quick\" for basic searches, \"medium\" for moderate exploration, or \"thorough\" for comprehensive analysis across multiple locations and naming conventions. Use this agent for any read-only exploration that will clearly require more than 3 search queries. Prefer launching multiple explore agents concurrently when investigating independent questions.\ntools:\n - Bash\n - Read\n - ReadMediaFile\n - Glob\n - Grep\n - WebSearch\n - FetchURL\n";
97296
+ var explore_default = "extends: agent\nname: explore\npromptVars:\n roleAdditional: |\n You are now running as a subagent. All the `user` messages are sent by the main agent. The main agent cannot see your context, it can only see your last message when you finish the task. You must treat the parent agent as your caller. Do not directly ask the end user questions. If something is unclear, explain the ambiguity in your final summary to the parent agent.\n\n You are a codebase exploration specialist. Your role is EXCLUSIVELY to search, read, and analyze existing code and resources. You do NOT have access to file editing tools.\n\n Your strengths:\n - Rapidly finding files using glob patterns\n - Searching code and text with powerful regex patterns\n - Reading and analyzing file contents\n - Running read-only shell commands (git log, git diff, ls, find, etc.)\n\n Guidelines:\n - Use Glob for broad file pattern matching. Prefer patterns with a literal anchor (extension or subdirectory); pure wildcards like `*` or `**/*` are allowed but usually truncate at the match cap.\n - Use Grep for searching file contents with regex\n - Use Read when you know the specific file path\n - Use Bash ONLY for read-only operations (ls, git status, git log, git diff, find)\n - NEVER use Bash for any file creation or modification commands\n - Adapt your search depth based on the thoroughness level specified by the caller\n - Wherever possible, spawn multiple parallel tool calls for grepping and reading files to maximize speed\n\n If the prompt includes a <git-context> block, use it to orient yourself about the repository state before starting your investigation.\n\n You are meant to be a fast agent. Complete the search request efficiently and report your findings clearly in a structured format.\nwhenToUse: |\n Fast agent specialized for exploring codebases. Use this when you need to quickly find files by patterns (e.g. \"src/**/*.yaml\"), search code for keywords (e.g. \"database connection\"), or answer questions about the codebase (e.g. \"how does the auth module work?\"). When calling this agent, specify the desired thoroughness level: \"quick\" for basic searches, \"medium\" for moderate exploration, or \"thorough\" for comprehensive analysis across multiple locations and naming conventions. Use this agent for any read-only exploration that will clearly require more than 3 search queries. Prefer launching multiple explore agents concurrently when investigating independent questions.\ntools:\n - Bash\n - Read\n - ReadMediaFile\n - Glob\n - Grep\n - WebSearch\n - FetchURL\n";
97250
97297
  //#endregion
97251
97298
  //#region ../../packages/agent-core/src/profile/default/init.md?raw
97252
97299
  var init_default = "You are a software engineering expert with many years of programming experience. Please explore the current project directory to understand the project's architecture and main details.\n\nTask requirements:\n1. Analyze the project structure and identify key configuration files (such as pyproject.toml, package.json, Cargo.toml, etc.).\n2. Understand the project's technology stack, build process and runtime architecture.\n3. Identify how the code is organized and main module divisions.\n4. Discover project-specific development conventions, testing strategies, and deployment processes.\n\nAfter the exploration, you should do a thorough summary of your findings and overwrite it into `AGENTS.md` file in the project root. You need to refer to what is already in the file when you do so.\n\nFor your information, `AGENTS.md` is a file intended to be read by AI coding agents. Expect the reader of this file know nothing about the project.\n\nYou should compose this file according to the actual project content. Do not make any assumptions or generalizations. Ensure the information is accurate and useful. You must use the natural language that is mainly used in the project's comments and documentation.\n\nPopular sections that people usually write in `AGENTS.md` are:\n\n- Project overview\n- Build and test commands\n- Code style guidelines\n- Testing instructions\n- Security considerations\n";
@@ -99664,278 +99711,6 @@ var EditTool = class {
99664
99711
  }
99665
99712
  };
99666
99713
  //#endregion
99667
- //#region ../../packages/agent-core/src/tools/builtin/file/glob.md?raw
99668
- var glob_default = "Find files (and optionally directories) by glob pattern, sorted by modification time (most recent first).\n\nGood patterns:\n- `*.ts` — files in the current directory matching an extension\n- `src/**/*.ts` — recursive walk with a subdirectory anchor and extension\n- `**/*.py` — recursive walk from the search root for an extension\n- `*.{ts,tsx}` — brace expansion is supported; expanded into `*.ts` and `*.tsx` before walking\n- `{src,test}/**/*.ts` — cartesian brace expansion is supported too\n\nPrefer a pattern with a literal anchor (a file extension or subdirectory) up front; a bare `**/*` walks until it truncates at the match cap. Results are capped at the first 100 matching paths (walk order, not global modification-time order). If a search would return more, a truncation marker is appended with the count of matches seen so far. Refine the pattern (extension, subdirectory) when 100 is not enough, or call again with a narrower anchor.\n\nLarge-directory caveat — avoid recursing into dependency / build output even with an anchor:\n- `node_modules/**/*.js`, `.venv/**/*.py`, `__pycache__/**`, `target/**` all match technically but\n typically produce thousands of results that truncate at the match cap and waste the caller context.\n Prefer specific subpaths like `node_modules/react/src/**/*.js`.\n";
99669
- //#endregion
99670
- //#region ../../packages/agent-core/src/tools/builtin/file/glob.ts
99671
- const GlobInputSchema = object({
99672
- pattern: string().describe("Glob pattern to match files/directories."),
99673
- path: string().optional().describe("Absolute path to the directory to search in. Defaults to the current working directory."),
99674
- include_dirs: boolean$1().default(true).optional().describe("Whether to include directories in results. Defaults to true. Set false to return only files.")
99675
- });
99676
- /**
99677
- * Hard upper bound on the number of sub-patterns a single brace expansion
99678
- * is allowed to produce. Generous enough for the common LLM patterns
99679
- * (`*.{ts,tsx,js,jsx,mjs,cjs}` etc.) while still keeping pathological
99680
- * cartesian inputs like `{a,b}{c,d}{e,f}{g,h}{i,j}{k,l}` (= 64) from
99681
- * fanning out unboundedly. Beyond this we fall through with the original
99682
- * pattern unexpanded — kaos would then treat the braces as literals and
99683
- * match zero, which is the right "obvious failure" signal for a pattern
99684
- * the model probably did not mean.
99685
- */
99686
- const MAX_BRACE_EXPANSIONS = 64;
99687
- /**
99688
- * Path-shape hint appended to the tool description only on a Windows
99689
- * (`win32` path class) backend. The `path` argument accepts both native
99690
- * Windows paths and POSIX-style paths, but matched paths come back in
99691
- * Windows backslash form — a command run through Bash must convert them
99692
- * to forward slashes first. Injected conditionally so non-Windows
99693
- * sessions are not shown a hint that does not apply to them.
99694
- */
99695
- const WINDOWS_PATH_HINT = "\n\nWindows note: the `path` argument accepts both Windows paths (e.g. `C:\\Users\\foo`) and POSIX-style paths (e.g. `/c/Users/foo`). Matched paths are returned in Windows backslash form; convert them to forward slashes before using them in a Bash command.";
99696
- const S_IFMT$2 = 61440;
99697
- const S_IFDIR$1 = 16384;
99698
- /**
99699
- * Tool-level description shown to the LLM at tool declaration time.
99700
- * Tells the model — before any round-trip — which patterns are accepted,
99701
- * how brace expansion is handled, and which directories are too large to
99702
- * recurse into. On a Windows backend the description also carries
99703
- * `WINDOWS_PATH_HINT` (path-shape guidance).
99704
- */
99705
- var GlobTool = class {
99706
- kaos;
99707
- workspace;
99708
- name = "Glob";
99709
- description;
99710
- parameters = toInputJsonSchema(GlobInputSchema);
99711
- constructor(kaos, workspace) {
99712
- this.kaos = kaos;
99713
- this.workspace = workspace;
99714
- this.description = this.kaos.pathClass() === "win32" ? glob_default + WINDOWS_PATH_HINT : glob_default;
99715
- }
99716
- resolveExecution(args) {
99717
- let path;
99718
- if (args.path !== void 0) path = resolvePathAccessPath(args.path, {
99719
- kaos: this.kaos,
99720
- workspace: this.workspace,
99721
- operation: "search",
99722
- policy: {
99723
- guardMode: "absolute-outside-allowed",
99724
- checkSensitive: false
99725
- }
99726
- });
99727
- const searchRoots = [path ?? this.workspace.workspaceDir];
99728
- const detailParts = [];
99729
- detailParts.push(`pattern: ${args.pattern}`);
99730
- if (args.path !== void 0) detailParts.push(`path: ${args.path}`);
99731
- if (args.include_dirs === false) detailParts.push("include_dirs: false");
99732
- return {
99733
- accesses: ToolAccesses.searchTree(searchRoots[0]),
99734
- description: `Searching ${args.pattern}`,
99735
- display: {
99736
- kind: "file_io",
99737
- operation: "glob",
99738
- path: searchRoots[0],
99739
- detail: detailParts.join(", ")
99740
- },
99741
- approvalRule: literalRulePattern(this.name, args.pattern),
99742
- matchesRule: (ruleArgs) => matchesGlobRuleSubject(ruleArgs, args.pattern),
99743
- execute: () => this.execution(args, searchRoots)
99744
- };
99745
- }
99746
- async execution(args, searchRoots) {
99747
- const subPatterns = expandBraces(args.pattern).map((p) => hasGlobEscape(p) ? p : normalize$1(p));
99748
- const includeDirs = args.include_dirs ?? true;
99749
- for (const root of searchRoots) try {
99750
- const iter = this.kaos.iterdir(root);
99751
- await iter.next();
99752
- if (typeof iter.return === "function") await iter.return(void 0);
99753
- } catch (error) {
99754
- if (error !== null && typeof error === "object" && "code" in error) {
99755
- const code = error.code;
99756
- if (code === "ENOENT") return {
99757
- isError: true,
99758
- output: `${root} does not exist`
99759
- };
99760
- if (code === "ENOTDIR") return {
99761
- isError: true,
99762
- output: `${root} is not a directory`
99763
- };
99764
- }
99765
- }
99766
- try {
99767
- const seen = /* @__PURE__ */ new Set();
99768
- const entries = [];
99769
- const YIELD_SAFETY_CAP = 200 * subPatterns.length;
99770
- let yielded = 0;
99771
- let truncated = false;
99772
- outer: for (const root of searchRoots) for (const subPattern of subPatterns) for await (const filePath of this.kaos.glob(root, subPattern)) {
99773
- yielded++;
99774
- if (yielded >= YIELD_SAFETY_CAP) {
99775
- truncated = true;
99776
- break outer;
99777
- }
99778
- if (seen.has(filePath)) continue;
99779
- if (entries.length >= 100) {
99780
- truncated = true;
99781
- break outer;
99782
- }
99783
- seen.add(filePath);
99784
- let mtime = 0;
99785
- let isDir = false;
99786
- try {
99787
- const st = await this.kaos.stat(filePath);
99788
- mtime = st.stMtime ?? 0;
99789
- isDir = (st.stMode & S_IFMT$2) === S_IFDIR$1;
99790
- } catch {}
99791
- if (!includeDirs && isDir) continue;
99792
- entries.push({
99793
- path: filePath,
99794
- mtime
99795
- });
99796
- }
99797
- entries.sort((a, b) => b.mtime - a.mtime);
99798
- const paths = entries.map((e) => e.path);
99799
- const pathClass = this.kaos.pathClass();
99800
- const relBase = searchRoots[0] ?? this.workspace.workspaceDir;
99801
- const shouldRelativize = isWithinDirectory(relBase, this.workspace.workspaceDir, pathClass);
99802
- const displayLines = paths.map((p) => shouldRelativize ? relativizeIfUnder$1(p, relBase, pathClass) : p);
99803
- if (entries.length === 0 && !truncated) return { output: "No matches found" };
99804
- const lines = [];
99805
- if (truncated) {
99806
- lines.push(`[Truncated at ${String(100)} matches — ${String(seen.size)} matched so far, use a more specific pattern]`);
99807
- lines.push(`Only the first ${String(100)} matches are returned.`);
99808
- }
99809
- lines.push(...displayLines);
99810
- if (!truncated && entries.length === 100) lines.push(`Found ${String(entries.length)} matches`);
99811
- return { output: lines.join("\n") };
99812
- } catch (error) {
99813
- if (error !== null && typeof error === "object" && "code" in error) {
99814
- const code = error.code;
99815
- const path = searchRoots[0] ?? this.workspace.workspaceDir;
99816
- if (code === "ENOENT") return {
99817
- isError: true,
99818
- output: `${path} does not exist`
99819
- };
99820
- if (code === "ENOTDIR") return {
99821
- isError: true,
99822
- output: `${path} is not a directory`
99823
- };
99824
- }
99825
- return {
99826
- isError: true,
99827
- output: error instanceof Error ? error.message : String(error)
99828
- };
99829
- }
99830
- }
99831
- };
99832
- /**
99833
- * If `candidate` is under `base`, return the portion after `base/`.
99834
- * Otherwise return `candidate` unchanged (absolute). Both arguments
99835
- * should be canonical absolute paths.
99836
- */
99837
- function relativizeIfUnder$1(candidate, base, pathClass) {
99838
- const normCandidate = normalize$1(candidate);
99839
- const normBase = normalize$1(base);
99840
- const comparableCandidate = pathClass === "win32" ? normCandidate.toLowerCase() : normCandidate;
99841
- const comparableBase = pathClass === "win32" ? normBase.toLowerCase() : normBase;
99842
- if (comparableCandidate === comparableBase) return ".";
99843
- const prefix = comparableBase.endsWith("/") ? comparableBase : comparableBase + "/";
99844
- if (comparableCandidate.startsWith(prefix)) return normCandidate.slice(prefix.length);
99845
- return normCandidate;
99846
- }
99847
- /**
99848
- * Expand brace alternations (`{a,b,c}`, `{src,test}/**`) into a flat list
99849
- * of sub-patterns. Recursive — handles cartesian products (`{a,b}/{c,d}.ts`
99850
- * → 4 patterns) and one or more levels of nesting (`{a,{b,c}}.ts`).
99851
- *
99852
- * Falls through with the original pattern as a single-element list when:
99853
- * - the pattern contains no `{...}` group at all;
99854
- * - the pattern contains `{...}` groups but none have a top-level comma
99855
- * (e.g. `{abc}` — bash treats those as literal);
99856
- * - braces are unbalanced (a stray `{` with no matching `}`, etc.);
99857
- * - expansion would produce more than `MAX_BRACE_EXPANSIONS` patterns —
99858
- * pathological cartesian inputs (`{a,b}{c,d}{e,f}{g,h}{i,j}{k,l,m}`
99859
- * ≥ 192) bail out rather than fan out unboundedly.
99860
- *
99861
- * Backslash-escaped braces (`\{`, `\}`) are treated as literals and skip
99862
- * the structural recognition so a user can opt out of expansion.
99863
- */
99864
- function expandBraces(pattern) {
99865
- const out = [];
99866
- if (!expandInto(pattern, out, MAX_BRACE_EXPANSIONS)) return [pattern];
99867
- return out;
99868
- }
99869
- function hasGlobEscape(pattern) {
99870
- return /\\[{}[\]*?,]/.test(pattern);
99871
- }
99872
- function expandInto(pattern, out, cap) {
99873
- let depth = 0;
99874
- let start = -1;
99875
- for (let i = 0; i < pattern.length; i++) {
99876
- const ch = pattern[i];
99877
- if (ch === "\\" && i + 1 < pattern.length) {
99878
- i++;
99879
- continue;
99880
- }
99881
- if (ch === "{") {
99882
- if (depth === 0) start = i;
99883
- depth++;
99884
- continue;
99885
- }
99886
- if (ch === "}") {
99887
- if (depth === 0) return pushLiteral(pattern, out, cap);
99888
- depth--;
99889
- if (depth === 0 && start !== -1) {
99890
- const parts = splitTopLevelCommas(pattern.slice(start + 1, i));
99891
- if (parts.length < 2) {
99892
- start = -1;
99893
- continue;
99894
- }
99895
- const prefix = pattern.slice(0, start);
99896
- const suffix = pattern.slice(i + 1);
99897
- for (const part of parts) {
99898
- if (out.length >= cap) return false;
99899
- if (!expandInto(prefix + part + suffix, out, cap)) return false;
99900
- }
99901
- return true;
99902
- }
99903
- }
99904
- }
99905
- if (depth !== 0) return pushLiteral(pattern, out, cap);
99906
- return pushLiteral(pattern, out, cap);
99907
- }
99908
- function pushLiteral(pattern, out, cap) {
99909
- if (out.length >= cap) return false;
99910
- out.push(pattern);
99911
- return true;
99912
- }
99913
- /**
99914
- * Split on commas that sit at brace depth zero. Used by `expandBraces`
99915
- * to slice a `{a,{b,c},d}` group into `["a", "{b,c}", "d"]` rather than
99916
- * `["a", "{b", "c}", "d"]`.
99917
- */
99918
- function splitTopLevelCommas(s) {
99919
- const parts = [];
99920
- let depth = 0;
99921
- let last = 0;
99922
- for (let i = 0; i < s.length; i++) {
99923
- const ch = s[i];
99924
- if (ch === "\\" && i + 1 < s.length) {
99925
- i++;
99926
- continue;
99927
- }
99928
- if (ch === "{") depth++;
99929
- else if (ch === "}") depth--;
99930
- else if (ch === "," && depth === 0) {
99931
- parts.push(s.slice(last, i));
99932
- last = i + 1;
99933
- }
99934
- }
99935
- parts.push(s.slice(last));
99936
- return parts;
99937
- }
99938
- //#endregion
99939
99714
  //#region ../../node_modules/.pnpm/tar@7.5.13/node_modules/tar/dist/esm/index.min.js
99940
99715
  var kr = Object.defineProperty;
99941
99716
  var vr = (s, t) => {
@@ -104310,6 +104085,386 @@ function rgUnavailableMessage(cause) {
104310
104085
  Error: ${cause instanceof Error ? cause.message : typeof cause === "string" ? cause : "unknown error"}\n\nFix options:\n macOS: brew install ripgrep\n Ubuntu: sudo apt-get install ripgrep\n Other: https://github.com/BurntSushi/ripgrep#installation\n\nAlternatively, drop a static rg binary at ${join$4(getShareDir(), "bin", rgBinaryName())}`;
104311
104086
  }
104312
104087
  //#endregion
104088
+ //#region ../../packages/agent-core/src/tools/support/stream.ts
104089
+ function isPrematureCloseError(error) {
104090
+ return error instanceof Error && error.code === "ERR_STREAM_PREMATURE_CLOSE";
104091
+ }
104092
+ //#endregion
104093
+ //#region ../../packages/agent-core/src/tools/support/run-rg.ts
104094
+ const DEFAULT_TIMEOUT_MS$1 = 2e4;
104095
+ const MAX_OUTPUT_BYTES = 10 * 1024 * 1024;
104096
+ const VCS_DIRECTORIES_TO_EXCLUDE = [
104097
+ ".git",
104098
+ ".svn",
104099
+ ".hg",
104100
+ ".bzr",
104101
+ ".jj",
104102
+ ".sl"
104103
+ ];
104104
+ const SENSITIVE_GLOBS_TO_EXCLUDE = [
104105
+ "**/.env",
104106
+ ...[
104107
+ "id_rsa",
104108
+ "id_ed25519",
104109
+ "id_ecdsa"
104110
+ ].flatMap((name) => [
104111
+ `**/${name}`,
104112
+ `**/${name}[-_]*`,
104113
+ ...SENSITIVE_DOT_VARIANT_SUFFIXES.map((suffix) => `**/${name}${suffix}`)
104114
+ ]),
104115
+ "**/.aws/credentials",
104116
+ "**/.aws/credentials/**",
104117
+ "**/.gcp/credentials",
104118
+ "**/.gcp/credentials/**"
104119
+ ];
104120
+ async function disposeProcess$1(proc) {
104121
+ try {
104122
+ await proc.dispose();
104123
+ } catch {}
104124
+ }
104125
+ async function runRipgrepOnce(kaos, rgArgs, signal, options = {}) {
104126
+ const abortedMessage = options.abortedMessage ?? "Aborted";
104127
+ if (signal.aborted) return {
104128
+ kind: "tool-error",
104129
+ result: {
104130
+ isError: true,
104131
+ output: abortedMessage
104132
+ }
104133
+ };
104134
+ let proc;
104135
+ try {
104136
+ proc = await kaos.exec(...rgArgs);
104137
+ } catch (error) {
104138
+ return {
104139
+ kind: "tool-error",
104140
+ result: {
104141
+ isError: true,
104142
+ output: error instanceof Error && "code" in error && error.code === "ENOENT" ? rgUnavailableMessage(error) : error instanceof Error ? error.message : String(error)
104143
+ }
104144
+ };
104145
+ }
104146
+ try {
104147
+ proc.stdin.end();
104148
+ } catch {}
104149
+ let timedOut = false;
104150
+ let aborted = false;
104151
+ let killed = false;
104152
+ const killProc = async () => {
104153
+ if (killed) return;
104154
+ killed = true;
104155
+ try {
104156
+ await proc.kill("SIGTERM");
104157
+ } catch {}
104158
+ const exited = proc.wait().then(() => true).catch(() => true);
104159
+ if (!await Promise.race([exited, new Promise((resolve) => {
104160
+ setTimeout(() => {
104161
+ resolve(false);
104162
+ }, 5e3);
104163
+ })]) && proc.exitCode === null) try {
104164
+ await proc.kill("SIGKILL");
104165
+ } catch {}
104166
+ await disposeProcess$1(proc);
104167
+ };
104168
+ const onAbort = () => {
104169
+ aborted = true;
104170
+ killProc();
104171
+ };
104172
+ signal.addEventListener("abort", onAbort);
104173
+ if (signal.aborted) onAbort();
104174
+ const timeoutHandle = setTimeout(() => {
104175
+ timedOut = true;
104176
+ killProc();
104177
+ }, DEFAULT_TIMEOUT_MS$1);
104178
+ let exitCode = 0;
104179
+ let stdoutText = "";
104180
+ let stderrText = "";
104181
+ let bufferTruncated = false;
104182
+ let stderrTruncated = false;
104183
+ try {
104184
+ const isTerminating = () => timedOut || aborted || killed;
104185
+ const [stdoutResult, stderrResult, code] = await Promise.all([
104186
+ readStreamWithCap(proc.stdout, MAX_OUTPUT_BYTES, isTerminating),
104187
+ readStreamWithCap(proc.stderr, MAX_OUTPUT_BYTES, isTerminating),
104188
+ proc.wait()
104189
+ ]);
104190
+ stdoutText = stdoutResult.text;
104191
+ stderrText = stderrResult.text;
104192
+ bufferTruncated = stdoutResult.truncated;
104193
+ stderrTruncated = stderrResult.truncated;
104194
+ exitCode = code;
104195
+ } catch (error) {
104196
+ if (isPrematureCloseError(error) && (timedOut || aborted || killed)) {} else return {
104197
+ kind: "tool-error",
104198
+ result: {
104199
+ isError: true,
104200
+ output: error instanceof Error ? error.message : String(error)
104201
+ }
104202
+ };
104203
+ } finally {
104204
+ clearTimeout(timeoutHandle);
104205
+ signal.removeEventListener("abort", onAbort);
104206
+ await disposeProcess$1(proc);
104207
+ }
104208
+ if (aborted) return {
104209
+ kind: "tool-error",
104210
+ result: {
104211
+ isError: true,
104212
+ output: abortedMessage
104213
+ }
104214
+ };
104215
+ return {
104216
+ kind: "result",
104217
+ exitCode,
104218
+ stdoutText,
104219
+ stderrText,
104220
+ bufferTruncated,
104221
+ stderrTruncated,
104222
+ timedOut
104223
+ };
104224
+ }
104225
+ function shouldRetryRipgrepEagain(result) {
104226
+ return result.exitCode !== 0 && result.exitCode !== 1 && !result.timedOut && isEagainRipgrepError(result.stderrText);
104227
+ }
104228
+ function isEagainRipgrepError(stderr) {
104229
+ return stderr.includes("os error 11") || stderr.includes("Resource temporarily unavailable");
104230
+ }
104231
+ async function readStreamWithCap(stream, maxBytes, suppressPrematureClose) {
104232
+ const chunks = [];
104233
+ let total = 0;
104234
+ let truncated = false;
104235
+ try {
104236
+ for await (const chunk of stream) {
104237
+ const buf = typeof chunk === "string" ? Buffer.from(chunk, "utf8") : chunk;
104238
+ if (truncated) continue;
104239
+ if (total + buf.length > maxBytes) {
104240
+ const remaining = maxBytes - total;
104241
+ if (remaining > 0) chunks.push(buf.subarray(0, remaining));
104242
+ total = maxBytes;
104243
+ truncated = true;
104244
+ continue;
104245
+ }
104246
+ chunks.push(buf);
104247
+ total += buf.length;
104248
+ }
104249
+ } catch (error) {
104250
+ if (!isPrematureCloseError(error) || suppressPrematureClose?.() !== true) throw error;
104251
+ }
104252
+ return {
104253
+ text: Buffer.concat(chunks).toString("utf8"),
104254
+ truncated
104255
+ };
104256
+ }
104257
+ //#endregion
104258
+ //#region ../../packages/agent-core/src/tools/builtin/file/glob.md?raw
104259
+ var glob_default = "Find files by glob pattern, sorted by modification time (most recent first).\n\nPowered by ripgrep. Respects `.gitignore`, `.ignore`, and `.rgignore` by default — set `include_ignored` to also match ignored files (e.g. build outputs, `node_modules`). Sensitive files (such as `.env`) are always filtered out.\n\nGood patterns:\n- `*.ts` — all files matching an extension, at any depth below the search root (a bare pattern without `/` matches recursively)\n- `src/*.ts` — files directly inside `src/` (one level, not recursive)\n- `src/**/*.ts` — recursive walk with a subdirectory anchor and extension\n- `**/*.py` — recursive walk from the search root for an extension\n- `*.{ts,tsx}` — brace expansion is supported\n- `{src,test}/**/*.ts` — cartesian brace expansion is supported too\n\nResults are capped at the first 100 matching paths. If a search would return more, a truncation marker is appended. Refine the pattern (extension, subdirectory) when 100 is not enough, or call again with a narrower anchor.\n\nLarge-directory caveat — avoid recursing into dependency / build output even with an anchor, especially when `include_ignored` is set:\n- `node_modules/**/*.js`, `.venv/**/*.py`, `__pycache__/**`, `target/**` can produce thousands of results that truncate at the match cap and waste context. Prefer specific subpaths like `node_modules/react/src/**/*.js`.\n";
104260
+ //#endregion
104261
+ //#region ../../packages/agent-core/src/tools/builtin/file/glob.ts
104262
+ const GlobInputSchema = object({
104263
+ pattern: string().describe("Glob pattern to match files."),
104264
+ path: string().optional().describe("Absolute path to the directory to search in. Defaults to the current working directory."),
104265
+ include_ignored: boolean$1().optional().describe("Also match files excluded by ignore files such as `.gitignore`, `.ignore`, and `.rgignore` (for example `node_modules` or build outputs). Sensitive files (such as `.env`) remain filtered out for safety. Defaults to false."),
104266
+ include_dirs: boolean$1().optional().describe("Deprecated and ignored. Results are always files-only — directories are never listed. Accepted only so older calls that still pass this flag are not rejected by parameter validation.")
104267
+ });
104268
+ /**
104269
+ * Path-shape hint appended to the tool description only on a Windows
104270
+ * (`win32` path class) backend. The `path` argument accepts both native
104271
+ * Windows paths and POSIX-style paths, but matched paths come back in
104272
+ * Windows backslash form — a command run through Bash must convert them
104273
+ * to forward slashes first. Injected conditionally so non-Windows
104274
+ * sessions are not shown a hint that does not apply to them.
104275
+ */
104276
+ const WINDOWS_PATH_HINT = "\n\nWindows note: the `path` argument accepts both Windows paths (e.g. `C:\\Users\\foo`) and POSIX-style paths (e.g. `/c/Users/foo`). Matched paths are returned in Windows backslash form; convert them to forward slashes before using them in a Bash command.";
104277
+ const S_IFMT$2 = 61440;
104278
+ const S_IFDIR$1 = 16384;
104279
+ /**
104280
+ * Tool-level description shown to the LLM at tool declaration time.
104281
+ * Tells the model — before any round-trip — which patterns are accepted,
104282
+ * how brace expansion is handled, and which directories are too large to
104283
+ * recurse into. On a Windows backend the description also carries
104284
+ * `WINDOWS_PATH_HINT` (path-shape guidance).
104285
+ */
104286
+ var GlobTool = class {
104287
+ kaos;
104288
+ workspace;
104289
+ name = "Glob";
104290
+ description;
104291
+ parameters = toInputJsonSchema(GlobInputSchema);
104292
+ telemetry;
104293
+ constructor(kaos, workspace, telemetry = noopTelemetryClient) {
104294
+ this.kaos = kaos;
104295
+ this.workspace = workspace;
104296
+ this.telemetry = telemetry;
104297
+ this.description = this.kaos.pathClass() === "win32" ? glob_default + WINDOWS_PATH_HINT : glob_default;
104298
+ }
104299
+ resolveExecution(args) {
104300
+ let path;
104301
+ if (args.path !== void 0) path = resolvePathAccessPath(args.path, {
104302
+ kaos: this.kaos,
104303
+ workspace: this.workspace,
104304
+ operation: "search",
104305
+ policy: {
104306
+ guardMode: "absolute-outside-allowed",
104307
+ checkSensitive: false
104308
+ }
104309
+ });
104310
+ const searchRoots = [path ?? this.workspace.workspaceDir];
104311
+ const detailParts = [`pattern: ${args.pattern}`];
104312
+ if (args.path !== void 0) detailParts.push(`path: ${args.path}`);
104313
+ if (args.include_ignored === true) detailParts.push("include_ignored: true");
104314
+ return {
104315
+ accesses: ToolAccesses.searchTree(searchRoots[0]),
104316
+ description: `Searching ${args.pattern}`,
104317
+ display: {
104318
+ kind: "file_io",
104319
+ operation: "glob",
104320
+ path: searchRoots[0],
104321
+ detail: detailParts.join(", ")
104322
+ },
104323
+ approvalRule: literalRulePattern(this.name, args.pattern),
104324
+ matchesRule: (ruleArgs) => matchesGlobRuleSubject(ruleArgs, args.pattern),
104325
+ execute: ({ signal }) => this.execution(args, signal, searchRoots)
104326
+ };
104327
+ }
104328
+ async execution(args, signal, searchRoots) {
104329
+ const searchRoot = searchRoots[0] ?? this.workspace.workspaceDir;
104330
+ try {
104331
+ if (((await this.kaos.stat(searchRoot)).stMode & S_IFMT$2) !== S_IFDIR$1) return {
104332
+ isError: true,
104333
+ output: `${searchRoot} is not a directory`
104334
+ };
104335
+ } catch (error) {
104336
+ if (errorCode(error) === "ENOENT") return {
104337
+ isError: true,
104338
+ output: `${searchRoot} does not exist`
104339
+ };
104340
+ return {
104341
+ isError: true,
104342
+ output: error instanceof Error ? error.message : String(error)
104343
+ };
104344
+ }
104345
+ let rgPath;
104346
+ try {
104347
+ const resolution = await ensureRgPath({ signal });
104348
+ rgPath = resolution.path;
104349
+ if (resolution.source !== "system-path") this.telemetry.track("glob_tool_rg_fallback", {
104350
+ source: resolution.source,
104351
+ outcome: "resolved"
104352
+ });
104353
+ } catch (error) {
104354
+ if (isAbortError$3(error)) return {
104355
+ isError: true,
104356
+ output: "Glob aborted"
104357
+ };
104358
+ this.telemetry.track("glob_tool_rg_fallback", { outcome: "failed" });
104359
+ return {
104360
+ isError: true,
104361
+ output: rgUnavailableMessage(error)
104362
+ };
104363
+ }
104364
+ const execKaos = this.kaos.withCwd(searchRoot);
104365
+ let runResult = await runRipgrepOnce(execKaos, buildRgArgs$1(rgPath, args), signal, { abortedMessage: "Glob aborted" });
104366
+ if (runResult.kind === "tool-error") return runResult.result;
104367
+ if (shouldRetryRipgrepEagain(runResult)) {
104368
+ runResult = await runRipgrepOnce(execKaos, buildRgArgs$1(rgPath, args, true), signal, { abortedMessage: "Glob aborted" });
104369
+ if (runResult.kind === "tool-error") return runResult.result;
104370
+ }
104371
+ const { exitCode, stdoutText, stderrText, bufferTruncated, timedOut } = runResult;
104372
+ let traversalWarning;
104373
+ if (exitCode !== 0 && exitCode !== 1 && !timedOut) {
104374
+ if (splitCompletePaths(stdoutText, true).length === 0) return {
104375
+ isError: true,
104376
+ output: formatGlobError(searchRoot, stderrText)
104377
+ };
104378
+ traversalWarning = formatGlobWarning(stderrText);
104379
+ }
104380
+ if (signal.aborted) return {
104381
+ isError: true,
104382
+ output: "Glob aborted"
104383
+ };
104384
+ const rawPaths = splitCompletePaths(stdoutText, bufferTruncated || timedOut).map((p) => resolve$2(searchRoot, p));
104385
+ const kept = [];
104386
+ let filteredSensitive = 0;
104387
+ for (const p of rawPaths) if (isSensitiveFile(p)) filteredSensitive++;
104388
+ else kept.push(p);
104389
+ const truncated = kept.length > 100;
104390
+ const limited = truncated ? kept.slice(0, 100) : kept;
104391
+ if (limited.length === 0 && !timedOut) {
104392
+ if (filteredSensitive > 0) return { output: `No non-sensitive matches found (${String(filteredSensitive)} sensitive file(s) filtered).` };
104393
+ return { output: "No matches found" };
104394
+ }
104395
+ const pathClass = this.kaos.pathClass();
104396
+ const shouldRelativize = isWithinDirectory(searchRoot, this.workspace.workspaceDir, pathClass);
104397
+ const displayLines = limited.map((p) => shouldRelativize ? relativizeIfUnder$1(p, searchRoot, pathClass) : p);
104398
+ const lines = [];
104399
+ if (timedOut) lines.push(`Glob timed out after ${String(DEFAULT_TIMEOUT_MS$1 / 1e3)}s; partial results returned.`);
104400
+ if (bufferTruncated) lines.push(`[stdout truncated at ${String(MAX_OUTPUT_BYTES)} bytes; results may be incomplete — use a more specific pattern]`);
104401
+ if (traversalWarning !== void 0) lines.push(traversalWarning);
104402
+ if (truncated) {
104403
+ lines.push(`[Truncated at ${String(100)} matches — use a more specific pattern]`);
104404
+ lines.push(`Only the first ${String(100)} matches are returned.`);
104405
+ }
104406
+ lines.push(...displayLines);
104407
+ if (filteredSensitive > 0) lines.push(`Filtered ${String(filteredSensitive)} sensitive file(s).`);
104408
+ if (!truncated && limited.length === 100) lines.push(`Found ${String(limited.length)} matches`);
104409
+ return { output: lines.join("\n") };
104410
+ }
104411
+ };
104412
+ function buildRgArgs$1(rgPath, args, singleThreaded = false) {
104413
+ const cmd = [rgPath];
104414
+ if (singleThreaded) cmd.push("-j", "1");
104415
+ cmd.push("--files", "--hidden", "--sortr=modified");
104416
+ for (const dir of VCS_DIRECTORIES_TO_EXCLUDE) cmd.push("--glob", `!${dir}`);
104417
+ cmd.push("--glob", args.pattern);
104418
+ for (const glob of SENSITIVE_GLOBS_TO_EXCLUDE) cmd.push("--glob", `!${glob}`);
104419
+ if (args.include_ignored) cmd.push("--no-ignore");
104420
+ cmd.push(".");
104421
+ return cmd;
104422
+ }
104423
+ function formatGlobError(searchRoot, stderr) {
104424
+ const trimmed = stderr.trim();
104425
+ if (/no such file or directory/i.test(trimmed)) return `${searchRoot} does not exist`;
104426
+ return trimmed.length > 0 ? `Glob failed: ${trimmed}` : "Glob failed";
104427
+ }
104428
+ function formatGlobWarning(stderr) {
104429
+ const trimmed = stderr.trim();
104430
+ return trimmed.length > 0 ? `Glob completed with warnings; some directories could not be read: ${trimmed}` : "Glob completed with warnings; some directories could not be read.";
104431
+ }
104432
+ function errorCode(error) {
104433
+ if (error !== null && typeof error === "object" && "code" in error) {
104434
+ const code = error.code;
104435
+ return typeof code === "string" ? code : void 0;
104436
+ }
104437
+ }
104438
+ /**
104439
+ * Split `rg --files` stdout into complete paths. When the run was capped or
104440
+ * timed out (`truncatedOutput`), a path cut mid-write lacks its terminating
104441
+ * newline; drop that trailing fragment so it is never surfaced as a match.
104442
+ * Complete output always ends in `\n`, so the split is lossless in that case.
104443
+ */
104444
+ function splitCompletePaths(stdoutText, truncatedOutput) {
104445
+ let text = stdoutText;
104446
+ if (truncatedOutput && !text.endsWith("\n")) {
104447
+ const lastNewline = text.lastIndexOf("\n");
104448
+ text = lastNewline >= 0 ? text.slice(0, lastNewline + 1) : "";
104449
+ }
104450
+ return text.split("\n").filter((p) => p.length > 0);
104451
+ }
104452
+ /**
104453
+ * If `candidate` is under `base`, return the portion after `base/`.
104454
+ * Otherwise return `candidate` unchanged (absolute). Both arguments
104455
+ * should be canonical absolute paths.
104456
+ */
104457
+ function relativizeIfUnder$1(candidate, base, pathClass) {
104458
+ const normCandidate = normalize$1(candidate);
104459
+ const normBase = normalize$1(base);
104460
+ const comparableCandidate = pathClass === "win32" ? normCandidate.toLowerCase() : normCandidate;
104461
+ const comparableBase = pathClass === "win32" ? normBase.toLowerCase() : normBase;
104462
+ if (comparableCandidate === comparableBase) return ".";
104463
+ const prefix = comparableBase.endsWith("/") ? comparableBase : comparableBase + "/";
104464
+ if (comparableCandidate.startsWith(prefix)) return normCandidate.slice(prefix.length);
104465
+ return normCandidate;
104466
+ }
104467
+ //#endregion
104313
104468
  //#region ../../packages/agent-core/src/tools/support/result-builder.ts
104314
104469
  const DEFAULT_MAX_CHARS = 5e4;
104315
104470
  const DEFAULT_MAX_LINE_LENGTH = 2e3;
@@ -104394,11 +104549,6 @@ var ToolResultBuilder = class {
104394
104549
  }
104395
104550
  };
104396
104551
  //#endregion
104397
- //#region ../../packages/agent-core/src/tools/support/stream.ts
104398
- function isPrematureCloseError(error) {
104399
- return error instanceof Error && error.code === "ERR_STREAM_PREMATURE_CLOSE";
104400
- }
104401
- //#endregion
104402
104552
  //#region ../../packages/agent-core/src/tools/builtin/file/grep.md?raw
104403
104553
  var grep_default = "Search file contents using regular expressions (powered by ripgrep).\n\nUse Grep when the task is to find unknown content or unknown file locations. Do not use shell `grep` or `rg` directly; this tool applies workspace path policy, output limits, and sensitive-file filtering.\nALWAYS use Grep tool instead of running `grep` or `rg` from a shell — direct shell calls bypass workspace policy, output limits, and sensitive-file filtering.\nIf you already know a concrete file path and need to inspect its contents, use Read directly instead.\n\nWrite patterns in ripgrep regex syntax, which differs from POSIX `grep` syntax. For example, braces are special, so escape them as `\\{` to match a literal `{`.\n\nHidden files (dotfiles such as `.gitlab-ci.yml` or `.eslintrc.json`) are searched by default. To also search files excluded by `.gitignore` (such as `node_modules` or build outputs), set `include_ignored` to `true`. Sensitive files (such as `.env`) are always skipped for safety, even when `include_ignored` is `true`.\n";
104404
104554
  //#endregion
@@ -104436,41 +104586,9 @@ object({
104436
104586
  numMatches: number$1().int().nonnegative().optional(),
104437
104587
  appliedLimit: number$1().int().nonnegative().optional()
104438
104588
  });
104439
- const DEFAULT_TIMEOUT_MS$1 = 2e4;
104440
- const SIGTERM_GRACE_MS = 5e3;
104441
- const MAX_OUTPUT_BYTES = 10 * 1024 * 1024;
104442
- async function disposeProcess$1(proc) {
104443
- try {
104444
- await proc.dispose();
104445
- } catch {}
104446
- }
104447
104589
  const RG_MAX_COLUMNS = 500;
104448
104590
  const DEFAULT_HEAD_LIMIT = 250;
104449
104591
  const MTIME_STAT_CONCURRENCY = 32;
104450
- const VCS_DIRECTORIES_TO_EXCLUDE = [
104451
- ".git",
104452
- ".svn",
104453
- ".hg",
104454
- ".bzr",
104455
- ".jj",
104456
- ".sl"
104457
- ];
104458
- const SENSITIVE_GLOBS_TO_EXCLUDE = [
104459
- "**/.env",
104460
- ...[
104461
- "id_rsa",
104462
- "id_ed25519",
104463
- "id_ecdsa"
104464
- ].flatMap((name) => [
104465
- `**/${name}`,
104466
- `**/${name}[-_]*`,
104467
- ...SENSITIVE_DOT_VARIANT_SUFFIXES.map((suffix) => `**/${name}${suffix}`)
104468
- ]),
104469
- "**/.aws/credentials",
104470
- "**/.aws/credentials/**",
104471
- "**/.gcp/credentials",
104472
- "**/.gcp/credentials/**"
104473
- ];
104474
104592
  const CONTENT_LINE_RE = /^(.*?)([:-])(\d+)\2/;
104475
104593
  var GrepTool = class {
104476
104594
  kaos;
@@ -104478,9 +104596,11 @@ var GrepTool = class {
104478
104596
  name = "Grep";
104479
104597
  description = grep_default;
104480
104598
  parameters = toInputJsonSchema(GrepInputSchema);
104481
- constructor(kaos, workspace) {
104599
+ telemetry;
104600
+ constructor(kaos, workspace, telemetry = noopTelemetryClient) {
104482
104601
  this.kaos = kaos;
104483
104602
  this.workspace = workspace;
104603
+ this.telemetry = telemetry;
104484
104604
  }
104485
104605
  resolveExecution(args) {
104486
104606
  let path;
@@ -104516,21 +104636,27 @@ var GrepTool = class {
104516
104636
  const pathClass = this.kaos.pathClass();
104517
104637
  let rgPath;
104518
104638
  try {
104519
- rgPath = (await ensureRgPath({ signal })).path;
104639
+ const resolution = await ensureRgPath({ signal });
104640
+ rgPath = resolution.path;
104641
+ if (resolution.source !== "system-path") this.telemetry.track("grep_tool_rg_fallback", {
104642
+ source: resolution.source,
104643
+ outcome: "resolved"
104644
+ });
104520
104645
  } catch (error) {
104521
104646
  if (isAbortError$3(error)) return {
104522
104647
  isError: true,
104523
104648
  output: "Grep aborted"
104524
104649
  };
104650
+ this.telemetry.track("grep_tool_rg_fallback", { outcome: "failed" });
104525
104651
  return {
104526
104652
  isError: true,
104527
104653
  output: rgUnavailableMessage(error)
104528
104654
  };
104529
104655
  }
104530
- let runResult = await runRipgrepOnce(this.kaos, buildRgArgs(rgPath, args, searchPaths), signal);
104656
+ let runResult = await runRipgrepOnce(this.kaos, buildRgArgs(rgPath, args, searchPaths), signal, { abortedMessage: "Grep aborted" });
104531
104657
  if (runResult.kind === "tool-error") return runResult.result;
104532
104658
  if (shouldRetryRipgrepEagain(runResult)) {
104533
- runResult = await runRipgrepOnce(this.kaos, buildRgArgs(rgPath, args, searchPaths, true), signal);
104659
+ runResult = await runRipgrepOnce(this.kaos, buildRgArgs(rgPath, args, searchPaths, true), signal, { abortedMessage: "Grep aborted" });
104534
104660
  if (runResult.kind === "tool-error") return runResult.result;
104535
104661
  }
104536
104662
  const { exitCode, stderrText, bufferTruncated, stderrTruncated, timedOut } = runResult;
@@ -104605,111 +104731,6 @@ var GrepAbortedError = class extends Error {
104605
104731
  this.name = "GrepAbortedError";
104606
104732
  }
104607
104733
  };
104608
- async function runRipgrepOnce(kaos, rgArgs, signal) {
104609
- if (signal.aborted) return {
104610
- kind: "tool-error",
104611
- result: {
104612
- isError: true,
104613
- output: "Grep aborted"
104614
- }
104615
- };
104616
- let proc;
104617
- try {
104618
- proc = await kaos.exec(...rgArgs);
104619
- } catch (error) {
104620
- return {
104621
- kind: "tool-error",
104622
- result: {
104623
- isError: true,
104624
- output: error instanceof Error && "code" in error && error.code === "ENOENT" ? rgUnavailableMessage(error) : error instanceof Error ? error.message : String(error)
104625
- }
104626
- };
104627
- }
104628
- try {
104629
- proc.stdin.end();
104630
- } catch {}
104631
- let timedOut = false;
104632
- let aborted = false;
104633
- let killed = false;
104634
- const killProc = async () => {
104635
- if (killed) return;
104636
- killed = true;
104637
- try {
104638
- await proc.kill("SIGTERM");
104639
- } catch {}
104640
- const exited = proc.wait().then(() => true).catch(() => true);
104641
- if (!await Promise.race([exited, new Promise((resolve) => {
104642
- setTimeout(() => {
104643
- resolve(false);
104644
- }, SIGTERM_GRACE_MS);
104645
- })]) && proc.exitCode === null) try {
104646
- await proc.kill("SIGKILL");
104647
- } catch {}
104648
- await disposeProcess$1(proc);
104649
- };
104650
- const onAbort = () => {
104651
- aborted = true;
104652
- killProc();
104653
- };
104654
- signal.addEventListener("abort", onAbort);
104655
- if (signal.aborted) onAbort();
104656
- const timeoutHandle = setTimeout(() => {
104657
- timedOut = true;
104658
- killProc();
104659
- }, DEFAULT_TIMEOUT_MS$1);
104660
- let exitCode = 0;
104661
- let stdoutText = "";
104662
- let stderrText = "";
104663
- let bufferTruncated = false;
104664
- let stderrTruncated = false;
104665
- try {
104666
- const isTerminating = () => timedOut || aborted || killed;
104667
- const [stdoutResult, stderrResult, code] = await Promise.all([
104668
- readStreamWithCap(proc.stdout, MAX_OUTPUT_BYTES, isTerminating),
104669
- readStreamWithCap(proc.stderr, MAX_OUTPUT_BYTES, isTerminating),
104670
- proc.wait()
104671
- ]);
104672
- stdoutText = stdoutResult.text;
104673
- stderrText = stderrResult.text;
104674
- bufferTruncated = stdoutResult.truncated;
104675
- stderrTruncated = stderrResult.truncated;
104676
- exitCode = code;
104677
- } catch (error) {
104678
- if (isPrematureCloseError(error) && (timedOut || aborted || killed)) {} else return {
104679
- kind: "tool-error",
104680
- result: {
104681
- isError: true,
104682
- output: error instanceof Error ? error.message : String(error)
104683
- }
104684
- };
104685
- } finally {
104686
- clearTimeout(timeoutHandle);
104687
- signal.removeEventListener("abort", onAbort);
104688
- await disposeProcess$1(proc);
104689
- }
104690
- if (aborted) return {
104691
- kind: "tool-error",
104692
- result: {
104693
- isError: true,
104694
- output: "Grep aborted"
104695
- }
104696
- };
104697
- return {
104698
- kind: "result",
104699
- exitCode,
104700
- stdoutText,
104701
- stderrText,
104702
- bufferTruncated,
104703
- stderrTruncated,
104704
- timedOut
104705
- };
104706
- }
104707
- function shouldRetryRipgrepEagain(result) {
104708
- return result.exitCode !== 0 && result.exitCode !== 1 && !result.timedOut && isEagainRipgrepError(result.stderrText);
104709
- }
104710
- function isEagainRipgrepError(stderr) {
104711
- return stderr.includes("os error 11") || stderr.includes("Resource temporarily unavailable");
104712
- }
104713
104734
  async function sortFilesWithMatchesByMtime(lines, kaos, signal) {
104714
104735
  const entries = await mapWithConcurrency(lines, MTIME_STAT_CONCURRENCY, signal, async (line, index) => {
104715
104736
  const path = line.kind === "record" ? line.filePath : line.kind === "legacy" ? line.text : void 0;
@@ -104986,32 +105007,6 @@ function countPayloadFromLegacyLine(line) {
104986
105007
  const idx = line.lastIndexOf(":");
104987
105008
  return idx > 0 ? line.slice(idx + 1) : void 0;
104988
105009
  }
104989
- async function readStreamWithCap(stream, maxBytes, suppressPrematureClose) {
104990
- const chunks = [];
104991
- let total = 0;
104992
- let truncated = false;
104993
- try {
104994
- for await (const chunk of stream) {
104995
- const buf = typeof chunk === "string" ? Buffer.from(chunk, "utf8") : chunk;
104996
- if (truncated) continue;
104997
- if (total + buf.length > maxBytes) {
104998
- const remaining = maxBytes - total;
104999
- if (remaining > 0) chunks.push(buf.subarray(0, remaining));
105000
- total = maxBytes;
105001
- truncated = true;
105002
- continue;
105003
- }
105004
- chunks.push(buf);
105005
- total += buf.length;
105006
- }
105007
- } catch (error) {
105008
- if (!isPrematureCloseError(error) || suppressPrematureClose?.() !== true) throw error;
105009
- }
105010
- return {
105011
- text: Buffer.concat(chunks).toString("utf8"),
105012
- truncated
105013
- };
105014
- }
105015
105010
  const IMAGE_MIME_BY_SUFFIX = Object.freeze({
105016
105011
  ".png": "image/png",
105017
105012
  ".jpg": "image/jpeg",
@@ -108540,8 +108535,8 @@ var ToolManager = class {
108540
108535
  new ReadTool(kaos, workspace),
108541
108536
  new WriteTool(kaos, workspace),
108542
108537
  new EditTool(kaos, workspace),
108543
- new GrepTool(kaos, workspace),
108544
- new GlobTool(kaos, workspace),
108538
+ new GrepTool(kaos, workspace, this.agent.telemetry),
108539
+ new GlobTool(kaos, workspace, this.agent.telemetry),
108545
108540
  new BashTool(kaos, cwd, background, { allowBackground }),
108546
108541
  (modelCapabilities.image_in || modelCapabilities.video_in) && new ReadMediaFileTool(kaos, workspace, modelCapabilities, videoUploader),
108547
108542
  new EnterPlanModeTool(this.agent),
@@ -108603,7 +108598,7 @@ var ToolManager = class {
108603
108598
  ...base,
108604
108599
  outcome: "error",
108605
108600
  duration_ms: Date.now() - startedAt,
108606
- error: error instanceof Error ? error.message : String(error)
108601
+ error_type: error instanceof Error ? error.name : "Unknown"
108607
108602
  });
108608
108603
  throw error;
108609
108604
  }
@@ -158254,6 +158249,382 @@ function normalizeOAuthHost(oauthHost) {
158254
158249
  return oauthHost.trim().replace(/\/+$/, "");
158255
158250
  }
158256
158251
  //#endregion
158252
+ //#region ../../packages/oauth/src/refreshProviderModels.ts
158253
+ function readProvider(config, providerId) {
158254
+ const provider = config.providers[providerId];
158255
+ if (provider === void 0) return void 0;
158256
+ return provider;
158257
+ }
158258
+ function readModel(config, alias) {
158259
+ const model = config.models?.[alias];
158260
+ if (model === void 0) return void 0;
158261
+ return model;
158262
+ }
158263
+ function readCustomRegistrySource$1(provider) {
158264
+ const source = provider.source;
158265
+ if (typeof source !== "object" || source === null) return void 0;
158266
+ const candidate = source;
158267
+ if (candidate["kind"] !== "apiJson") return void 0;
158268
+ const url = candidate["url"];
158269
+ const apiKey = candidate["apiKey"];
158270
+ if (typeof url !== "string" || url.length === 0) return void 0;
158271
+ if (typeof apiKey !== "string") return void 0;
158272
+ return {
158273
+ kind: "apiJson",
158274
+ url,
158275
+ apiKey
158276
+ };
158277
+ }
158278
+ function customRegistrySourceKey(source) {
158279
+ return JSON.stringify([source.url]);
158280
+ }
158281
+ function customRegistrySourceCredentialKey(source) {
158282
+ return JSON.stringify([source.url, source.apiKey]);
158283
+ }
158284
+ async function fetchCustomRegistryFromSources(sources) {
158285
+ let lastError;
158286
+ for (const source of sources) try {
158287
+ return {
158288
+ entries: await fetchCustomRegistry(source),
158289
+ source
158290
+ };
158291
+ } catch (error) {
158292
+ lastError = error;
158293
+ }
158294
+ if (lastError instanceof Error) throw lastError;
158295
+ if (typeof lastError === "string") throw new Error(lastError);
158296
+ throw new Error("No custom registry sources configured.");
158297
+ }
158298
+ function collectModelIdsForAliases(config, aliasKeys) {
158299
+ const ids = /* @__PURE__ */ new Set();
158300
+ for (const aliasKey of aliasKeys) {
158301
+ const alias = readModel(config, aliasKey);
158302
+ if (alias !== void 0 && alias.model.length > 0) ids.add(alias.model);
158303
+ }
158304
+ return ids;
158305
+ }
158306
+ function providerAliasKeys(config, providerId) {
158307
+ const keys = /* @__PURE__ */ new Set();
158308
+ for (const [alias, raw] of Object.entries(config.models ?? {})) if (raw.provider === providerId) keys.add(alias);
158309
+ return keys;
158310
+ }
158311
+ function generatedProviderAliasKeys(config, providerId, aliasPrefix) {
158312
+ const keys = /* @__PURE__ */ new Set();
158313
+ for (const [alias, raw] of Object.entries(config.models ?? {})) if (raw.provider === providerId && alias.startsWith(aliasPrefix)) keys.add(alias);
158314
+ return keys;
158315
+ }
158316
+ function computeChanges(oldIds, newIds) {
158317
+ let added = 0;
158318
+ for (const id of newIds) if (!oldIds.has(id)) added++;
158319
+ let removed = 0;
158320
+ for (const id of oldIds) if (!newIds.has(id)) removed++;
158321
+ return {
158322
+ added,
158323
+ removed
158324
+ };
158325
+ }
158326
+ function providerModelSnapshot(config, providerId, aliasKeys) {
158327
+ const snapshots = [];
158328
+ for (const alias of aliasKeys) {
158329
+ const model = readModel(config, alias);
158330
+ if (model === void 0 || model.provider !== providerId) continue;
158331
+ snapshots.push({
158332
+ alias,
158333
+ model: {
158334
+ ...model,
158335
+ capabilities: model.capabilities === void 0 ? void 0 : model.capabilities.toSorted()
158336
+ }
158337
+ });
158338
+ }
158339
+ snapshots.sort((a, b) => a.alias.localeCompare(b.alias));
158340
+ return JSON.stringify(snapshots);
158341
+ }
158342
+ function providerModelsEqual(config, nextConfig, providerId, aliasKeys) {
158343
+ return providerModelSnapshot(config, providerId, aliasKeys) === providerModelSnapshot(nextConfig, providerId, aliasKeys);
158344
+ }
158345
+ function providerConfigSnapshot(config, providerId) {
158346
+ return JSON.stringify(config.providers[providerId] ?? null);
158347
+ }
158348
+ function providerConfigEqual(config, nextConfig, providerId) {
158349
+ return providerConfigSnapshot(config, providerId) === providerConfigSnapshot(nextConfig, providerId);
158350
+ }
158351
+ function providerRefreshAliasKeys(config, nextConfig, providerId, aliasPrefix) {
158352
+ const keys = generatedProviderAliasKeys(config, providerId, aliasPrefix);
158353
+ for (const key of providerAliasKeys(nextConfig, providerId)) keys.add(key);
158354
+ return keys;
158355
+ }
158356
+ function preserveUserProviderAliases(config, providerId, refreshedAliasKeys) {
158357
+ const preserved = {};
158358
+ for (const [alias, raw] of Object.entries(config.models ?? {})) {
158359
+ const model = raw;
158360
+ if (model.provider !== providerId || refreshedAliasKeys.has(alias)) continue;
158361
+ preserved[alias] = structuredClone(model);
158362
+ }
158363
+ return preserved;
158364
+ }
158365
+ function restoreProviderAliases(config, aliases) {
158366
+ if (Object.keys(aliases).length === 0) return;
158367
+ config.models = {
158368
+ ...config.models,
158369
+ ...aliases
158370
+ };
158371
+ }
158372
+ function restoreDefaultSelection(config, defaultModel, defaultThinking) {
158373
+ if (defaultModel === void 0 || readModel(config, defaultModel) === void 0) return;
158374
+ config.defaultModel = defaultModel;
158375
+ config.defaultThinking = (readModel(config, defaultModel)?.capabilities ?? []).includes("always_thinking") ? true : defaultThinking;
158376
+ }
158377
+ function clampDanglingDefault(config) {
158378
+ if (config.defaultModel !== void 0 && readModel(config, config.defaultModel) === void 0) {
158379
+ config.defaultModel = void 0;
158380
+ config.defaultThinking = void 0;
158381
+ }
158382
+ }
158383
+ function clearDefaultThinkingWhenDefaultRemoved(config, previousDefaultModel) {
158384
+ if (previousDefaultModel !== void 0 && config.defaultModel === void 0) config.defaultThinking = void 0;
158385
+ }
158386
+ function pickDefaultModel(config, providerId, models) {
158387
+ const firstModel = models[0];
158388
+ if (firstModel === void 0) return "";
158389
+ const existingDefault = config.defaultModel;
158390
+ if (existingDefault !== void 0) {
158391
+ const alias = readModel(config, existingDefault);
158392
+ if (alias !== void 0 && alias.provider === providerId) {
158393
+ const stillAvailable = models.find((m) => m.id === alias.model);
158394
+ if (stillAvailable !== void 0) return stillAvailable.id;
158395
+ }
158396
+ }
158397
+ return firstModel.id;
158398
+ }
158399
+ /**
158400
+ * Refresh remote model metadata for the configured providers and persist any
158401
+ * changes through the host. Handles three provider kinds, in order:
158402
+ *
158403
+ * 1. Managed Kimi Code (OAuth) — `GET /models` against the runtime endpoint.
158404
+ * 2. Open platforms (moonshot-cn, moonshot-ai, …) — platform catalog fetch.
158405
+ * 3. Custom registries (models.dev-style, keyed by `provider.source`).
158406
+ *
158407
+ * Each branch diffs old vs new and only writes when something actually changed
158408
+ * (`removeProvider` then `setConfig`). Failures are collected per-provider and
158409
+ * never abort the whole refresh. Pass `providerId` to scope the refresh to a
158410
+ * single provider; pass `scope: 'oauth'` to refresh only the managed provider.
158411
+ */
158412
+ async function refreshProviderModels(host, options = {}) {
158413
+ const changed = [];
158414
+ const unchanged = [];
158415
+ const failed = [];
158416
+ const scope = options.scope ?? "all";
158417
+ const targetId = options.providerId;
158418
+ let config = await host.getConfig();
158419
+ const managedProvider = readProvider(config, KIMI_CODE_PROVIDER_NAME$1);
158420
+ if ((targetId === void 0 || targetId === "managed:kimi-code") && managedProvider !== void 0 && managedProvider.type === "kimi" && managedProvider.oauth !== void 0) try {
158421
+ const auth = resolveKimiCodeRuntimeAuth({
158422
+ configuredBaseUrl: managedProvider.baseUrl,
158423
+ configuredOAuthRef: managedProvider.oauth
158424
+ });
158425
+ const models = await fetchManagedKimiCodeModels({
158426
+ accessToken: await host.resolveOAuthToken(KIMI_CODE_PROVIDER_NAME$1, auth.oauthRef),
158427
+ baseUrl: auth.baseUrl
158428
+ });
158429
+ if (models.length > 0) {
158430
+ const next = structuredClone(config);
158431
+ applyManagedKimiCodeConfig(next, {
158432
+ models,
158433
+ baseUrl: auth.baseUrl,
158434
+ oauthKey: auth.oauthRef.key,
158435
+ oauthHost: auth.oauthRef.oauthHost,
158436
+ preserveDefaultModel: true
158437
+ });
158438
+ const refreshedAliasKeys = providerRefreshAliasKeys(config, next, KIMI_CODE_PROVIDER_NAME$1, `${KIMI_CODE_PLATFORM_ID}/`);
158439
+ restoreProviderAliases(next, preserveUserProviderAliases(config, KIMI_CODE_PROVIDER_NAME$1, refreshedAliasKeys));
158440
+ restoreDefaultSelection(next, config.defaultModel, config.defaultThinking);
158441
+ clampDanglingDefault(next);
158442
+ clearDefaultThinkingWhenDefaultRemoved(next, config.defaultModel);
158443
+ if (providerModelsEqual(config, next, "managed:kimi-code", refreshedAliasKeys)) unchanged.push(KIMI_CODE_PROVIDER_NAME$1);
158444
+ else {
158445
+ const { added, removed } = computeChanges(collectModelIdsForAliases(config, refreshedAliasKeys), collectModelIdsForAliases(next, refreshedAliasKeys));
158446
+ await host.removeProvider(KIMI_CODE_PROVIDER_NAME$1);
158447
+ config = await host.setConfig({
158448
+ providers: next.providers,
158449
+ models: next.models,
158450
+ defaultModel: next.defaultModel,
158451
+ defaultThinking: next.defaultThinking
158452
+ });
158453
+ changed.push({
158454
+ providerId: KIMI_CODE_PROVIDER_NAME$1,
158455
+ providerName: "Kimi Code",
158456
+ added,
158457
+ removed
158458
+ });
158459
+ }
158460
+ }
158461
+ } catch (error) {
158462
+ failed.push({
158463
+ provider: KIMI_CODE_PROVIDER_NAME$1,
158464
+ reason: error instanceof Error ? error.message : String(error)
158465
+ });
158466
+ }
158467
+ if (scope === "oauth" || targetId === "managed:kimi-code") return {
158468
+ changed,
158469
+ unchanged,
158470
+ failed
158471
+ };
158472
+ const openPlatformIds = Object.keys(config.providers).filter((id) => isOpenPlatformId(id));
158473
+ for (const providerId of openPlatformIds) {
158474
+ if (targetId !== void 0 && targetId !== providerId) continue;
158475
+ const platform = getOpenPlatformById(providerId);
158476
+ if (platform === void 0) continue;
158477
+ const providerConfig = readProvider(config, providerId);
158478
+ if (providerConfig === void 0) continue;
158479
+ const apiKey = providerConfig.apiKey;
158480
+ if (typeof apiKey !== "string" || apiKey.length === 0) continue;
158481
+ try {
158482
+ let models = await fetchOpenPlatformModels(platform, apiKey);
158483
+ models = filterModelsByPrefix(models, platform);
158484
+ if (models.length === 0) continue;
158485
+ const selectedModelId = pickDefaultModel(config, providerId, models);
158486
+ const selectedModel = models.find((m) => m.id === selectedModelId);
158487
+ if (selectedModel === void 0) continue;
158488
+ const next = structuredClone(config);
158489
+ applyOpenPlatformConfig(next, {
158490
+ platform,
158491
+ models,
158492
+ selectedModel,
158493
+ thinking: false,
158494
+ apiKey
158495
+ });
158496
+ const refreshedAliasKeys = providerRefreshAliasKeys(config, next, providerId, `${providerId}/`);
158497
+ restoreProviderAliases(next, preserveUserProviderAliases(config, providerId, refreshedAliasKeys));
158498
+ restoreDefaultSelection(next, config.defaultModel, config.defaultThinking);
158499
+ clampDanglingDefault(next);
158500
+ clearDefaultThinkingWhenDefaultRemoved(next, config.defaultModel);
158501
+ if (providerModelsEqual(config, next, providerId, refreshedAliasKeys)) unchanged.push(providerId);
158502
+ else {
158503
+ const { added, removed } = computeChanges(collectModelIdsForAliases(config, refreshedAliasKeys), collectModelIdsForAliases(next, refreshedAliasKeys));
158504
+ await host.removeProvider(providerId);
158505
+ config = await host.setConfig({
158506
+ providers: next.providers,
158507
+ models: next.models,
158508
+ defaultModel: next.defaultModel,
158509
+ defaultThinking: next.defaultThinking
158510
+ });
158511
+ changed.push({
158512
+ providerId,
158513
+ providerName: platform.name,
158514
+ added,
158515
+ removed
158516
+ });
158517
+ }
158518
+ } catch (error) {
158519
+ failed.push({
158520
+ provider: providerId,
158521
+ reason: error instanceof Error ? error.message : String(error)
158522
+ });
158523
+ }
158524
+ }
158525
+ const customSources = /* @__PURE__ */ new Map();
158526
+ for (const providerId of Object.keys(config.providers)) {
158527
+ if (providerId === "managed:kimi-code") continue;
158528
+ if (isOpenPlatformId(providerId)) continue;
158529
+ const provider = readProvider(config, providerId);
158530
+ if (provider === void 0) continue;
158531
+ const source = readCustomRegistrySource$1(provider);
158532
+ if (source === void 0) continue;
158533
+ const key = customRegistrySourceKey(source);
158534
+ const sourceKey = customRegistrySourceCredentialKey(source);
158535
+ const entry = customSources.get(key);
158536
+ if (entry !== void 0) {
158537
+ if (!entry.sourceKeys.has(sourceKey)) {
158538
+ entry.sources.push(source);
158539
+ entry.sourceKeys.add(sourceKey);
158540
+ }
158541
+ entry.providerIds.push(providerId);
158542
+ } else customSources.set(key, {
158543
+ sources: [source],
158544
+ sourceKeys: new Set([sourceKey]),
158545
+ providerIds: [providerId]
158546
+ });
158547
+ }
158548
+ for (const { sources, providerIds } of customSources.values()) {
158549
+ if (targetId !== void 0 && !providerIds.includes(targetId)) continue;
158550
+ try {
158551
+ const { entries, source } = await fetchCustomRegistryFromSources(sources);
158552
+ const next = structuredClone(config);
158553
+ const changedProviders = [];
158554
+ const providersToRemoveBeforeSet = /* @__PURE__ */ new Set();
158555
+ let hasUnreportedConfigChange = false;
158556
+ const remoteEntries = Object.values(entries);
158557
+ const remoteEntriesByProviderId = new Map(remoteEntries.map((entry) => [entry.id, entry]));
158558
+ const providerIdsToSync = new Set(providerIds);
158559
+ if (targetId === void 0) for (const entry of remoteEntries) providerIdsToSync.add(entry.id);
158560
+ for (const providerId of providerIdsToSync) {
158561
+ if (targetId !== void 0 && providerId !== targetId) continue;
158562
+ const entry = remoteEntriesByProviderId.get(providerId);
158563
+ if (entry === void 0) {
158564
+ const oldIds = collectModelIdsForAliases(config, providerAliasKeys(config, providerId));
158565
+ removeCustomRegistryProvider(next, providerId);
158566
+ changedProviders.push({
158567
+ providerId,
158568
+ providerName: providerId,
158569
+ added: 0,
158570
+ removed: oldIds.size
158571
+ });
158572
+ providersToRemoveBeforeSet.add(providerId);
158573
+ continue;
158574
+ }
158575
+ const existed = config.providers[providerId] !== void 0;
158576
+ applyCustomRegistryProvider(next, entry, source);
158577
+ const refreshedAliasKeys = providerRefreshAliasKeys(config, next, providerId, `${providerId}/`);
158578
+ if (existed) restoreProviderAliases(next, preserveUserProviderAliases(config, providerId, refreshedAliasKeys));
158579
+ if (existed && providerModelsEqual(config, next, providerId, refreshedAliasKeys) && providerConfigEqual(config, next, providerId)) unchanged.push(providerId);
158580
+ else if (existed && providerModelsEqual(config, next, providerId, refreshedAliasKeys)) {
158581
+ unchanged.push(providerId);
158582
+ providersToRemoveBeforeSet.add(providerId);
158583
+ hasUnreportedConfigChange = true;
158584
+ } else {
158585
+ const { added, removed } = computeChanges(collectModelIdsForAliases(config, refreshedAliasKeys), collectModelIdsForAliases(next, refreshedAliasKeys));
158586
+ changedProviders.push({
158587
+ providerId,
158588
+ providerName: entry.name || providerId,
158589
+ added,
158590
+ removed
158591
+ });
158592
+ if (existed) providersToRemoveBeforeSet.add(providerId);
158593
+ }
158594
+ }
158595
+ if (changedProviders.length > 0 || hasUnreportedConfigChange) {
158596
+ restoreDefaultSelection(next, config.defaultModel, config.defaultThinking);
158597
+ clampDanglingDefault(next);
158598
+ clearDefaultThinkingWhenDefaultRemoved(next, config.defaultModel);
158599
+ for (const providerId of providersToRemoveBeforeSet) await host.removeProvider(providerId);
158600
+ config = await host.setConfig({
158601
+ providers: next.providers,
158602
+ models: next.models,
158603
+ defaultModel: next.defaultModel,
158604
+ defaultThinking: next.defaultThinking
158605
+ });
158606
+ for (const change of changedProviders) changed.push({
158607
+ providerId: change.providerId,
158608
+ providerName: change.providerName,
158609
+ added: change.added,
158610
+ removed: change.removed
158611
+ });
158612
+ }
158613
+ } catch (error) {
158614
+ const reportedIds = targetId !== void 0 ? [targetId] : providerIds;
158615
+ for (const providerId of reportedIds) failed.push({
158616
+ provider: providerId,
158617
+ reason: error instanceof Error ? error.message : String(error)
158618
+ });
158619
+ }
158620
+ }
158621
+ return {
158622
+ changed,
158623
+ unchanged,
158624
+ failed
158625
+ };
158626
+ }
158627
+ //#endregion
158257
158628
  //#region ../../packages/agent-core/src/session/provider-manager.ts
158258
158629
  var ProviderManager = class {
158259
158630
  options;
@@ -160889,16 +161260,12 @@ function telemetryErrorReason(error) {
160889
161260
  }
160890
161261
  function clientTelemetryProperties(client) {
160891
161262
  if (client === void 0) return {};
160892
- const properties = {};
160893
- addNonEmpty(properties, "client_id", client.id);
160894
- addNonEmpty(properties, "client_name", client.name);
160895
- addNonEmpty(properties, "client_version", client.version);
160896
- addNonEmpty(properties, "ui_mode", client.uiMode);
160897
- return properties;
160898
- }
160899
- function addNonEmpty(target, key, value) {
160900
- const trimmed = value?.trim();
160901
- if (trimmed !== void 0 && trimmed.length > 0) target[key] = trimmed;
161263
+ return {
161264
+ client_id: client.id ?? null,
161265
+ client_name: client.name ?? null,
161266
+ client_version: client.version ?? null,
161267
+ ui_mode: client.uiMode ?? null
161268
+ };
160902
161269
  }
160903
161270
  async function resumeSessionResult(summary, session, warning) {
160904
161271
  const api = new SessionAPIImpl(session);
@@ -163600,10 +163967,12 @@ let FsSearchService = class FsSearchService extends Disposable {
163600
163967
  gitignoreCache = /* @__PURE__ */ new Map();
163601
163968
  rgPath = void 0;
163602
163969
  rgMissingWarned = false;
163603
- constructor(sessions, logger) {
163970
+ telemetry;
163971
+ constructor(telemetry, sessions, logger) {
163604
163972
  super();
163605
163973
  this.sessions = sessions;
163606
163974
  this.logger = logger;
163975
+ this.telemetry = telemetry;
163607
163976
  }
163608
163977
  dispose() {
163609
163978
  this.gitignoreCache.clear();
@@ -163650,6 +164019,7 @@ let FsSearchService = class FsSearchService extends Disposable {
163650
164019
  try {
163651
164020
  const rg = await this.probeRg();
163652
164021
  if (rg !== null) return await this.grepWithRg(rg, realCwd, req, abortController.signal, startedAt);
164022
+ this.telemetry.track("fs_grep_node_fallback", { reason: "rg_missing" });
163653
164023
  return await this.grepWithNode(realCwd, req, abortController.signal, startedAt);
163654
164024
  } finally {
163655
164025
  clearTimeout(timeoutHandle);
@@ -163920,7 +164290,7 @@ let FsSearchService = class FsSearchService extends Disposable {
163920
164290
  return ig;
163921
164291
  }
163922
164292
  };
163923
- FsSearchService = __decorate([__decorateParam(0, ISessionService), __decorateParam(1, ILogService)], FsSearchService);
164293
+ FsSearchService = __decorate([__decorateParam(1, ISessionService), __decorateParam(2, ILogService)], FsSearchService);
163924
164294
  function computeFuzzyScore(name, queryLower) {
163925
164295
  if (queryLower.length === 0) return 0;
163926
164296
  const nameLower = name.toLowerCase();
@@ -164034,7 +164404,7 @@ async function whichBinary(name) {
164034
164404
  }
164035
164405
  return null;
164036
164406
  }
164037
- registerSingleton(IFsSearchService, FsSearchService, 1);
164407
+ registerSingleton(IFsSearchService, new SyncDescriptor(FsSearchService, [noopTelemetryClient], true));
164038
164408
  //#endregion
164039
164409
  //#region ../../packages/agent-core/src/services/fs/fsGit.ts
164040
164410
  var FsGitUnavailableError = class extends Error {
@@ -167252,15 +167622,20 @@ function globalDefaultForProvider(config, providerId) {
167252
167622
  var _ModelCatalogService;
167253
167623
  let ModelCatalogService = _ModelCatalogService = class ModelCatalogService extends Disposable {
167254
167624
  core;
167625
+ eventService;
167255
167626
  _serviceBrand;
167256
167627
  _authFacade;
167257
- constructor(env, core) {
167628
+ /** Serializes refresh runs so a scheduled refresh and a manual one (or two
167629
+ * manual ones with different options) never race on writing config.toml. */
167630
+ _refreshChain = Promise.resolve();
167631
+ constructor(env, core, eventService) {
167258
167632
  super();
167259
167633
  this.core = core;
167634
+ this.eventService = eventService;
167260
167635
  this._authFacade = createManagedAuthFacade(env);
167261
167636
  }
167262
- static _createForTest(env, core, authFacade) {
167263
- const service = new _ModelCatalogService(env, core);
167637
+ static _createForTest(env, core, authFacade, eventService = noopEventService) {
167638
+ const service = new _ModelCatalogService(env, core, eventService);
167264
167639
  service._authFacade = authFacade;
167265
167640
  return service;
167266
167641
  }
@@ -167289,74 +167664,44 @@ let ModelCatalogService = _ModelCatalogService = class ModelCatalogService exten
167289
167664
  };
167290
167665
  }
167291
167666
  async refreshOAuthProviderModels() {
167292
- let config = await this._readConfig();
167293
- const changed = [];
167294
- const unchanged = [];
167295
- const failed = [];
167296
- const provider = config.providers?.[KIMI_CODE_PROVIDER_NAME$1];
167297
- if (provider?.type !== "kimi" || provider.oauth === void 0) return {
167298
- changed,
167299
- unchanged,
167300
- failed
167301
- };
167302
- try {
167303
- const auth = resolveKimiCodeRuntimeAuth({
167304
- configuredBaseUrl: provider.baseUrl,
167305
- configuredOAuthRef: provider.oauth
167306
- });
167307
- const tokenProvider = this._authFacade.resolveOAuthTokenProvider(KIMI_CODE_PROVIDER_NAME$1, auth.oauthRef);
167308
- if (tokenProvider === void 0) throw new Error("OAuth token provider is not configured.");
167309
- const models = await fetchManagedKimiCodeModels({
167310
- accessToken: await tokenProvider.getAccessToken(),
167311
- baseUrl: auth.baseUrl,
167312
- headers: this.core.kimiRequestHeaders
167313
- });
167314
- if (models.length === 0) return {
167315
- changed,
167316
- unchanged,
167317
- failed
167318
- };
167319
- const next = structuredClone(config);
167320
- applyManagedKimiCodeConfig(next, {
167321
- models,
167322
- baseUrl: auth.baseUrl,
167323
- oauthKey: auth.oauthRef.key,
167324
- oauthHost: auth.oauthRef.oauthHost,
167325
- preserveDefaultModel: true
167326
- });
167327
- const refreshedAliasKeys = providerRefreshAliasKeys$1(config, next, KIMI_CODE_PROVIDER_NAME$1, `${KIMI_CODE_PLATFORM_ID}/`);
167328
- restoreProviderAliases$1(next, preserveUserProviderAliases$1(config, KIMI_CODE_PROVIDER_NAME$1, refreshedAliasKeys));
167329
- restoreDefaultSelection$1(next, config.defaultModel, config.defaultThinking);
167330
- clampDanglingDefault$1(next);
167331
- if (providerModelsEqual$1(config, next, "managed:kimi-code", refreshedAliasKeys)) unchanged.push(KIMI_CODE_PROVIDER_NAME$1);
167332
- else {
167333
- const { added, removed } = computeChanges$1(collectModelIdsForAliases$1(config, refreshedAliasKeys), collectModelIdsForAliases$1(next, refreshedAliasKeys));
167334
- await this.core.rpc.removeKimiProvider({ providerId: KIMI_CODE_PROVIDER_NAME$1 });
167335
- await this.core.rpc.setKimiConfig({
167336
- providers: next.providers,
167337
- models: next.models,
167338
- defaultModel: next.defaultModel,
167339
- defaultThinking: next.defaultThinking
167340
- });
167341
- changed.push({
167342
- provider_id: KIMI_CODE_PROVIDER_NAME$1,
167343
- provider_name: "Kimi Code",
167344
- added,
167345
- removed
167346
- });
167347
- }
167348
- } catch (err) {
167349
- failed.push({
167350
- provider: KIMI_CODE_PROVIDER_NAME$1,
167351
- reason: err instanceof Error ? err.message : String(err)
167352
- });
167667
+ return this.refreshProviderModels({ scope: "oauth" });
167668
+ }
167669
+ refreshProviderModels(options = {}) {
167670
+ const run = this._refreshChain.then(() => this._doRefreshProviderModels(options));
167671
+ this._refreshChain = run.then(() => void 0, () => void 0);
167672
+ return run;
167673
+ }
167674
+ async _doRefreshProviderModels(options) {
167675
+ if (options.providerId !== void 0) {
167676
+ if ((await this._readConfig()).providers?.[options.providerId] === void 0) throw new ProviderNotFoundError(options.providerId);
167353
167677
  }
167678
+ const response = mapRefreshResult(await refreshProviderModels(this._buildRefreshHost(), {
167679
+ scope: options.scope,
167680
+ providerId: options.providerId
167681
+ }));
167682
+ if (response.changed.length > 0) this.eventService.publish({
167683
+ type: "event.model_catalog.changed",
167684
+ agentId: "main",
167685
+ sessionId: "__global__",
167686
+ changed: response.changed,
167687
+ unchanged: response.unchanged,
167688
+ failed: response.failed
167689
+ });
167690
+ return response;
167691
+ }
167692
+ _buildRefreshHost() {
167354
167693
  return {
167355
- changed,
167356
- unchanged,
167357
- failed
167694
+ getConfig: () => this._readConfig(),
167695
+ removeProvider: (providerId) => this.core.rpc.removeKimiProvider({ providerId }),
167696
+ setConfig: (patch) => this.core.rpc.setKimiConfig(patch),
167697
+ resolveOAuthToken: (providerName, oauthRef) => this._resolveOAuthToken(providerName, oauthRef)
167358
167698
  };
167359
167699
  }
167700
+ async _resolveOAuthToken(providerName, oauthRef) {
167701
+ const tokenProvider = this._authFacade.resolveOAuthTokenProvider(providerName, oauthRef);
167702
+ if (tokenProvider === void 0) throw new Error("OAuth token provider is not configured.");
167703
+ return tokenProvider.getAccessToken();
167704
+ }
167360
167705
  async _readConfig() {
167361
167706
  return this.core.rpc.getKimiConfig({ reload: true });
167362
167707
  }
@@ -167375,7 +167720,26 @@ let ModelCatalogService = _ModelCatalogService = class ModelCatalogService exten
167375
167720
  }
167376
167721
  }
167377
167722
  };
167378
- ModelCatalogService = _ModelCatalogService = __decorate([__decorateParam(0, IEnvironmentService), __decorateParam(1, ICoreProcessService)], ModelCatalogService);
167723
+ ModelCatalogService = _ModelCatalogService = __decorate([
167724
+ __decorateParam(0, IEnvironmentService),
167725
+ __decorateParam(1, ICoreProcessService),
167726
+ __decorateParam(2, IEventService)
167727
+ ], ModelCatalogService);
167728
+ function mapRefreshResult(result) {
167729
+ return {
167730
+ changed: result.changed.map((change) => ({
167731
+ provider_id: change.providerId,
167732
+ provider_name: change.providerName,
167733
+ added: change.added,
167734
+ removed: change.removed
167735
+ })),
167736
+ unchanged: [...result.unchanged],
167737
+ failed: result.failed.map((failure) => ({
167738
+ provider: failure.provider,
167739
+ reason: failure.reason
167740
+ }))
167741
+ };
167742
+ }
167379
167743
  function hasConfiguredApiKey(provider) {
167380
167744
  if (nonEmpty$1(provider.apiKey) !== void 0) return true;
167381
167745
  switch (provider.type) {
@@ -167388,89 +167752,16 @@ function hasConfiguredApiKey(provider) {
167388
167752
  }
167389
167753
  return false;
167390
167754
  }
167391
- function collectModelIdsForAliases$1(config, aliasKeys) {
167392
- const ids = /* @__PURE__ */ new Set();
167393
- for (const aliasKey of aliasKeys) {
167394
- const alias = config.models?.[aliasKey];
167395
- if (alias !== void 0 && alias.model.length > 0) ids.add(alias.model);
167396
- }
167397
- return ids;
167398
- }
167399
- function providerAliasKeys$1(config, providerId) {
167400
- const keys = /* @__PURE__ */ new Set();
167401
- for (const [alias, model] of Object.entries(config.models ?? {})) if (model.provider === providerId) keys.add(alias);
167402
- return keys;
167403
- }
167404
- function generatedProviderAliasKeys$1(config, providerId, aliasPrefix) {
167405
- const keys = /* @__PURE__ */ new Set();
167406
- for (const [alias, model] of Object.entries(config.models ?? {})) if (model.provider === providerId && alias.startsWith(aliasPrefix)) keys.add(alias);
167407
- return keys;
167408
- }
167409
- function computeChanges$1(oldIds, newIds) {
167410
- let added = 0;
167411
- for (const id of newIds) if (!oldIds.has(id)) added++;
167412
- let removed = 0;
167413
- for (const id of oldIds) if (!newIds.has(id)) removed++;
167414
- return {
167415
- added,
167416
- removed
167417
- };
167418
- }
167419
- function providerModelsEqual$1(config, nextConfig, providerId, aliasKeys) {
167420
- return providerModelSnapshot$1(config, providerId, aliasKeys) === providerModelSnapshot$1(nextConfig, providerId, aliasKeys);
167421
- }
167422
- function providerModelSnapshot$1(config, providerId, aliasKeys) {
167423
- const snapshots = [];
167424
- for (const alias of aliasKeys) {
167425
- const model = config.models?.[alias];
167426
- if (model === void 0 || model.provider !== providerId) continue;
167427
- snapshots.push({
167428
- alias,
167429
- model: {
167430
- ...model,
167431
- capabilities: model.capabilities === void 0 ? void 0 : model.capabilities.toSorted()
167432
- }
167433
- });
167434
- }
167435
- snapshots.sort((a, b) => a.alias.localeCompare(b.alias));
167436
- return JSON.stringify(snapshots);
167437
- }
167438
- function providerRefreshAliasKeys$1(config, nextConfig, providerId, aliasPrefix) {
167439
- const keys = generatedProviderAliasKeys$1(config, providerId, aliasPrefix);
167440
- for (const key of providerAliasKeys$1(nextConfig, providerId)) keys.add(key);
167441
- return keys;
167442
- }
167443
- function preserveUserProviderAliases$1(config, providerId, refreshedAliasKeys) {
167444
- const preserved = {};
167445
- for (const [alias, model] of Object.entries(config.models ?? {})) {
167446
- if (model.provider !== providerId || refreshedAliasKeys.has(alias)) continue;
167447
- preserved[alias] = structuredClone(model);
167448
- }
167449
- return preserved;
167450
- }
167451
- function restoreProviderAliases$1(config, aliases) {
167452
- if (Object.keys(aliases).length === 0) return;
167453
- config.models = {
167454
- ...config.models,
167455
- ...aliases
167456
- };
167457
- }
167458
- function restoreDefaultSelection$1(config, defaultModel, defaultThinking) {
167459
- if (defaultModel === void 0 || config.models?.[defaultModel] === void 0) return;
167460
- config.defaultModel = defaultModel;
167461
- config.defaultThinking = (config.models[defaultModel]?.capabilities ?? []).includes("always_thinking") ? true : defaultThinking;
167462
- }
167463
- function clampDanglingDefault$1(config) {
167464
- if (config.defaultModel !== void 0 && config.models?.[config.defaultModel] === void 0) {
167465
- config.defaultModel = void 0;
167466
- config.defaultThinking = void 0;
167467
- }
167468
- }
167469
167755
  function nonEmpty$1(value) {
167470
167756
  if (value === void 0) return void 0;
167471
167757
  const trimmed = value.trim();
167472
167758
  return trimmed.length === 0 ? void 0 : trimmed;
167473
167759
  }
167760
+ const noopEventService = {
167761
+ _serviceBrand: void 0,
167762
+ onDidPublish: () => ({ dispose: () => void 0 }),
167763
+ publish: () => void 0
167764
+ };
167474
167765
  registerSingleton(IModelCatalogService, ModelCatalogService, 1);
167475
167766
  //#endregion
167476
167767
  //#region ../../packages/agent-core/src/services/config/config.ts
@@ -170793,6 +171084,7 @@ var KimiHarness = class {
170793
171084
  withTelemetryContext$1(this.telemetry, { sessionId: eventSessionId }).track("session_started", {
170794
171085
  ...this.sessionStartedProperties,
170795
171086
  ...sessionScoped,
171087
+ client_id: null,
170796
171088
  client_name: this.identity?.userAgentProduct ?? null,
170797
171089
  client_version: this.identity?.version ?? null,
170798
171090
  ui_mode: this.uiMode,
@@ -193111,7 +193403,7 @@ var AcpSession = class {
193111
193403
  }
193112
193404
  }));
193113
193405
  if (answer === null) this.emitTelemetry("question_dismissed");
193114
- else this.emitTelemetry("question_answered");
193406
+ else this.emitTelemetry("question_answered", { answered: Object.keys(answer).length });
193115
193407
  return answer;
193116
193408
  } catch (err) {
193117
193409
  log.warn("acp: requestPermission (question) failed; dismissing", {
@@ -194959,7 +195251,7 @@ async function handleProviderAdd$1(deps, url, opts) {
194959
195251
  const addedProviderIds = [];
194960
195252
  let modelCount = 0;
194961
195253
  for (const entry of entryList) {
194962
- applyCustomRegistryProvider(asManaged$1(config), entry, source);
195254
+ applyCustomRegistryProvider(asManaged(config), entry, source);
194963
195255
  addedProviderIds.push(entry.id);
194964
195256
  modelCount += Object.keys(entry.models).length;
194965
195257
  }
@@ -195201,7 +195493,7 @@ function resolveApiKey(flag, env) {
195201
195493
  const fromEnv = env["KIMI_REGISTRY_API_KEY"];
195202
195494
  if (typeof fromEnv === "string" && fromEnv.length > 0) return fromEnv;
195203
195495
  }
195204
- function asManaged$1(config) {
195496
+ function asManaged(config) {
195205
195497
  return config;
195206
195498
  }
195207
195499
  function providerSourceLabel(provider) {
@@ -224670,7 +224962,7 @@ function extractSessionId(event) {
224670
224962
  if (typeof snake === "string" && snake.length > 0) return snake;
224671
224963
  }
224672
224964
  function isGlobalSessionEvent(type) {
224673
- return type === "event.session.created" || type === "event.session.status_changed" || type === "session.meta.updated" || type === "event.config.changed" || type === "event.workspace.created" || type === "event.workspace.updated" || type === "event.workspace.deleted";
224965
+ return type === "event.session.created" || type === "event.session.status_changed" || type === "session.meta.updated" || type === "event.config.changed" || type === "event.model_catalog.changed" || type === "event.workspace.created" || type === "event.workspace.updated" || type === "event.workspace.deleted";
224674
224966
  }
224675
224967
  /** Session ids are ULID-ish, but never trust an id used as a path segment. */
224676
224968
  function sanitizeFileName(sid) {
@@ -228304,6 +228596,8 @@ function parseActionSuffix(opts) {
228304
228596
  //#region ../../packages/server/src/routes/modelCatalog.ts
228305
228597
  const providerIdParamSchema = object({ provider_id: string().min(1) });
228306
228598
  const modelActionTailParamSchema = object({ tail: string().min(1) });
228599
+ const providerActionTailParamSchema = object({ tail: string().min(1) });
228600
+ const providerCollectionActionParamSchema = object({ action: string().min(1) });
228307
228601
  function registerModelCatalogRoutes(app, ix) {
228308
228602
  const listModelsRoute = defineRoute({
228309
228603
  method: "GET",
@@ -228359,18 +228653,63 @@ function registerModelCatalogRoutes(app, ix) {
228359
228653
  reply.send(okEnvelope({ items }, req.id));
228360
228654
  });
228361
228655
  app.get(listProvidersRoute.path, listProvidersRoute.options, listProvidersRoute.handler);
228362
- const refreshOAuthProvidersRoute = defineRoute({
228656
+ const refreshProvidersRoute = defineRoute({
228363
228657
  method: "POST",
228364
- path: "/providers:refresh_oauth",
228365
- success: { data: refreshOAuthProviderModelsResponseSchema },
228366
- description: "Refresh OAuth-backed provider model metadata",
228658
+ path: "/providers:action",
228659
+ params: providerCollectionActionParamSchema,
228660
+ success: { data: refreshProviderModelsResponseSchema },
228661
+ errors: { [ErrorCode$1.VALIDATION_FAILED]: {} },
228662
+ description: "Refresh provider model metadata. Use `:refresh` for all providers or `:refresh_oauth` for OAuth-backed providers only.",
228367
228663
  tags: ["providers"],
228368
- operationId: "refreshOAuthProviderModels"
228664
+ operationId: "refreshProviders"
228369
228665
  }, async (req, reply) => {
228370
- const result = await ix.invokeFunction((a) => a.get(IModelCatalogService).refreshOAuthProviderModels());
228371
- reply.send(okEnvelope(result, req.id));
228666
+ const raw = req.params.action;
228667
+ const action = raw.startsWith(":") ? raw.slice(1) : raw;
228668
+ if (action === "refresh_oauth") {
228669
+ const result = await ix.invokeFunction((a) => a.get(IModelCatalogService).refreshOAuthProviderModels());
228670
+ reply.send(okEnvelope(result, req.id));
228671
+ return;
228672
+ }
228673
+ if (action === "refresh") {
228674
+ const result = await ix.invokeFunction((a) => a.get(IModelCatalogService).refreshProviderModels({ scope: "all" }));
228675
+ reply.send(okEnvelope(result, req.id));
228676
+ return;
228677
+ }
228678
+ reply.send(errEnvelope(ErrorCode$1.VALIDATION_FAILED, `unsupported action: ${raw}`, req.id));
228372
228679
  });
228373
- app.post(refreshOAuthProvidersRoute.path, refreshOAuthProvidersRoute.options, refreshOAuthProvidersRoute.handler);
228680
+ app.post(refreshProvidersRoute.path, refreshProvidersRoute.options, refreshProvidersRoute.handler);
228681
+ const refreshProviderRoute = defineRoute({
228682
+ method: "POST",
228683
+ path: "/providers/{tail}",
228684
+ params: providerActionTailParamSchema,
228685
+ success: { data: refreshProviderModelsResponseSchema },
228686
+ errors: {
228687
+ [ErrorCode$1.VALIDATION_FAILED]: {},
228688
+ [ErrorCode$1.PROVIDER_NOT_FOUND]: {}
228689
+ },
228690
+ description: "Refresh model metadata for a single provider",
228691
+ tags: ["providers"],
228692
+ operationId: "refreshProvider"
228693
+ }, async (req, reply) => {
228694
+ try {
228695
+ const { tail } = req.params;
228696
+ const parsed = parseActionSuffix({
228697
+ tail,
228698
+ allowedActions: ["refresh"],
228699
+ resourceLabel: "provider"
228700
+ });
228701
+ if (parsed.kind !== "action") {
228702
+ const message = parsed.kind === "invalid" ? parsed.reason : `unsupported action: ${tail}`;
228703
+ reply.send(errEnvelope(ErrorCode$1.VALIDATION_FAILED, message, req.id));
228704
+ return;
228705
+ }
228706
+ const result = await ix.invokeFunction((a) => a.get(IModelCatalogService).refreshProviderModels({ providerId: parsed.id }));
228707
+ reply.send(okEnvelope(result, req.id));
228708
+ } catch (err) {
228709
+ sendMappedError$8(reply, req.id, err);
228710
+ }
228711
+ });
228712
+ app.post(refreshProviderRoute.path, refreshProviderRoute.options, refreshProviderRoute.handler);
228374
228713
  const getProviderRoute = defineRoute({
228375
228714
  method: "GET",
228376
228715
  path: "/providers/{provider_id}",
@@ -230639,13 +230978,100 @@ function registerHealthRoute(apiV1) {
230639
230978
  });
230640
230979
  }
230641
230980
  //#endregion
230981
+ //#region ../../packages/server/src/services/modelCatalog/modelCatalogRefreshScheduler.ts
230982
+ /**
230983
+ * Periodic background refresh of provider model metadata for a long-lived
230984
+ * daemon. The original CLI refreshed `/models` at startup; once the server
230985
+ * became a daemon that started once and ran for days, the on-disk catalog went
230986
+ * stale. This scheduler restores "stays fresh" behavior: it refreshes once on
230987
+ * start and then on a configurable interval, delegating the actual work to
230988
+ * `IModelCatalogService.refreshProviderModels` (which serializes concurrent
230989
+ * runs, persists changes, and publishes `event.model_catalog.changed`).
230990
+ *
230991
+ * This is a server-local service (only the daemon is long-lived); the CLI uses
230992
+ * the same underlying refresh orchestrator but triggers it on demand.
230993
+ */
230994
+ const DEFAULT_REFRESH_INTERVAL_MS = 360 * 60 * 1e3;
230995
+ const INTERVAL_ENV = "KIMI_CODE_MODEL_CATALOG_REFRESH_INTERVAL_MS";
230996
+ const REFRESH_ON_START_ENV = "KIMI_CODE_MODEL_CATALOG_REFRESH_ON_START";
230997
+ const IModelCatalogRefreshScheduler = createDecorator("modelCatalogRefreshScheduler");
230998
+ let ModelCatalogRefreshScheduler = class ModelCatalogRefreshScheduler extends Disposable {
230999
+ modelCatalog;
231000
+ core;
231001
+ logger;
231002
+ _serviceBrand;
231003
+ _timer;
231004
+ _started = false;
231005
+ constructor(modelCatalog, core, logger) {
231006
+ super();
231007
+ this.modelCatalog = modelCatalog;
231008
+ this.core = core;
231009
+ this.logger = logger;
231010
+ }
231011
+ async start() {
231012
+ if (this._started) return;
231013
+ this._started = true;
231014
+ const config = await this.core.rpc.getKimiConfig({ reload: true });
231015
+ const intervalMs = resolveIntervalMs(config.modelCatalog?.refreshIntervalMs);
231016
+ if (resolveRefreshOnStart(config.modelCatalog?.refreshOnStart)) this._refresh("startup");
231017
+ if (intervalMs > 0) {
231018
+ this._timer = setInterval(() => void this._refresh("interval"), intervalMs);
231019
+ this._timer.unref?.();
231020
+ this.logger.info({ intervalMs }, "provider-model catalog auto-refresh enabled");
231021
+ }
231022
+ }
231023
+ async _refresh(trigger) {
231024
+ try {
231025
+ const result = await this.modelCatalog.refreshProviderModels({ scope: "all" });
231026
+ if (result.failed.length > 0) this.logger.warn({
231027
+ trigger,
231028
+ failed: result.failed
231029
+ }, "provider-model catalog refresh completed with failures");
231030
+ } catch (error) {
231031
+ this.logger.warn({
231032
+ trigger,
231033
+ err: error instanceof Error ? error.message : String(error)
231034
+ }, "provider-model catalog refresh failed");
231035
+ }
231036
+ }
231037
+ dispose() {
231038
+ if (this._timer !== void 0) {
231039
+ clearInterval(this._timer);
231040
+ this._timer = void 0;
231041
+ }
231042
+ super.dispose();
231043
+ }
231044
+ };
231045
+ ModelCatalogRefreshScheduler = __decorate([
231046
+ __decorateParam(0, IModelCatalogService),
231047
+ __decorateParam(1, ICoreProcessService),
231048
+ __decorateParam(2, ILogService)
231049
+ ], ModelCatalogRefreshScheduler);
231050
+ function resolveIntervalMs(configValue) {
231051
+ const raw = process.env[INTERVAL_ENV];
231052
+ if (raw !== void 0 && raw.trim().length > 0) {
231053
+ const parsed = Number(raw);
231054
+ if (Number.isFinite(parsed) && parsed >= 0) return parsed;
231055
+ }
231056
+ return configValue ?? DEFAULT_REFRESH_INTERVAL_MS;
231057
+ }
231058
+ function resolveRefreshOnStart(configValue) {
231059
+ const raw = process.env[REFRESH_ON_START_ENV];
231060
+ if (raw !== void 0 && raw.trim().length > 0) {
231061
+ const normalized = raw.trim().toLowerCase();
231062
+ return normalized === "1" || normalized === "true" || normalized === "yes";
231063
+ }
231064
+ return configValue ?? true;
231065
+ }
231066
+ //#endregion
230642
231067
  //#region ../../packages/server/src/services/serviceCollection.ts
230643
231068
  function createServerServiceCollection(input) {
230644
231069
  const { server, app, pinoLogger, envService } = input;
230645
231070
  const snapshotConfig = loadSnapshotConfig();
230646
- const services = new ServiceCollection(...getSingletonServiceDescriptors(), [IConnectionRegistry, new SyncDescriptor(ConnectionRegistry, [], false)], [ISessionClientsService, new SyncDescriptor(SessionClientsService, [], false)], [IWSBroadcastService, new SyncDescriptor(WSBroadcastService, [], false)], [IApprovalService, new SyncDescriptor(ApprovalService, [], false)], [IQuestionService, new SyncDescriptor(QuestionService, [], false)]);
231071
+ const services = new ServiceCollection(...getSingletonServiceDescriptors(), [IConnectionRegistry, new SyncDescriptor(ConnectionRegistry, [], false)], [ISessionClientsService, new SyncDescriptor(SessionClientsService, [], false)], [IWSBroadcastService, new SyncDescriptor(WSBroadcastService, [], false)], [IModelCatalogRefreshScheduler, new SyncDescriptor(ModelCatalogRefreshScheduler, [], false)], [IApprovalService, new SyncDescriptor(ApprovalService, [], false)], [IQuestionService, new SyncDescriptor(QuestionService, [], false)]);
230647
231072
  if (snapshotConfig.mode !== "legacy") services.set(ISnapshotService, new SyncDescriptor(SnapshotService, [], false));
230648
231073
  services.set(ILogService, new PinoLogger(pinoLogger));
231074
+ services.set(IFsSearchService, new SyncDescriptor(FsSearchService, [server.coreProcessOptions?.telemetry ?? noopTelemetryClient], true));
230649
231075
  services.set(IRestGateway, new FastifyRestGateway(app));
230650
231076
  services.set(IEnvironmentService, envService);
230651
231077
  services.set(IWSGateway, new SyncDescriptor(WSGateway, [server.wsGatewayOptions ?? {}], false));
@@ -241163,6 +241589,7 @@ async function startServer(opts) {
241163
241589
  a.get(IAuthSummaryService);
241164
241590
  a.get(IOAuthService);
241165
241591
  a.get(IModelCatalogService);
241592
+ a.get(IModelCatalogRefreshScheduler).start().catch((err) => log.error({ err }, "failed to start provider-model refresh scheduler"));
241166
241593
  const promptService = a.get(IPromptService);
241167
241594
  const terminalService = a.get(ITerminalService);
241168
241595
  wsGw.setAbortHandler({
@@ -242570,10 +242997,7 @@ async function runServerInProcess(options, mode, onReady) {
242570
242997
  } : void 0
242571
242998
  }
242572
242999
  });
242573
- track("server_started", {
242574
- ui_mode: "web",
242575
- daemon: mode.daemon
242576
- });
243000
+ track("server_started", { daemon: mode.daemon });
242577
243001
  process.once("SIGINT", () => {
242578
243002
  shutdown("SIGINT");
242579
243003
  });
@@ -248274,6 +248698,7 @@ async function handleKimiCodeOAuthLogin(host) {
248274
248698
  }
248275
248699
  host.track("login", {
248276
248700
  provider: DEFAULT_OAUTH_PROVIDER_NAME,
248701
+ method: "oauth",
248277
248702
  already_logged_in: alreadyLoggedIn
248278
248703
  });
248279
248704
  if (alreadyLoggedIn) host.showStatus("Already logged in. Model configuration refreshed.");
@@ -253414,7 +253839,7 @@ var CustomRegistryImportDialogComponent = class extends Container {
253414
253839
  const ADD_ROW_LABEL = "[ Add New Platform ]";
253415
253840
  const PAGE_SIZE = 8;
253416
253841
  const HEADER_HINT = "↑↓ navigate · D delete · Esc cancel";
253417
- function readCustomRegistrySource$1(provider) {
253842
+ function readCustomRegistrySource(provider) {
253418
253843
  if (typeof provider !== "object" || provider === null) return void 0;
253419
253844
  const source = provider.source;
253420
253845
  if (typeof source !== "object" || source === null) return void 0;
@@ -253469,7 +253894,7 @@ function buildRows(opts) {
253469
253894
  continue;
253470
253895
  }
253471
253896
  const baseUrl = typeof cfg === "object" && cfg !== null && "baseUrl" in cfg && typeof cfg.baseUrl === "string" ? cfg.baseUrl : void 0;
253472
- const customSource = readCustomRegistrySource$1(cfg);
253897
+ const customSource = readCustomRegistrySource(cfg);
253473
253898
  if (customSource !== void 0) {
253474
253899
  const key = `${customSource.url}${customSource.apiKey}`;
253475
253900
  const existingIdx = customRegistryIndex.get(key);
@@ -317103,7 +317528,7 @@ function extractKeyArgument(toolName, args, workspaceDir) {
317103
317528
  let summary = pattern;
317104
317529
  const path = args["path"];
317105
317530
  if (typeof path === "string" && path.length > 0) summary += ` · ${makeWorkspaceRelativePath(path, workspaceDir)}`;
317106
- if (args["include_dirs"] === false) summary += " · no dirs";
317531
+ if (args["include_ignored"] === true) summary += " · include ignored";
317107
317532
  return truncateArgValue("pattern", summary);
317108
317533
  }
317109
317534
  const candidates = keyMap[toolName] ?? Object.keys(args);
@@ -323020,7 +323445,7 @@ var StatusMessageComponent = class extends Container {
323020
323445
  super.invalidate();
323021
323446
  }
323022
323447
  renderText() {
323023
- return (this.color === void 0 ? currentTheme.fg("textDim", this.content) : currentTheme.fg(this.color, this.content)).split("\n").map((line) => ` ${line}`).join("\n");
323448
+ return (this.color === void 0 ? currentTheme.fg("textDim", this.content) : currentTheme.fg(this.color, this.content)).replaceAll("\r", "").split("\n").map((line) => ` ${line}`).join("\n");
323024
323449
  }
323025
323450
  };
323026
323451
  var NoticeMessageComponent = class extends Container {
@@ -323128,349 +323553,18 @@ var QueuePaneComponent = class extends Container {
323128
323553
  };
323129
323554
  //#endregion
323130
323555
  //#region src/tui/utils/refresh-providers.ts
323131
- function readCustomRegistrySource(provider) {
323132
- const source = provider.source;
323133
- if (typeof source !== "object" || source === null) return void 0;
323134
- const candidate = source;
323135
- if (candidate["kind"] !== "apiJson") return void 0;
323136
- const url = candidate["url"];
323137
- const apiKey = candidate["apiKey"];
323138
- if (typeof url !== "string" || url.length === 0) return void 0;
323139
- if (typeof apiKey !== "string") return void 0;
323140
- return {
323141
- kind: "apiJson",
323142
- url,
323143
- apiKey
323144
- };
323145
- }
323146
- function customRegistrySourceKey(source) {
323147
- return JSON.stringify([source.url]);
323148
- }
323149
- function customRegistrySourceCredentialKey(source) {
323150
- return JSON.stringify([source.url, source.apiKey]);
323151
- }
323152
- async function fetchCustomRegistryFromSources(sources) {
323153
- let lastError;
323154
- for (const source of sources) try {
323155
- return {
323156
- entries: await fetchCustomRegistry(source),
323157
- source
323158
- };
323159
- } catch (error) {
323160
- lastError = error;
323161
- }
323162
- if (lastError instanceof Error) throw lastError;
323163
- if (typeof lastError === "string") throw new Error(lastError);
323164
- throw new Error("No custom registry sources configured.");
323165
- }
323166
- function asManaged(config) {
323167
- return config;
323168
- }
323169
- function collectModelIdsForAliases(config, aliasKeys) {
323170
- const ids = /* @__PURE__ */ new Set();
323171
- for (const aliasKey of aliasKeys) {
323172
- const alias = config.models?.[aliasKey];
323173
- if (alias !== void 0 && alias.model.length > 0) ids.add(alias.model);
323174
- }
323175
- return ids;
323176
- }
323177
- function providerAliasKeys(config, providerId) {
323178
- const keys = /* @__PURE__ */ new Set();
323179
- for (const [alias, model] of Object.entries(config.models ?? {})) if (model.provider === providerId) keys.add(alias);
323180
- return keys;
323181
- }
323182
- function generatedProviderAliasKeys(config, providerId, aliasPrefix) {
323183
- const keys = /* @__PURE__ */ new Set();
323184
- for (const [alias, model] of Object.entries(config.models ?? {})) if (model.provider === providerId && alias.startsWith(aliasPrefix)) keys.add(alias);
323185
- return keys;
323186
- }
323187
- function computeChanges(oldIds, newIds) {
323188
- let added = 0;
323189
- for (const id of newIds) if (!oldIds.has(id)) added++;
323190
- let removed = 0;
323191
- for (const id of oldIds) if (!newIds.has(id)) removed++;
323192
- return {
323193
- added,
323194
- removed
323195
- };
323196
- }
323197
- function providerModelSnapshot(config, providerId, aliasKeys) {
323198
- const snapshots = [];
323199
- for (const alias of aliasKeys) {
323200
- const model = config.models?.[alias];
323201
- if (model === void 0 || model.provider !== providerId) continue;
323202
- snapshots.push({
323203
- alias,
323204
- model: {
323205
- ...model,
323206
- capabilities: model.capabilities === void 0 ? void 0 : model.capabilities.toSorted()
323207
- }
323208
- });
323209
- }
323210
- snapshots.sort((a, b) => a.alias.localeCompare(b.alias));
323211
- return JSON.stringify(snapshots);
323212
- }
323213
- function providerModelsEqual(config, nextConfig, providerId, aliasKeys) {
323214
- return providerModelSnapshot(config, providerId, aliasKeys) === providerModelSnapshot(nextConfig, providerId, aliasKeys);
323215
- }
323216
- function providerConfigSnapshot(config, providerId) {
323217
- return JSON.stringify(config.providers[providerId] ?? null);
323218
- }
323219
- function providerConfigEqual(config, nextConfig, providerId) {
323220
- return providerConfigSnapshot(config, providerId) === providerConfigSnapshot(nextConfig, providerId);
323221
- }
323222
- function providerRefreshAliasKeys(config, nextConfig, providerId, aliasPrefix) {
323223
- const keys = generatedProviderAliasKeys(config, providerId, aliasPrefix);
323224
- for (const key of providerAliasKeys(nextConfig, providerId)) keys.add(key);
323225
- return keys;
323226
- }
323227
- function preserveUserProviderAliases(config, providerId, refreshedAliasKeys) {
323228
- const preserved = {};
323229
- for (const [alias, model] of Object.entries(config.models ?? {})) {
323230
- if (model.provider !== providerId || refreshedAliasKeys.has(alias)) continue;
323231
- preserved[alias] = structuredClone(model);
323232
- }
323233
- return preserved;
323234
- }
323235
- function restoreProviderAliases(config, aliases) {
323236
- if (Object.keys(aliases).length === 0) return;
323237
- config.models = {
323238
- ...config.models,
323239
- ...aliases
323240
- };
323241
- }
323242
- function restoreDefaultSelection(config, defaultModel, defaultThinking) {
323243
- if (defaultModel === void 0 || config.models?.[defaultModel] === void 0) return;
323244
- config.defaultModel = defaultModel;
323245
- config.defaultThinking = (config.models[defaultModel]?.capabilities ?? []).includes("always_thinking") ? true : defaultThinking;
323246
- }
323247
- function clampDanglingDefault(config) {
323248
- if (config.defaultModel !== void 0 && config.models?.[config.defaultModel] === void 0) {
323249
- config.defaultModel = void 0;
323250
- config.defaultThinking = void 0;
323251
- }
323252
- }
323253
- function clearDefaultThinkingWhenDefaultRemoved(config, previousDefaultModel) {
323254
- if (previousDefaultModel !== void 0 && config.defaultModel === void 0) config.defaultThinking = void 0;
323255
- }
323256
- function pickDefaultModel(config, providerId, models) {
323257
- const firstModel = models[0];
323258
- if (firstModel === void 0) return "";
323259
- const existingDefault = config.defaultModel;
323260
- if (existingDefault !== void 0) {
323261
- const alias = config.models?.[existingDefault];
323262
- if (alias !== void 0 && alias.provider === providerId) {
323263
- const stillAvailable = models.find((m) => m.id === alias.model);
323264
- if (stillAvailable !== void 0) return stillAvailable.id;
323265
- }
323266
- }
323267
- return firstModel.id;
323268
- }
323556
+ /**
323557
+ * Refresh remote model metadata for the configured providers. Thin adapter over
323558
+ * the shared `refreshProviderModels` orchestrator in `@moonshot-ai/kimi-code-oauth`
323559
+ * (which is also what the daemon's scheduled/manual refresh uses).
323560
+ */
323269
323561
  async function refreshAllProviderModels(host, options = {}) {
323270
- const changed = [];
323271
- const unchanged = [];
323272
- const failed = [];
323273
- const scope = options.scope ?? "all";
323274
- let config = await host.getConfig();
323275
- const managedProvider = config.providers[KIMI_CODE_PROVIDER_NAME$1];
323276
- if (managedProvider !== void 0 && managedProvider.type === "kimi" && managedProvider.oauth !== void 0) try {
323277
- const auth = resolveKimiCodeRuntimeAuth({
323278
- configuredBaseUrl: managedProvider.baseUrl,
323279
- configuredOAuthRef: managedProvider.oauth
323280
- });
323281
- const models = await fetchManagedKimiCodeModels({
323282
- accessToken: await host.resolveOAuthToken(KIMI_CODE_PROVIDER_NAME$1, auth.oauthRef),
323283
- baseUrl: auth.baseUrl
323284
- });
323285
- if (models.length > 0) {
323286
- const next = structuredClone(config);
323287
- applyManagedKimiCodeConfig(asManaged(next), {
323288
- models,
323289
- baseUrl: auth.baseUrl,
323290
- oauthKey: auth.oauthRef.key,
323291
- oauthHost: auth.oauthRef.oauthHost,
323292
- preserveDefaultModel: true
323293
- });
323294
- const refreshedAliasKeys = providerRefreshAliasKeys(config, next, KIMI_CODE_PROVIDER_NAME$1, `${KIMI_CODE_PLATFORM_ID}/`);
323295
- restoreProviderAliases(next, preserveUserProviderAliases(config, KIMI_CODE_PROVIDER_NAME$1, refreshedAliasKeys));
323296
- restoreDefaultSelection(next, config.defaultModel, config.defaultThinking);
323297
- clampDanglingDefault(next);
323298
- clearDefaultThinkingWhenDefaultRemoved(next, config.defaultModel);
323299
- if (providerModelsEqual(config, next, "managed:kimi-code", refreshedAliasKeys)) unchanged.push(KIMI_CODE_PROVIDER_NAME$1);
323300
- else {
323301
- const { added, removed } = computeChanges(collectModelIdsForAliases(config, refreshedAliasKeys), collectModelIdsForAliases(next, refreshedAliasKeys));
323302
- await host.removeProvider(KIMI_CODE_PROVIDER_NAME$1);
323303
- config = await host.setConfig({
323304
- providers: next.providers,
323305
- models: next.models,
323306
- defaultModel: next.defaultModel,
323307
- defaultThinking: next.defaultThinking
323308
- });
323309
- changed.push({
323310
- providerId: KIMI_CODE_PROVIDER_NAME$1,
323311
- providerName: "Kimi Code",
323312
- added,
323313
- removed
323314
- });
323315
- }
323316
- }
323317
- } catch (error) {
323318
- failed.push({
323319
- provider: KIMI_CODE_PROVIDER_NAME$1,
323320
- reason: error instanceof Error ? error.message : String(error)
323321
- });
323322
- }
323323
- if (scope === "oauth") return {
323324
- changed,
323325
- unchanged,
323326
- failed
323327
- };
323328
- const openPlatformIds = Object.keys(config.providers).filter((id) => isOpenPlatformId(id));
323329
- for (const providerId of openPlatformIds) {
323330
- const platform = getOpenPlatformById(providerId);
323331
- if (platform === void 0) continue;
323332
- const providerConfig = config.providers[providerId];
323333
- if (providerConfig === void 0) continue;
323334
- const apiKey = providerConfig.apiKey;
323335
- if (typeof apiKey !== "string" || apiKey.length === 0) continue;
323336
- try {
323337
- let models = await fetchOpenPlatformModels(platform, apiKey);
323338
- models = filterModelsByPrefix(models, platform);
323339
- if (models.length === 0) continue;
323340
- const selectedModelId = pickDefaultModel(config, providerId, models);
323341
- const selectedModel = models.find((m) => m.id === selectedModelId);
323342
- if (selectedModel === void 0) continue;
323343
- const next = structuredClone(config);
323344
- applyOpenPlatformConfig(asManaged(next), {
323345
- platform,
323346
- models,
323347
- selectedModel,
323348
- thinking: false,
323349
- apiKey
323350
- });
323351
- const refreshedAliasKeys = providerRefreshAliasKeys(config, next, providerId, `${providerId}/`);
323352
- restoreProviderAliases(next, preserveUserProviderAliases(config, providerId, refreshedAliasKeys));
323353
- restoreDefaultSelection(next, config.defaultModel, config.defaultThinking);
323354
- clampDanglingDefault(next);
323355
- clearDefaultThinkingWhenDefaultRemoved(next, config.defaultModel);
323356
- if (providerModelsEqual(config, next, providerId, refreshedAliasKeys)) unchanged.push(providerId);
323357
- else {
323358
- const { added, removed } = computeChanges(collectModelIdsForAliases(config, refreshedAliasKeys), collectModelIdsForAliases(next, refreshedAliasKeys));
323359
- await host.removeProvider(providerId);
323360
- config = await host.setConfig({
323361
- providers: next.providers,
323362
- models: next.models,
323363
- defaultModel: next.defaultModel,
323364
- defaultThinking: next.defaultThinking
323365
- });
323366
- changed.push({
323367
- providerId,
323368
- providerName: platform.name,
323369
- added,
323370
- removed
323371
- });
323372
- }
323373
- } catch (error) {
323374
- failed.push({
323375
- provider: providerId,
323376
- reason: error instanceof Error ? error.message : String(error)
323377
- });
323378
- }
323379
- }
323380
- const customSources = /* @__PURE__ */ new Map();
323381
- for (const [providerId, providerConfig] of Object.entries(config.providers)) {
323382
- if (providerId === "managed:kimi-code") continue;
323383
- if (isOpenPlatformId(providerId)) continue;
323384
- const source = readCustomRegistrySource(providerConfig);
323385
- if (source === void 0) continue;
323386
- const key = customRegistrySourceKey(source);
323387
- const sourceKey = customRegistrySourceCredentialKey(source);
323388
- const entry = customSources.get(key);
323389
- if (entry !== void 0) {
323390
- if (!entry.sourceKeys.has(sourceKey)) {
323391
- entry.sources.push(source);
323392
- entry.sourceKeys.add(sourceKey);
323393
- }
323394
- entry.providerIds.push(providerId);
323395
- } else customSources.set(key, {
323396
- sources: [source],
323397
- sourceKeys: new Set([sourceKey]),
323398
- providerIds: [providerId]
323399
- });
323400
- }
323401
- for (const { sources, providerIds } of customSources.values()) try {
323402
- const { entries, source } = await fetchCustomRegistryFromSources(sources);
323403
- const next = structuredClone(config);
323404
- const changedProviders = [];
323405
- const providersToRemoveBeforeSet = /* @__PURE__ */ new Set();
323406
- let hasUnreportedConfigChange = false;
323407
- const remoteEntries = Object.values(entries);
323408
- const remoteEntriesByProviderId = new Map(remoteEntries.map((entry) => [entry.id, entry]));
323409
- const providerIdsToSync = new Set(providerIds);
323410
- for (const entry of remoteEntries) providerIdsToSync.add(entry.id);
323411
- for (const providerId of providerIdsToSync) {
323412
- const entry = remoteEntriesByProviderId.get(providerId);
323413
- if (entry === void 0) {
323414
- const oldIds = collectModelIdsForAliases(config, providerAliasKeys(config, providerId));
323415
- removeCustomRegistryProvider(asManaged(next), providerId);
323416
- changedProviders.push({
323417
- providerId,
323418
- providerName: providerId,
323419
- added: 0,
323420
- removed: oldIds.size
323421
- });
323422
- providersToRemoveBeforeSet.add(providerId);
323423
- continue;
323424
- }
323425
- const existed = config.providers[providerId] !== void 0;
323426
- applyCustomRegistryProvider(asManaged(next), entry, source);
323427
- const refreshedAliasKeys = providerRefreshAliasKeys(config, next, providerId, `${providerId}/`);
323428
- if (existed) restoreProviderAliases(next, preserveUserProviderAliases(config, providerId, refreshedAliasKeys));
323429
- if (existed && providerModelsEqual(config, next, providerId, refreshedAliasKeys) && providerConfigEqual(config, next, providerId)) unchanged.push(providerId);
323430
- else if (existed && providerModelsEqual(config, next, providerId, refreshedAliasKeys)) {
323431
- unchanged.push(providerId);
323432
- providersToRemoveBeforeSet.add(providerId);
323433
- hasUnreportedConfigChange = true;
323434
- } else {
323435
- const { added, removed } = computeChanges(collectModelIdsForAliases(config, refreshedAliasKeys), collectModelIdsForAliases(next, refreshedAliasKeys));
323436
- changedProviders.push({
323437
- providerId,
323438
- providerName: entry.name || providerId,
323439
- added,
323440
- removed
323441
- });
323442
- if (existed) providersToRemoveBeforeSet.add(providerId);
323443
- }
323444
- }
323445
- if (changedProviders.length > 0 || hasUnreportedConfigChange) {
323446
- restoreDefaultSelection(next, config.defaultModel, config.defaultThinking);
323447
- clampDanglingDefault(next);
323448
- clearDefaultThinkingWhenDefaultRemoved(next, config.defaultModel);
323449
- for (const providerId of providersToRemoveBeforeSet) await host.removeProvider(providerId);
323450
- config = await host.setConfig({
323451
- providers: next.providers,
323452
- models: next.models,
323453
- defaultModel: next.defaultModel,
323454
- defaultThinking: next.defaultThinking
323455
- });
323456
- for (const change of changedProviders) changed.push({
323457
- providerId: change.providerId,
323458
- providerName: change.providerName,
323459
- added: change.added,
323460
- removed: change.removed
323461
- });
323462
- }
323463
- } catch (error) {
323464
- for (const providerId of providerIds) failed.push({
323465
- provider: providerId,
323466
- reason: error instanceof Error ? error.message : String(error)
323467
- });
323468
- }
323469
- return {
323470
- changed,
323471
- unchanged,
323472
- failed
323473
- };
323562
+ return refreshProviderModels({
323563
+ getConfig: () => host.getConfig(),
323564
+ removeProvider: (providerId) => host.removeProvider(providerId),
323565
+ setConfig: (patch) => host.setConfig(patch),
323566
+ resolveOAuthToken: (providerName, oauthRef) => host.resolveOAuthToken(providerName, oauthRef)
323567
+ }, options);
323474
323568
  }
323475
323569
  //#endregion
323476
323570
  //#region src/tui/controllers/auth-flow.ts
@@ -333329,8 +333423,6 @@ async function shouldAutoInstallUpdates() {
333329
333423
  }
333330
333424
  function trackUpdatePrompted(track, currentVersion, target, source, decision, rolloutTelemetry) {
333331
333425
  trackUpdateEvent(track, "update_prompted", {
333332
- current: currentVersion,
333333
- latest: target.version,
333334
333426
  current_version: currentVersion,
333335
333427
  target_version: target.version,
333336
333428
  source,