@cjhyy/code-shell-core 0.5.0-rc.0

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 (484) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +162 -0
  3. package/dist/agent/coordinator.d.ts +49 -0
  4. package/dist/agent/coordinator.js +77 -0
  5. package/dist/arena/arena.d.ts +43 -0
  6. package/dist/arena/arena.js +334 -0
  7. package/dist/arena/context/context-tools.d.ts +16 -0
  8. package/dist/arena/context/context-tools.js +231 -0
  9. package/dist/arena/detect-mode.d.ts +20 -0
  10. package/dist/arena/detect-mode.js +78 -0
  11. package/dist/arena/digest-builder.d.ts +25 -0
  12. package/dist/arena/digest-builder.js +120 -0
  13. package/dist/arena/index.d.ts +29 -0
  14. package/dist/arena/index.js +29 -0
  15. package/dist/arena/iterate/convergence.d.ts +25 -0
  16. package/dist/arena/iterate/convergence.js +103 -0
  17. package/dist/arena/iterate/formats/index.d.ts +22 -0
  18. package/dist/arena/iterate/formats/index.js +283 -0
  19. package/dist/arena/iterate/index.d.ts +11 -0
  20. package/dist/arena/iterate/index.js +9 -0
  21. package/dist/arena/iterate/iterative-arena.d.ts +23 -0
  22. package/dist/arena/iterate/iterative-arena.js +237 -0
  23. package/dist/arena/iterate/parse.d.ts +42 -0
  24. package/dist/arena/iterate/parse.js +123 -0
  25. package/dist/arena/iterate/phases/argue.d.ts +22 -0
  26. package/dist/arena/iterate/phases/argue.js +159 -0
  27. package/dist/arena/iterate/phases/revise.d.ts +16 -0
  28. package/dist/arena/iterate/phases/revise.js +62 -0
  29. package/dist/arena/iterate/phases/tournament.d.ts +34 -0
  30. package/dist/arena/iterate/phases/tournament.js +113 -0
  31. package/dist/arena/iterate/tools/web-tools.d.ts +13 -0
  32. package/dist/arena/iterate/tools/web-tools.js +54 -0
  33. package/dist/arena/iterate/types.d.ts +152 -0
  34. package/dist/arena/iterate/types.js +8 -0
  35. package/dist/arena/ledger.d.ts +47 -0
  36. package/dist/arena/ledger.js +151 -0
  37. package/dist/arena/lenses/architecture.d.ts +5 -0
  38. package/dist/arena/lenses/architecture.js +22 -0
  39. package/dist/arena/lenses/engineering.d.ts +5 -0
  40. package/dist/arena/lenses/engineering.js +22 -0
  41. package/dist/arena/lenses/general.d.ts +5 -0
  42. package/dist/arena/lenses/general.js +20 -0
  43. package/dist/arena/lenses/index.d.ts +16 -0
  44. package/dist/arena/lenses/index.js +47 -0
  45. package/dist/arena/lenses/product.d.ts +5 -0
  46. package/dist/arena/lenses/product.js +22 -0
  47. package/dist/arena/model-presets.d.ts +23 -0
  48. package/dist/arena/model-presets.js +44 -0
  49. package/dist/arena/phases/adjudication.d.ts +24 -0
  50. package/dist/arena/phases/adjudication.js +144 -0
  51. package/dist/arena/phases/build-consensus.d.ts +29 -0
  52. package/dist/arena/phases/build-consensus.js +86 -0
  53. package/dist/arena/phases/claim-registry.d.ts +26 -0
  54. package/dist/arena/phases/claim-registry.js +60 -0
  55. package/dist/arena/phases/cross-review.d.ts +45 -0
  56. package/dist/arena/phases/cross-review.js +224 -0
  57. package/dist/arena/phases/debate-rounds.d.ts +27 -0
  58. package/dist/arena/phases/debate-rounds.js +162 -0
  59. package/dist/arena/phases/participant-research.d.ts +38 -0
  60. package/dist/arena/phases/participant-research.js +317 -0
  61. package/dist/arena/phases/planning-detail-expansion.d.ts +38 -0
  62. package/dist/arena/phases/planning-detail-expansion.js +121 -0
  63. package/dist/arena/planner.d.ts +27 -0
  64. package/dist/arena/planner.js +312 -0
  65. package/dist/arena/providers/docs.d.ts +6 -0
  66. package/dist/arena/providers/docs.js +108 -0
  67. package/dist/arena/providers/git.d.ts +8 -0
  68. package/dist/arena/providers/git.js +174 -0
  69. package/dist/arena/providers/index.d.ts +32 -0
  70. package/dist/arena/providers/index.js +132 -0
  71. package/dist/arena/providers/none.d.ts +7 -0
  72. package/dist/arena/providers/none.js +11 -0
  73. package/dist/arena/providers/repo.d.ts +6 -0
  74. package/dist/arena/providers/repo.js +255 -0
  75. package/dist/arena/render/session.d.ts +17 -0
  76. package/dist/arena/render/session.js +190 -0
  77. package/dist/arena/render/terminal.d.ts +34 -0
  78. package/dist/arena/render/terminal.js +286 -0
  79. package/dist/arena/strategies/discussion.d.ts +25 -0
  80. package/dist/arena/strategies/discussion.js +143 -0
  81. package/dist/arena/strategies/index.d.ts +15 -0
  82. package/dist/arena/strategies/index.js +28 -0
  83. package/dist/arena/strategies/language-wrapper.d.ts +17 -0
  84. package/dist/arena/strategies/language-wrapper.js +102 -0
  85. package/dist/arena/strategies/lens-wrapper.d.ts +16 -0
  86. package/dist/arena/strategies/lens-wrapper.js +236 -0
  87. package/dist/arena/strategies/planning.d.ts +30 -0
  88. package/dist/arena/strategies/planning.js +225 -0
  89. package/dist/arena/strategies/review.d.ts +26 -0
  90. package/dist/arena/strategies/review.js +168 -0
  91. package/dist/arena/strategies/utils.d.ts +39 -0
  92. package/dist/arena/strategies/utils.js +647 -0
  93. package/dist/arena/tools/selector.d.ts +17 -0
  94. package/dist/arena/tools/selector.js +61 -0
  95. package/dist/arena/transitions.d.ts +48 -0
  96. package/dist/arena/transitions.js +92 -0
  97. package/dist/arena/types.d.ts +508 -0
  98. package/dist/arena/types.js +27 -0
  99. package/dist/cli/agent-server-stdio.d.ts +32 -0
  100. package/dist/cli/agent-server-stdio.js +116 -0
  101. package/dist/colorizer.d.ts +23 -0
  102. package/dist/colorizer.js +12 -0
  103. package/dist/context/compaction.d.ts +116 -0
  104. package/dist/context/compaction.js +534 -0
  105. package/dist/context/manager.d.ts +145 -0
  106. package/dist/context/manager.js +423 -0
  107. package/dist/context/token-counter.d.ts +27 -0
  108. package/dist/context/token-counter.js +91 -0
  109. package/dist/context/tool-result-storage.d.ts +96 -0
  110. package/dist/context/tool-result-storage.js +296 -0
  111. package/dist/cost-tracker.d.ts +64 -0
  112. package/dist/cost-tracker.js +314 -0
  113. package/dist/cron/scheduler.d.ts +34 -0
  114. package/dist/cron/scheduler.js +115 -0
  115. package/dist/data/deepseek-models.json +46 -0
  116. package/dist/data/gemini-models.json +67 -0
  117. package/dist/data/openai-models.json +175 -0
  118. package/dist/data/openrouter-models.d.ts +35 -0
  119. package/dist/data/openrouter-models.js +36 -0
  120. package/dist/data/openrouter-models.json +4626 -0
  121. package/dist/data/openrouter-sync.d.ts +16 -0
  122. package/dist/data/openrouter-sync.js +53 -0
  123. package/dist/data/static-catalogs.d.ts +25 -0
  124. package/dist/data/static-catalogs.js +26 -0
  125. package/dist/data/zai-models.json +56 -0
  126. package/dist/engine/cost-store.d.ts +22 -0
  127. package/dist/engine/cost-store.js +15 -0
  128. package/dist/engine/engine.d.ts +295 -0
  129. package/dist/engine/engine.js +1467 -0
  130. package/dist/engine/model-facade.d.ts +24 -0
  131. package/dist/engine/model-facade.js +194 -0
  132. package/dist/engine/parse-task.d.ts +59 -0
  133. package/dist/engine/parse-task.js +135 -0
  134. package/dist/engine/patch-orphaned-tools.d.ts +52 -0
  135. package/dist/engine/patch-orphaned-tools.js +95 -0
  136. package/dist/engine/query.d.ts +50 -0
  137. package/dist/engine/query.js +107 -0
  138. package/dist/engine/runtime.d.ts +50 -0
  139. package/dist/engine/runtime.js +59 -0
  140. package/dist/engine/streaming-tool-queue.d.ts +34 -0
  141. package/dist/engine/streaming-tool-queue.js +61 -0
  142. package/dist/engine/token-budget.d.ts +22 -0
  143. package/dist/engine/token-budget.js +40 -0
  144. package/dist/engine/tool-summary.d.ts +13 -0
  145. package/dist/engine/tool-summary.js +35 -0
  146. package/dist/engine/turn-loop.d.ts +122 -0
  147. package/dist/engine/turn-loop.js +602 -0
  148. package/dist/engine/turn-state.d.ts +20 -0
  149. package/dist/engine/turn-state.js +17 -0
  150. package/dist/exceptions.d.ts +61 -0
  151. package/dist/exceptions.js +116 -0
  152. package/dist/git/utils.d.ts +35 -0
  153. package/dist/git/utils.js +98 -0
  154. package/dist/git/worktree.d.ts +36 -0
  155. package/dist/git/worktree.js +139 -0
  156. package/dist/hooks/events.d.ts +114 -0
  157. package/dist/hooks/events.js +4 -0
  158. package/dist/hooks/inject.d.ts +19 -0
  159. package/dist/hooks/inject.js +29 -0
  160. package/dist/hooks/registry.d.ts +15 -0
  161. package/dist/hooks/registry.js +84 -0
  162. package/dist/hooks/shell-runner.d.ts +45 -0
  163. package/dist/hooks/shell-runner.js +173 -0
  164. package/dist/index.d.ts +117 -0
  165. package/dist/index.js +145 -0
  166. package/dist/llm/api-key-sanitize.d.ts +22 -0
  167. package/dist/llm/api-key-sanitize.js +81 -0
  168. package/dist/llm/capabilities/index.d.ts +20 -0
  169. package/dist/llm/capabilities/index.js +39 -0
  170. package/dist/llm/capabilities/rules.d.ts +26 -0
  171. package/dist/llm/capabilities/rules.js +215 -0
  172. package/dist/llm/capabilities/types.d.ts +114 -0
  173. package/dist/llm/capabilities/types.js +24 -0
  174. package/dist/llm/client-base.d.ts +29 -0
  175. package/dist/llm/client-base.js +137 -0
  176. package/dist/llm/client-factory.d.ts +10 -0
  177. package/dist/llm/client-factory.js +29 -0
  178. package/dist/llm/model-cache.d.ts +21 -0
  179. package/dist/llm/model-cache.js +46 -0
  180. package/dist/llm/model-fetcher.d.ts +29 -0
  181. package/dist/llm/model-fetcher.js +282 -0
  182. package/dist/llm/model-pool.d.ts +95 -0
  183. package/dist/llm/model-pool.js +246 -0
  184. package/dist/llm/provider-catalog.d.ts +32 -0
  185. package/dist/llm/provider-catalog.js +50 -0
  186. package/dist/llm/provider-kinds.d.ts +21 -0
  187. package/dist/llm/provider-kinds.js +132 -0
  188. package/dist/llm/providers/anthropic.d.ts +19 -0
  189. package/dist/llm/providers/anthropic.js +267 -0
  190. package/dist/llm/providers/openai.d.ts +64 -0
  191. package/dist/llm/providers/openai.js +606 -0
  192. package/dist/llm/retry.d.ts +12 -0
  193. package/dist/llm/retry.js +17 -0
  194. package/dist/llm/stream-watchdog.d.ts +42 -0
  195. package/dist/llm/stream-watchdog.js +70 -0
  196. package/dist/llm/token-counter.d.ts +17 -0
  197. package/dist/llm/token-counter.js +36 -0
  198. package/dist/llm/types.d.ts +37 -0
  199. package/dist/llm/types.js +4 -0
  200. package/dist/logging/logger.d.ts +109 -0
  201. package/dist/logging/logger.js +390 -0
  202. package/dist/logging/sanitize-messages.d.ts +42 -0
  203. package/dist/logging/sanitize-messages.js +150 -0
  204. package/dist/logging/session-recorder.d.ts +90 -0
  205. package/dist/logging/session-recorder.js +304 -0
  206. package/dist/lsp/client.d.ts +41 -0
  207. package/dist/lsp/client.js +166 -0
  208. package/dist/lsp/manager.d.ts +40 -0
  209. package/dist/lsp/manager.js +124 -0
  210. package/dist/lsp/servers.d.ts +16 -0
  211. package/dist/lsp/servers.js +60 -0
  212. package/dist/migrate-models.d.ts +45 -0
  213. package/dist/migrate-models.js +179 -0
  214. package/dist/onboarding.d.ts +189 -0
  215. package/dist/onboarding.js +625 -0
  216. package/dist/plugins/gitOps.d.ts +32 -0
  217. package/dist/plugins/gitOps.js +62 -0
  218. package/dist/plugins/installedPlugins.d.ts +15 -0
  219. package/dist/plugins/installedPlugins.js +56 -0
  220. package/dist/plugins/knownMarketplaces.d.ts +10 -0
  221. package/dist/plugins/knownMarketplaces.js +46 -0
  222. package/dist/plugins/loadPluginHooks.d.ts +52 -0
  223. package/dist/plugins/loadPluginHooks.js +162 -0
  224. package/dist/plugins/marketplaceManager.d.ts +49 -0
  225. package/dist/plugins/marketplaceManager.js +142 -0
  226. package/dist/plugins/parseMarketplaceInput.d.ts +16 -0
  227. package/dist/plugins/parseMarketplaceInput.js +73 -0
  228. package/dist/plugins/pluginCommandHook.d.ts +54 -0
  229. package/dist/plugins/pluginCommandHook.js +180 -0
  230. package/dist/plugins/pluginCommandsLoader.d.ts +25 -0
  231. package/dist/plugins/pluginCommandsLoader.js +114 -0
  232. package/dist/plugins/pluginInstaller.d.ts +36 -0
  233. package/dist/plugins/pluginInstaller.js +228 -0
  234. package/dist/plugins/schemas.d.ts +9 -0
  235. package/dist/plugins/schemas.js +136 -0
  236. package/dist/plugins/types.d.ts +75 -0
  237. package/dist/plugins/types.js +7 -0
  238. package/dist/plugins/varRewrite.d.ts +42 -0
  239. package/dist/plugins/varRewrite.js +129 -0
  240. package/dist/preset/index.d.ts +60 -0
  241. package/dist/preset/index.js +159 -0
  242. package/dist/product/define.d.ts +60 -0
  243. package/dist/product/define.js +123 -0
  244. package/dist/product/index.d.ts +5 -0
  245. package/dist/product/index.js +4 -0
  246. package/dist/product/types.d.ts +111 -0
  247. package/dist/product/types.js +21 -0
  248. package/dist/prompt/composer.d.ts +49 -0
  249. package/dist/prompt/composer.js +168 -0
  250. package/dist/prompt/instruction-scanner.d.ts +54 -0
  251. package/dist/prompt/instruction-scanner.js +187 -0
  252. package/dist/prompt/section-cache.d.ts +15 -0
  253. package/dist/prompt/section-cache.js +31 -0
  254. package/dist/prompt/section-loader.d.ts +26 -0
  255. package/dist/prompt/section-loader.js +53 -0
  256. package/dist/prompt/sections/base.md +35 -0
  257. package/dist/prompt/sections/coding.md +31 -0
  258. package/dist/prompt/sections/orchestration.md +16 -0
  259. package/dist/prompt/sections/tone.md +9 -0
  260. package/dist/protocol/chat-session-manager.d.ts +33 -0
  261. package/dist/protocol/chat-session-manager.js +65 -0
  262. package/dist/protocol/chat-session.d.ts +49 -0
  263. package/dist/protocol/chat-session.js +86 -0
  264. package/dist/protocol/client.d.ts +104 -0
  265. package/dist/protocol/client.js +260 -0
  266. package/dist/protocol/factories.d.ts +93 -0
  267. package/dist/protocol/factories.js +64 -0
  268. package/dist/protocol/helpers.d.ts +42 -0
  269. package/dist/protocol/helpers.js +55 -0
  270. package/dist/protocol/index.d.ts +4 -0
  271. package/dist/protocol/index.js +4 -0
  272. package/dist/protocol/server.d.ts +80 -0
  273. package/dist/protocol/server.js +855 -0
  274. package/dist/protocol/transport.d.ts +37 -0
  275. package/dist/protocol/transport.js +85 -0
  276. package/dist/protocol/types.d.ts +221 -0
  277. package/dist/protocol/types.js +61 -0
  278. package/dist/remote/bridge.d.ts +37 -0
  279. package/dist/remote/bridge.js +103 -0
  280. package/dist/run/ArtifactTracker.d.ts +38 -0
  281. package/dist/run/ArtifactTracker.js +132 -0
  282. package/dist/run/CheckpointWriter.d.ts +53 -0
  283. package/dist/run/CheckpointWriter.js +135 -0
  284. package/dist/run/EngineRunner.d.ts +72 -0
  285. package/dist/run/EngineRunner.js +119 -0
  286. package/dist/run/Evaluator.d.ts +56 -0
  287. package/dist/run/Evaluator.js +62 -0
  288. package/dist/run/FileRunStore.d.ts +39 -0
  289. package/dist/run/FileRunStore.js +176 -0
  290. package/dist/run/Heartbeat.d.ts +54 -0
  291. package/dist/run/Heartbeat.js +123 -0
  292. package/dist/run/RunApprovalBackend.d.ts +53 -0
  293. package/dist/run/RunApprovalBackend.js +85 -0
  294. package/dist/run/RunLock.d.ts +40 -0
  295. package/dist/run/RunLock.js +98 -0
  296. package/dist/run/RunManager.d.ts +82 -0
  297. package/dist/run/RunManager.js +587 -0
  298. package/dist/run/RunQueue.d.ts +27 -0
  299. package/dist/run/RunQueue.js +73 -0
  300. package/dist/run/RunStore.d.ts +25 -0
  301. package/dist/run/RunStore.js +9 -0
  302. package/dist/run/factory.d.ts +63 -0
  303. package/dist/run/factory.js +51 -0
  304. package/dist/run/index.d.ts +17 -0
  305. package/dist/run/index.js +23 -0
  306. package/dist/run/types.d.ts +136 -0
  307. package/dist/run/types.js +28 -0
  308. package/dist/runtime/safe-spawn.d.ts +118 -0
  309. package/dist/runtime/safe-spawn.js +268 -0
  310. package/dist/services/analytics.d.ts +29 -0
  311. package/dist/services/analytics.js +84 -0
  312. package/dist/services/auto-dream.d.ts +49 -0
  313. package/dist/services/auto-dream.js +124 -0
  314. package/dist/services/diagnostics.d.ts +41 -0
  315. package/dist/services/diagnostics.js +99 -0
  316. package/dist/services/extract-memories.d.ts +31 -0
  317. package/dist/services/extract-memories.js +71 -0
  318. package/dist/services/index.d.ts +11 -0
  319. package/dist/services/index.js +17 -0
  320. package/dist/services/memory-orchestrator.d.ts +60 -0
  321. package/dist/services/memory-orchestrator.js +133 -0
  322. package/dist/services/notifier.d.ts +25 -0
  323. package/dist/services/notifier.js +69 -0
  324. package/dist/services/oauth.d.ts +27 -0
  325. package/dist/services/oauth.js +153 -0
  326. package/dist/services/session-memory.d.ts +37 -0
  327. package/dist/services/session-memory.js +81 -0
  328. package/dist/session/file-history.d.ts +41 -0
  329. package/dist/session/file-history.js +115 -0
  330. package/dist/session/memory.d.ts +104 -0
  331. package/dist/session/memory.js +310 -0
  332. package/dist/session/session-manager.d.ts +41 -0
  333. package/dist/session/session-manager.js +261 -0
  334. package/dist/session/transcript.d.ts +39 -0
  335. package/dist/session/transcript.js +186 -0
  336. package/dist/settings/manager.d.ts +36 -0
  337. package/dist/settings/manager.js +187 -0
  338. package/dist/settings/schema.d.ts +1219 -0
  339. package/dist/settings/schema.js +246 -0
  340. package/dist/skills/frontmatter.d.ts +13 -0
  341. package/dist/skills/frontmatter.js +70 -0
  342. package/dist/skills/index.d.ts +7 -0
  343. package/dist/skills/index.js +6 -0
  344. package/dist/skills/scanner.d.ts +31 -0
  345. package/dist/skills/scanner.js +171 -0
  346. package/dist/state.d.ts +160 -0
  347. package/dist/state.js +267 -0
  348. package/dist/tool-system/builtin/agent-notifications.d.ts +84 -0
  349. package/dist/tool-system/builtin/agent-notifications.js +197 -0
  350. package/dist/tool-system/builtin/agent-registry.d.ts +67 -0
  351. package/dist/tool-system/builtin/agent-registry.js +126 -0
  352. package/dist/tool-system/builtin/agent-transcript-translator.d.ts +22 -0
  353. package/dist/tool-system/builtin/agent-transcript-translator.js +160 -0
  354. package/dist/tool-system/builtin/agent.d.ts +16 -0
  355. package/dist/tool-system/builtin/agent.js +364 -0
  356. package/dist/tool-system/builtin/apply-patch/applier.d.ts +26 -0
  357. package/dist/tool-system/builtin/apply-patch/applier.js +250 -0
  358. package/dist/tool-system/builtin/apply-patch/index.d.ts +20 -0
  359. package/dist/tool-system/builtin/apply-patch/index.js +101 -0
  360. package/dist/tool-system/builtin/apply-patch/parser.d.ts +17 -0
  361. package/dist/tool-system/builtin/apply-patch/parser.js +212 -0
  362. package/dist/tool-system/builtin/apply-patch/seek-sequence.d.ts +18 -0
  363. package/dist/tool-system/builtin/apply-patch/seek-sequence.js +123 -0
  364. package/dist/tool-system/builtin/apply-patch/types.d.ts +49 -0
  365. package/dist/tool-system/builtin/apply-patch/types.js +13 -0
  366. package/dist/tool-system/builtin/arena.d.ts +31 -0
  367. package/dist/tool-system/builtin/arena.js +416 -0
  368. package/dist/tool-system/builtin/ask-user.d.ts +20 -0
  369. package/dist/tool-system/builtin/ask-user.js +99 -0
  370. package/dist/tool-system/builtin/bash.d.ts +21 -0
  371. package/dist/tool-system/builtin/bash.js +149 -0
  372. package/dist/tool-system/builtin/brief.d.ts +6 -0
  373. package/dist/tool-system/builtin/brief.js +41 -0
  374. package/dist/tool-system/builtin/config.d.ts +6 -0
  375. package/dist/tool-system/builtin/config.js +67 -0
  376. package/dist/tool-system/builtin/cron.d.ts +10 -0
  377. package/dist/tool-system/builtin/cron.js +61 -0
  378. package/dist/tool-system/builtin/edit.d.ts +6 -0
  379. package/dist/tool-system/builtin/edit.js +100 -0
  380. package/dist/tool-system/builtin/file-cache.d.ts +11 -0
  381. package/dist/tool-system/builtin/file-cache.js +39 -0
  382. package/dist/tool-system/builtin/glob.d.ts +7 -0
  383. package/dist/tool-system/builtin/glob.js +76 -0
  384. package/dist/tool-system/builtin/grep.d.ts +7 -0
  385. package/dist/tool-system/builtin/grep.js +150 -0
  386. package/dist/tool-system/builtin/index.d.ts +20 -0
  387. package/dist/tool-system/builtin/index.js +449 -0
  388. package/dist/tool-system/builtin/lsp.d.ts +6 -0
  389. package/dist/tool-system/builtin/lsp.js +141 -0
  390. package/dist/tool-system/builtin/mcp-tools.d.ts +10 -0
  391. package/dist/tool-system/builtin/mcp-tools.js +102 -0
  392. package/dist/tool-system/builtin/memory.d.ts +26 -0
  393. package/dist/tool-system/builtin/memory.js +226 -0
  394. package/dist/tool-system/builtin/notebook-edit.d.ts +6 -0
  395. package/dist/tool-system/builtin/notebook-edit.js +124 -0
  396. package/dist/tool-system/builtin/plan.d.ts +15 -0
  397. package/dist/tool-system/builtin/plan.js +55 -0
  398. package/dist/tool-system/builtin/powershell.d.ts +11 -0
  399. package/dist/tool-system/builtin/powershell.js +64 -0
  400. package/dist/tool-system/builtin/read.d.ts +6 -0
  401. package/dist/tool-system/builtin/read.js +70 -0
  402. package/dist/tool-system/builtin/remote-trigger.d.ts +6 -0
  403. package/dist/tool-system/builtin/remote-trigger.js +54 -0
  404. package/dist/tool-system/builtin/repl.d.ts +11 -0
  405. package/dist/tool-system/builtin/repl.js +82 -0
  406. package/dist/tool-system/builtin/send-message.d.ts +6 -0
  407. package/dist/tool-system/builtin/send-message.js +47 -0
  408. package/dist/tool-system/builtin/skill-prompt.d.ts +20 -0
  409. package/dist/tool-system/builtin/skill-prompt.js +52 -0
  410. package/dist/tool-system/builtin/skill.d.ts +9 -0
  411. package/dist/tool-system/builtin/skill.js +55 -0
  412. package/dist/tool-system/builtin/sleep.d.ts +6 -0
  413. package/dist/tool-system/builtin/sleep.js +33 -0
  414. package/dist/tool-system/builtin/task.d.ts +48 -0
  415. package/dist/tool-system/builtin/task.js +139 -0
  416. package/dist/tool-system/builtin/tool-search.d.ts +11 -0
  417. package/dist/tool-system/builtin/tool-search.js +90 -0
  418. package/dist/tool-system/builtin/web-fetch.d.ts +10 -0
  419. package/dist/tool-system/builtin/web-fetch.js +328 -0
  420. package/dist/tool-system/builtin/web-search.d.ts +25 -0
  421. package/dist/tool-system/builtin/web-search.js +174 -0
  422. package/dist/tool-system/builtin/worktree.d.ts +10 -0
  423. package/dist/tool-system/builtin/worktree.js +95 -0
  424. package/dist/tool-system/builtin/write.d.ts +6 -0
  425. package/dist/tool-system/builtin/write.js +36 -0
  426. package/dist/tool-system/context.d.ts +165 -0
  427. package/dist/tool-system/context.js +18 -0
  428. package/dist/tool-system/executor.d.ts +49 -0
  429. package/dist/tool-system/executor.js +495 -0
  430. package/dist/tool-system/investigation-guard.d.ts +46 -0
  431. package/dist/tool-system/investigation-guard.js +155 -0
  432. package/dist/tool-system/mcp-manager.d.ts +67 -0
  433. package/dist/tool-system/mcp-manager.js +249 -0
  434. package/dist/tool-system/permission.d.ts +111 -0
  435. package/dist/tool-system/permission.js +774 -0
  436. package/dist/tool-system/registry.d.ts +32 -0
  437. package/dist/tool-system/registry.js +131 -0
  438. package/dist/tool-system/sandbox/bwrap.d.ts +13 -0
  439. package/dist/tool-system/sandbox/bwrap.js +63 -0
  440. package/dist/tool-system/sandbox/index.d.ts +78 -0
  441. package/dist/tool-system/sandbox/index.js +222 -0
  442. package/dist/tool-system/sandbox/off.d.ts +2 -0
  443. package/dist/tool-system/sandbox/off.js +8 -0
  444. package/dist/tool-system/sandbox/seatbelt.d.ts +18 -0
  445. package/dist/tool-system/sandbox/seatbelt.js +109 -0
  446. package/dist/tool-system/task-guard.d.ts +29 -0
  447. package/dist/tool-system/task-guard.js +70 -0
  448. package/dist/tool-system/validation.d.ts +5 -0
  449. package/dist/tool-system/validation.js +39 -0
  450. package/dist/types.d.ts +376 -0
  451. package/dist/types.js +4 -0
  452. package/dist/updater.d.ts +65 -0
  453. package/dist/updater.js +405 -0
  454. package/dist/utils/debug.d.ts +41 -0
  455. package/dist/utils/debug.js +110 -0
  456. package/dist/utils/earlyInput.d.ts +43 -0
  457. package/dist/utils/earlyInput.js +166 -0
  458. package/dist/utils/env.d.ts +24 -0
  459. package/dist/utils/env.js +104 -0
  460. package/dist/utils/envUtils.d.ts +51 -0
  461. package/dist/utils/envUtils.js +135 -0
  462. package/dist/utils/execFileNoThrow.d.ts +39 -0
  463. package/dist/utils/execFileNoThrow.js +74 -0
  464. package/dist/utils/format.d.ts +44 -0
  465. package/dist/utils/format.js +236 -0
  466. package/dist/utils/intl.d.ts +22 -0
  467. package/dist/utils/intl.js +83 -0
  468. package/dist/utils/lockfile.d.ts +15 -0
  469. package/dist/utils/lockfile.js +30 -0
  470. package/dist/utils/memoize.d.ts +19 -0
  471. package/dist/utils/memoize.js +14 -0
  472. package/dist/utils/semver.d.ts +6 -0
  473. package/dist/utils/semver.js +13 -0
  474. package/dist/utils/sliceAnsi.d.ts +12 -0
  475. package/dist/utils/sliceAnsi.js +62 -0
  476. package/dist/utils/systemTheme.d.ts +40 -0
  477. package/dist/utils/systemTheme.js +108 -0
  478. package/dist/utils/task-sanitizer.d.ts +6 -0
  479. package/dist/utils/task-sanitizer.js +24 -0
  480. package/dist/utils/theme.d.ts +93 -0
  481. package/dist/utils/theme.js +544 -0
  482. package/dist/utils/toolDisplay.d.ts +31 -0
  483. package/dist/utils/toolDisplay.js +188 -0
  484. package/package.json +72 -0
@@ -0,0 +1,166 @@
1
+ /**
2
+ * LSP client — JSON-RPC over stdio communication with language servers.
3
+ */
4
+ import { spawn } from "node:child_process";
5
+ import { EventEmitter } from "node:events";
6
+ export class LSPClient extends EventEmitter {
7
+ command;
8
+ args;
9
+ cwd;
10
+ process;
11
+ nextId = 1;
12
+ pending = new Map();
13
+ buffer = "";
14
+ contentLength = -1;
15
+ initialized = false;
16
+ constructor(command, args = [], cwd) {
17
+ super();
18
+ this.command = command;
19
+ this.args = args;
20
+ this.cwd = cwd;
21
+ }
22
+ async start() {
23
+ this.process = spawn(this.command, this.args, {
24
+ cwd: this.cwd,
25
+ stdio: ["pipe", "pipe", "pipe"],
26
+ });
27
+ this.process.stdout?.on("data", (data) => this.handleData(data.toString()));
28
+ this.process.stderr?.on("data", (_data) => {
29
+ // LSP servers often log to stderr — ignore
30
+ });
31
+ this.process.on("exit", (code) => {
32
+ this.emit("exit", code);
33
+ this.rejectAll(new Error(`LSP server exited with code ${code}`));
34
+ });
35
+ // Don't keep the event loop alive solely for the LSP child.
36
+ // Call after listeners are wired so event registration doesn't re-ref.
37
+ this.process.unref();
38
+ }
39
+ async initialize(rootUri) {
40
+ const result = await this.request("initialize", {
41
+ processId: process.pid,
42
+ rootUri,
43
+ capabilities: {
44
+ textDocument: {
45
+ definition: { dynamicRegistration: false },
46
+ references: { dynamicRegistration: false },
47
+ hover: { contentFormat: ["plaintext", "markdown"] },
48
+ documentSymbol: { dynamicRegistration: false },
49
+ completion: { dynamicRegistration: false },
50
+ },
51
+ workspace: {
52
+ symbol: { dynamicRegistration: false },
53
+ },
54
+ },
55
+ });
56
+ await this.notify("initialized", {});
57
+ this.initialized = true;
58
+ return result;
59
+ }
60
+ async request(method, params) {
61
+ if (!this.process?.stdin)
62
+ throw new Error("LSP server not started");
63
+ const id = this.nextId++;
64
+ const message = { jsonrpc: "2.0", id, method, params };
65
+ const content = JSON.stringify(message);
66
+ const header = `Content-Length: ${Buffer.byteLength(content)}\r\n\r\n`;
67
+ return new Promise((resolve, reject) => {
68
+ const timer = setTimeout(() => {
69
+ if (this.pending.has(id)) {
70
+ this.pending.delete(id);
71
+ reject(new Error(`LSP request "${method}" timed out`));
72
+ }
73
+ }, 30000);
74
+ // Don't let the timer keep the event loop alive by itself
75
+ timer.unref?.();
76
+ this.pending.set(id, {
77
+ resolve: (value) => { clearTimeout(timer); resolve(value); },
78
+ reject: (err) => { clearTimeout(timer); reject(err); },
79
+ });
80
+ this.process.stdin.write(header + content);
81
+ });
82
+ }
83
+ async notify(method, params) {
84
+ if (!this.process?.stdin)
85
+ throw new Error("LSP server not started");
86
+ const message = { jsonrpc: "2.0", method, params };
87
+ const content = JSON.stringify(message);
88
+ const header = `Content-Length: ${Buffer.byteLength(content)}\r\n\r\n`;
89
+ this.process.stdin.write(header + content);
90
+ }
91
+ async shutdown() {
92
+ if (!this.process)
93
+ return;
94
+ try {
95
+ await this.request("shutdown", {});
96
+ await this.notify("exit", {});
97
+ }
98
+ catch {
99
+ // Force kill
100
+ }
101
+ this.process.stdout?.removeAllListeners();
102
+ this.process.stderr?.removeAllListeners();
103
+ this.process.removeAllListeners();
104
+ this.process.kill();
105
+ this.process = undefined;
106
+ // Drain pending requests
107
+ for (const { reject } of this.pending.values()) {
108
+ reject(new Error("LSP server shut down"));
109
+ }
110
+ this.pending.clear();
111
+ }
112
+ get isInitialized() {
113
+ return this.initialized;
114
+ }
115
+ get isAlive() {
116
+ return this.process !== undefined && !this.process.killed;
117
+ }
118
+ handleData(data) {
119
+ this.buffer += data;
120
+ while (true) {
121
+ if (this.contentLength < 0) {
122
+ const headerEnd = this.buffer.indexOf("\r\n\r\n");
123
+ if (headerEnd < 0)
124
+ break;
125
+ const header = this.buffer.slice(0, headerEnd);
126
+ const match = header.match(/Content-Length:\s*(\d+)/i);
127
+ if (!match) {
128
+ this.buffer = this.buffer.slice(headerEnd + 4);
129
+ continue;
130
+ }
131
+ this.contentLength = parseInt(match[1], 10);
132
+ this.buffer = this.buffer.slice(headerEnd + 4);
133
+ }
134
+ if (this.buffer.length < this.contentLength)
135
+ break;
136
+ const content = this.buffer.slice(0, this.contentLength);
137
+ this.buffer = this.buffer.slice(this.contentLength);
138
+ this.contentLength = -1;
139
+ try {
140
+ const message = JSON.parse(content);
141
+ if ("id" in message && this.pending.has(message.id)) {
142
+ const { resolve, reject } = this.pending.get(message.id);
143
+ this.pending.delete(message.id);
144
+ if (message.error) {
145
+ reject(new Error(`LSP error: ${message.error.message}`));
146
+ }
147
+ else {
148
+ resolve(message.result);
149
+ }
150
+ }
151
+ else if ("method" in message && !("id" in message)) {
152
+ this.emit("notification", message);
153
+ }
154
+ }
155
+ catch {
156
+ // Skip malformed messages
157
+ }
158
+ }
159
+ }
160
+ rejectAll(error) {
161
+ for (const { reject } of this.pending.values()) {
162
+ reject(error);
163
+ }
164
+ this.pending.clear();
165
+ }
166
+ }
@@ -0,0 +1,40 @@
1
+ /**
2
+ * LSP Server Manager — manages lifecycle of language server instances.
3
+ * Lazy initialization: servers start only when needed.
4
+ */
5
+ import { LSPClient } from "./client.js";
6
+ type ServerState = "stopped" | "starting" | "ready" | "error";
7
+ export declare class LSPServerManager {
8
+ private servers;
9
+ private rootUri;
10
+ constructor(cwd: string);
11
+ /**
12
+ * Get or start a language server by name.
13
+ */
14
+ getClient(serverName: string): Promise<LSPClient | undefined>;
15
+ /**
16
+ * Start a specific language server.
17
+ */
18
+ private startServer;
19
+ /**
20
+ * Check if any LSP server is connected.
21
+ */
22
+ isConnected(): boolean;
23
+ /**
24
+ * List server statuses.
25
+ */
26
+ listServers(): Array<{
27
+ name: string;
28
+ language: string;
29
+ state: ServerState;
30
+ error?: string;
31
+ }>;
32
+ /**
33
+ * Shutdown all servers.
34
+ */
35
+ shutdownAll(): Promise<void>;
36
+ private isCommandAvailable;
37
+ }
38
+ export declare function initializeLSPManager(cwd: string): LSPServerManager;
39
+ export declare function getLSPManager(): LSPServerManager | undefined;
40
+ export {};
@@ -0,0 +1,124 @@
1
+ /**
2
+ * LSP Server Manager — manages lifecycle of language server instances.
3
+ * Lazy initialization: servers start only when needed.
4
+ */
5
+ import { LSPClient } from "./client.js";
6
+ import { BUILTIN_LSP_SERVERS } from "./servers.js";
7
+ import { execSync } from "node:child_process";
8
+ import { pathToFileURL } from "node:url";
9
+ export class LSPServerManager {
10
+ servers = new Map();
11
+ rootUri;
12
+ constructor(cwd) {
13
+ this.rootUri = pathToFileURL(cwd).href;
14
+ // Register all built-in servers
15
+ for (const config of BUILTIN_LSP_SERVERS) {
16
+ this.servers.set(config.name, { config, client: undefined, state: "stopped" });
17
+ }
18
+ }
19
+ /**
20
+ * Get or start a language server by name.
21
+ */
22
+ async getClient(serverName) {
23
+ const managed = this.servers.get(serverName);
24
+ if (!managed)
25
+ return undefined;
26
+ if (managed.state === "ready" && managed.client?.isAlive) {
27
+ return managed.client;
28
+ }
29
+ if (managed.state === "starting") {
30
+ // Wait for it to be ready
31
+ await new Promise((r) => setTimeout(r, 2000));
32
+ return managed.client;
33
+ }
34
+ // Try to start
35
+ return this.startServer(serverName);
36
+ }
37
+ /**
38
+ * Start a specific language server.
39
+ */
40
+ async startServer(name) {
41
+ const managed = this.servers.get(name);
42
+ if (!managed)
43
+ return undefined;
44
+ // Check if command is available
45
+ if (!this.isCommandAvailable(managed.config.command)) {
46
+ managed.state = "error";
47
+ managed.error = `${managed.config.command} not found. Install: ${managed.config.installHint}`;
48
+ return undefined;
49
+ }
50
+ managed.state = "starting";
51
+ try {
52
+ const client = new LSPClient(managed.config.command, managed.config.args, this.rootUri.replace("file://", ""));
53
+ await client.start();
54
+ await client.initialize(this.rootUri);
55
+ managed.client = client;
56
+ managed.state = "ready";
57
+ return client;
58
+ }
59
+ catch (err) {
60
+ managed.state = "error";
61
+ managed.error = err.message;
62
+ return undefined;
63
+ }
64
+ }
65
+ /**
66
+ * Check if any LSP server is connected.
67
+ */
68
+ isConnected() {
69
+ for (const server of this.servers.values()) {
70
+ if (server.state === "ready" && server.client?.isAlive)
71
+ return true;
72
+ }
73
+ return false;
74
+ }
75
+ /**
76
+ * List server statuses.
77
+ */
78
+ listServers() {
79
+ return [...this.servers.values()].map((s) => ({
80
+ name: s.config.name,
81
+ language: s.config.language,
82
+ state: s.state,
83
+ error: s.error,
84
+ }));
85
+ }
86
+ /**
87
+ * Shutdown all servers.
88
+ */
89
+ async shutdownAll() {
90
+ for (const server of this.servers.values()) {
91
+ if (server.client?.isAlive) {
92
+ try {
93
+ await server.client.shutdown();
94
+ }
95
+ catch {
96
+ // Force killed
97
+ }
98
+ }
99
+ server.state = "stopped";
100
+ server.client = undefined;
101
+ }
102
+ }
103
+ isCommandAvailable(command) {
104
+ try {
105
+ execSync(`which ${command} 2>/dev/null || where ${command} 2>nul`, {
106
+ encoding: "utf-8",
107
+ timeout: 5000,
108
+ });
109
+ return true;
110
+ }
111
+ catch {
112
+ return false;
113
+ }
114
+ }
115
+ }
116
+ // Singleton
117
+ let _manager;
118
+ export function initializeLSPManager(cwd) {
119
+ _manager = new LSPServerManager(cwd);
120
+ return _manager;
121
+ }
122
+ export function getLSPManager() {
123
+ return _manager;
124
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Built-in language server configurations.
3
+ */
4
+ export interface LSPServerConfig {
5
+ name: string;
6
+ language: string;
7
+ extensions: string[];
8
+ command: string;
9
+ args: string[];
10
+ installHint: string;
11
+ }
12
+ export declare const BUILTIN_LSP_SERVERS: LSPServerConfig[];
13
+ /**
14
+ * Detect which LSP server to use based on file extension.
15
+ */
16
+ export declare function detectLSPServer(filePath: string): LSPServerConfig | undefined;
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Built-in language server configurations.
3
+ */
4
+ export const BUILTIN_LSP_SERVERS = [
5
+ {
6
+ name: "typescript",
7
+ language: "typescript",
8
+ extensions: [".ts", ".tsx", ".js", ".jsx"],
9
+ command: "typescript-language-server",
10
+ args: ["--stdio"],
11
+ installHint: "npm install -g typescript-language-server typescript",
12
+ },
13
+ {
14
+ name: "python",
15
+ language: "python",
16
+ extensions: [".py"],
17
+ command: "pylsp",
18
+ args: [],
19
+ installHint: "pip install python-lsp-server",
20
+ },
21
+ {
22
+ name: "go",
23
+ language: "go",
24
+ extensions: [".go"],
25
+ command: "gopls",
26
+ args: ["serve"],
27
+ installHint: "go install golang.org/x/tools/gopls@latest",
28
+ },
29
+ {
30
+ name: "rust",
31
+ language: "rust",
32
+ extensions: [".rs"],
33
+ command: "rust-analyzer",
34
+ args: [],
35
+ installHint: "rustup component add rust-analyzer",
36
+ },
37
+ {
38
+ name: "json",
39
+ language: "json",
40
+ extensions: [".json"],
41
+ command: "vscode-json-languageserver",
42
+ args: ["--stdio"],
43
+ installHint: "npm install -g vscode-langservers-extracted",
44
+ },
45
+ {
46
+ name: "css",
47
+ language: "css",
48
+ extensions: [".css", ".scss", ".less"],
49
+ command: "vscode-css-languageserver",
50
+ args: ["--stdio"],
51
+ installHint: "npm install -g vscode-langservers-extracted",
52
+ },
53
+ ];
54
+ /**
55
+ * Detect which LSP server to use based on file extension.
56
+ */
57
+ export function detectLSPServer(filePath) {
58
+ const ext = filePath.slice(filePath.lastIndexOf("."));
59
+ return BUILTIN_LSP_SERVERS.find((s) => s.extensions.includes(ext));
60
+ }
@@ -0,0 +1,45 @@
1
+ /**
2
+ * One-shot migration of legacy flat models[] into providers[] + models[].
3
+ *
4
+ * Pure function — takes a snapshot, returns the new snapshot plus a flag.
5
+ * The caller (settings load path) is responsible for writing settings.json
6
+ * and the .bak backup.
7
+ */
8
+ import type { ProviderConfig } from "./llm/provider-catalog.js";
9
+ interface LegacyModel {
10
+ key: string;
11
+ label?: string;
12
+ provider?: string;
13
+ baseUrl?: string;
14
+ apiKey?: string;
15
+ model: string;
16
+ maxOutputTokens?: number;
17
+ maxContextTokens?: number;
18
+ providerKey?: string;
19
+ }
20
+ export interface MigrationInput {
21
+ providers: ProviderConfig[];
22
+ models: LegacyModel[];
23
+ }
24
+ export interface MigrationOutput {
25
+ providers: ProviderConfig[];
26
+ models: Array<{
27
+ key: string;
28
+ label?: string;
29
+ providerKey: string;
30
+ model: string;
31
+ /**
32
+ * Self-describing legacy fields. Kept (rather than stripped) so model
33
+ * entries stay valid standalone — the engine can read credentials
34
+ * straight off the entry without a ProviderCatalog round-trip.
35
+ */
36
+ provider?: string;
37
+ baseUrl?: string;
38
+ apiKey?: string;
39
+ maxOutputTokens?: number;
40
+ maxContextTokens?: number;
41
+ }>;
42
+ changed: boolean;
43
+ }
44
+ export declare function migrateModels(input: MigrationInput): MigrationOutput;
45
+ export {};
@@ -0,0 +1,179 @@
1
+ /**
2
+ * One-shot migration of legacy flat models[] into providers[] + models[].
3
+ *
4
+ * Pure function — takes a snapshot, returns the new snapshot plus a flag.
5
+ * The caller (settings load path) is responsible for writing settings.json
6
+ * and the .bak backup.
7
+ */
8
+ const BASEURL_KIND_PATTERNS = [
9
+ [/deepseek\.com/i, "deepseek"],
10
+ [/z\.ai/i, "zai"],
11
+ [/anthropic\.com/i, "anthropic"],
12
+ [/openai\.com/i, "openai"],
13
+ [/x\.ai/i, "xai"],
14
+ [/mistral\.ai/i, "mistral"],
15
+ [/groq\.com/i, "groq"],
16
+ [/generativelanguage\.googleapis/i, "google"],
17
+ [/openrouter\.ai/i, "openrouter"],
18
+ [/localhost:11434|127\.0\.0\.1:11434/i, "ollama"],
19
+ ];
20
+ function inferKind(baseUrl) {
21
+ if (!baseUrl)
22
+ return "custom";
23
+ for (const [re, kind] of BASEURL_KIND_PATTERNS) {
24
+ if (re.test(baseUrl))
25
+ return kind;
26
+ }
27
+ return "custom";
28
+ }
29
+ function makeFingerprint(m) {
30
+ return `${m.provider ?? ""}|${m.baseUrl ?? ""}|${m.apiKey ?? ""}`;
31
+ }
32
+ function deriveKey(base, used) {
33
+ if (!used.has(base))
34
+ return base;
35
+ for (let i = 2;; i++) {
36
+ const candidate = `${base}-${i}`;
37
+ if (!used.has(candidate))
38
+ return candidate;
39
+ }
40
+ }
41
+ /**
42
+ * Generate `<provider>-<model-id>` style pool key. Mirrors the
43
+ * `deriveModelPoolKey` helper in onboarding.ts — kept inline here to avoid
44
+ * an import cycle (settings/manager.ts → migrate-models.ts → ...).
45
+ */
46
+ function deriveProviderModelKey(providerKind, modelId, used) {
47
+ const slash = modelId.lastIndexOf("/");
48
+ const base = slash >= 0 ? modelId.slice(slash + 1) : modelId;
49
+ const prefix = providerKind.toLowerCase();
50
+ const candidate = base.toLowerCase().startsWith(`${prefix}-`) ? base : `${prefix}-${base}`;
51
+ if (!used.has(candidate))
52
+ return candidate;
53
+ for (let i = 2;; i++) {
54
+ const k = `${candidate}-${i}`;
55
+ if (!used.has(k))
56
+ return k;
57
+ }
58
+ }
59
+ export function migrateModels(input) {
60
+ if (input.models.length === 0) {
61
+ return {
62
+ providers: input.providers,
63
+ models: [],
64
+ changed: false,
65
+ };
66
+ }
67
+ const hasProvidersSection = input.providers.length > 0;
68
+ // Per-entry check (replaces the old "providers non-empty → skip everything"
69
+ // shortcut, which left legacy entries from the previous run forever
70
+ // un-migrated and bleeding key collisions like the two "deepseek" entries
71
+ // that motivated this rewrite).
72
+ // - Needs migration if: no providerKey set, OR
73
+ // - Needs migration if: the entry's `key` collides with a sibling (the
74
+ // old modelKey() helper folded v4-flash + v4-pro to "deepseek").
75
+ const keyCounts = new Map();
76
+ for (const m of input.models)
77
+ keyCounts.set(m.key, (keyCounts.get(m.key) ?? 0) + 1);
78
+ const needsMigration = input.models.some((m) => !m.providerKey || (keyCounts.get(m.key) ?? 0) > 1);
79
+ if (!needsMigration) {
80
+ return {
81
+ providers: input.providers,
82
+ models: input.models.map((m) => ({
83
+ key: m.key,
84
+ label: m.label,
85
+ providerKey: m.providerKey ?? "",
86
+ model: m.model,
87
+ maxOutputTokens: m.maxOutputTokens,
88
+ maxContextTokens: m.maxContextTokens,
89
+ provider: m.provider,
90
+ baseUrl: m.baseUrl,
91
+ apiKey: m.apiKey,
92
+ })),
93
+ changed: false,
94
+ };
95
+ }
96
+ // Build providerKey map from fingerprint (provider|baseUrl|apiKey). Each
97
+ // unique fingerprint becomes one provider entry. Existing providers[] are
98
+ // preserved; new ones are appended.
99
+ const fingerprintToKey = new Map();
100
+ const newProviders = [];
101
+ const usedProviderKeys = new Set(input.providers.map((p) => p.key));
102
+ // Pre-seed: if existing providers[] match a model's fingerprint already,
103
+ // reuse them instead of minting a new key.
104
+ for (const p of input.providers) {
105
+ const fp = `${""}|${p.baseUrl}|${p.apiKey ?? ""}`;
106
+ fingerprintToKey.set(fp, p.key);
107
+ }
108
+ for (const m of input.models) {
109
+ const fp = makeFingerprint(m);
110
+ // Also try matching against existing providers by baseUrl only — the
111
+ // legacy "provider" field on models is a generic kind ("openai") that
112
+ // doesn't disambiguate, so the fingerprint above won't match if the
113
+ // user added the provider via the wizard but kept legacy model entries.
114
+ const existingByUrl = input.providers.find((p) => p.baseUrl === (m.baseUrl ?? ""));
115
+ if (existingByUrl) {
116
+ fingerprintToKey.set(fp, existingByUrl.key);
117
+ continue;
118
+ }
119
+ if (fingerprintToKey.has(fp))
120
+ continue;
121
+ const kind = inferKind(m.baseUrl);
122
+ const key = deriveKey(kind, usedProviderKeys);
123
+ usedProviderKeys.add(key);
124
+ fingerprintToKey.set(fp, key);
125
+ newProviders.push({
126
+ key,
127
+ kind,
128
+ baseUrl: m.baseUrl ?? "",
129
+ apiKey: m.apiKey,
130
+ });
131
+ }
132
+ // Re-key models: any entry whose key collides with a sibling gets a fresh
133
+ // `<provider>-<model-id>` key. Entries that already have a unique key are
134
+ // left alone so user-customized aliases survive migration.
135
+ const usedModelKeys = new Set();
136
+ const newModels = input.models.map((m) => {
137
+ const providerKey = fingerprintToKey.get(makeFingerprint(m));
138
+ const collides = (keyCounts.get(m.key) ?? 0) > 1;
139
+ let key = m.key;
140
+ if (collides) {
141
+ const kind = inferKind(m.baseUrl);
142
+ key = deriveProviderModelKey(kind, m.model, usedModelKeys);
143
+ }
144
+ if (usedModelKeys.has(key)) {
145
+ // Defensive: if the user's original key happens to collide with a
146
+ // freshly minted one, re-derive too.
147
+ const kind = inferKind(m.baseUrl);
148
+ key = deriveProviderModelKey(kind, m.model, usedModelKeys);
149
+ }
150
+ usedModelKeys.add(key);
151
+ return {
152
+ key,
153
+ label: m.label,
154
+ providerKey,
155
+ provider: m.provider,
156
+ model: m.model,
157
+ baseUrl: m.baseUrl,
158
+ apiKey: m.apiKey,
159
+ maxOutputTokens: m.maxOutputTokens,
160
+ maxContextTokens: m.maxContextTokens,
161
+ };
162
+ });
163
+ // De-duplicate: if migration produced two entries with the same key + model
164
+ // (e.g. legacy duplicate that re-keys to the same canonical form), keep
165
+ // only the first.
166
+ const seen = new Set();
167
+ const deduped = newModels.filter((m) => {
168
+ const fp = `${m.key}|${m.model}`;
169
+ if (seen.has(fp))
170
+ return false;
171
+ seen.add(fp);
172
+ return true;
173
+ });
174
+ return {
175
+ providers: hasProvidersSection ? [...input.providers, ...newProviders] : newProviders,
176
+ models: deduped,
177
+ changed: true,
178
+ };
179
+ }