@cjhyy/code-shell-core 0.5.0-rc.2 → 0.6.0-rc.2

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 (387) hide show
  1. package/README.md +13 -10
  2. package/dist/agent/agent-definition-registry.d.ts +3 -0
  3. package/dist/agent/agent-definition-registry.js +3 -1
  4. package/dist/agent/agent-definition.d.ts +15 -0
  5. package/dist/agent/agent-definition.js +27 -3
  6. package/dist/arena/context/context-tools.js +47 -4
  7. package/dist/arena/ledger.js +9 -1
  8. package/dist/arena/strategies/utils.d.ts +1 -4
  9. package/dist/arena/strategies/utils.js +7 -84
  10. package/dist/automation/cron-expr.d.ts +10 -0
  11. package/dist/automation/cron-expr.js +23 -5
  12. package/dist/automation/runner.d.ts +21 -4
  13. package/dist/automation/runner.js +48 -12
  14. package/dist/automation/scheduler.d.ts +38 -0
  15. package/dist/automation/scheduler.js +89 -12
  16. package/dist/automation/store.js +5 -2
  17. package/dist/capability-control/disabled-lists.d.ts +25 -0
  18. package/dist/capability-control/disabled-lists.js +57 -0
  19. package/dist/capability-control/overlay.d.ts +15 -0
  20. package/dist/capability-control/overlay.js +27 -0
  21. package/dist/cc-orchestrator/agent-adapter.d.ts +50 -0
  22. package/dist/cc-orchestrator/agent-adapter.js +133 -0
  23. package/dist/cc-orchestrator/cc-capability.d.ts +19 -0
  24. package/dist/cc-orchestrator/cc-capability.js +53 -0
  25. package/dist/cc-orchestrator/codex-session-discovery.d.ts +24 -0
  26. package/dist/cc-orchestrator/codex-session-discovery.js +191 -0
  27. package/dist/cc-orchestrator/codex-session-history.d.ts +25 -0
  28. package/dist/cc-orchestrator/codex-session-history.js +187 -0
  29. package/dist/cc-orchestrator/external-agent-changes.d.ts +19 -0
  30. package/dist/cc-orchestrator/external-agent-changes.js +214 -0
  31. package/dist/cc-orchestrator/external-agent-driver.d.ts +18 -0
  32. package/dist/cc-orchestrator/external-agent-driver.js +69 -0
  33. package/dist/cc-orchestrator/index.d.ts +8 -0
  34. package/dist/cc-orchestrator/index.js +8 -0
  35. package/dist/cc-orchestrator/relevance-judge.d.ts +15 -0
  36. package/dist/cc-orchestrator/relevance-judge.js +29 -0
  37. package/dist/cc-orchestrator/session-discovery.d.ts +46 -0
  38. package/dist/cc-orchestrator/session-discovery.js +125 -0
  39. package/dist/cc-orchestrator/session-history.d.ts +19 -0
  40. package/dist/cc-orchestrator/session-history.js +67 -0
  41. package/dist/cli/agent-server-stdio.d.ts +15 -1
  42. package/dist/cli/agent-server-stdio.js +115 -17
  43. package/dist/cli/agent-server-tcp.js +40 -26
  44. package/dist/context/compaction.d.ts +56 -0
  45. package/dist/context/compaction.js +186 -0
  46. package/dist/context/manager.js +25 -4
  47. package/dist/cost-tracker.js +5 -61
  48. package/dist/credentials/cipher.d.ts +49 -0
  49. package/dist/credentials/cipher.js +45 -0
  50. package/dist/credentials/cookie-jar.d.ts +24 -0
  51. package/dist/credentials/cookie-jar.js +40 -0
  52. package/dist/credentials/index.d.ts +7 -0
  53. package/dist/credentials/index.js +5 -0
  54. package/dist/credentials/inject-credential-tool.d.ts +20 -0
  55. package/dist/credentials/inject-credential-tool.js +130 -0
  56. package/dist/credentials/store.d.ts +72 -0
  57. package/dist/credentials/store.js +184 -0
  58. package/dist/credentials/types.d.ts +56 -0
  59. package/dist/credentials/use-credential-tool.d.ts +29 -0
  60. package/dist/credentials/use-credential-tool.js +205 -0
  61. package/dist/credentials/use-gate.d.ts +56 -0
  62. package/dist/credentials/use-gate.js +52 -0
  63. package/dist/data/model-metadata.d.ts +77 -0
  64. package/dist/data/model-metadata.js +56 -0
  65. package/dist/data/model-metadata.json +216 -0
  66. package/dist/data/openrouter-models.d.ts +18 -7
  67. package/dist/data/openrouter-models.js +35 -8
  68. package/dist/engine/aux-key.d.ts +10 -0
  69. package/dist/engine/aux-key.js +11 -0
  70. package/dist/engine/dynamic-tool-defs.d.ts +19 -0
  71. package/dist/engine/dynamic-tool-defs.js +36 -0
  72. package/dist/engine/engine.d.ts +267 -138
  73. package/dist/engine/engine.js +957 -191
  74. package/dist/engine/friendly-error.d.ts +18 -0
  75. package/dist/engine/friendly-error.js +63 -0
  76. package/dist/engine/goal.d.ts +145 -0
  77. package/dist/engine/goal.js +144 -0
  78. package/dist/engine/image-policy.d.ts +13 -0
  79. package/dist/engine/image-policy.js +24 -0
  80. package/dist/engine/model-connections-pool.d.ts +17 -0
  81. package/dist/engine/model-connections-pool.js +66 -0
  82. package/dist/engine/model-facade.d.ts +10 -0
  83. package/dist/engine/model-facade.js +25 -0
  84. package/dist/engine/patch-orphaned-tools.js +3 -0
  85. package/dist/engine/resolve-llm-config.d.ts +16 -0
  86. package/dist/engine/resolve-llm-config.js +44 -0
  87. package/dist/engine/runtime.js +2 -1
  88. package/dist/engine/sandbox-cache-key.d.ts +10 -0
  89. package/dist/engine/sandbox-cache-key.js +9 -0
  90. package/dist/engine/sandbox-config.d.ts +31 -0
  91. package/dist/engine/sandbox-config.js +38 -0
  92. package/dist/engine/session-usage.d.ts +19 -0
  93. package/dist/engine/session-usage.js +25 -0
  94. package/dist/engine/steer-queue.d.ts +32 -0
  95. package/dist/engine/steer-queue.js +26 -0
  96. package/dist/engine/streaming-tool-queue.d.ts +12 -0
  97. package/dist/engine/streaming-tool-queue.js +50 -10
  98. package/dist/engine/turn-loop.d.ts +67 -3
  99. package/dist/engine/turn-loop.js +292 -41
  100. package/dist/engine/types.d.ts +175 -0
  101. package/dist/engine/types.js +13 -0
  102. package/dist/external-agents/config.d.ts +2 -0
  103. package/dist/external-agents/config.js +15 -0
  104. package/dist/external-agents/types.d.ts +31 -0
  105. package/dist/external-agents/types.js +1 -0
  106. package/dist/git/utils.js +11 -6
  107. package/dist/git/worktree.d.ts +48 -0
  108. package/dist/git/worktree.js +86 -10
  109. package/dist/hooks/goal-stop-hook.d.ts +28 -0
  110. package/dist/hooks/goal-stop-hook.js +186 -9
  111. package/dist/hooks/registry.d.ts +8 -0
  112. package/dist/hooks/registry.js +19 -0
  113. package/dist/hooks/shell-runner.js +10 -21
  114. package/dist/index.d.ts +49 -6
  115. package/dist/index.js +60 -4
  116. package/dist/llm/capabilities/param-specs.d.ts +14 -0
  117. package/dist/llm/capabilities/param-specs.js +62 -0
  118. package/dist/llm/capabilities/rules.js +4 -0
  119. package/dist/llm/capabilities/types.d.ts +10 -0
  120. package/dist/llm/client-base.d.ts +28 -1
  121. package/dist/llm/client-base.js +119 -13
  122. package/dist/llm/model-cache.js +4 -2
  123. package/dist/llm/model-pool.d.ts +14 -0
  124. package/dist/llm/model-pool.js +13 -0
  125. package/dist/llm/provider-auth.d.ts +41 -0
  126. package/dist/llm/provider-auth.js +76 -0
  127. package/dist/llm/provider-catalog.d.ts +4 -0
  128. package/dist/llm/providers/anthropic.js +64 -14
  129. package/dist/llm/providers/openai.d.ts +36 -0
  130. package/dist/llm/providers/openai.js +257 -51
  131. package/dist/llm/reasoning-setting.d.ts +3 -3
  132. package/dist/llm/reasoning-setting.js +9 -1
  133. package/dist/llm/stream-watchdog.js +5 -1
  134. package/dist/llm/token-counter.js +9 -2
  135. package/dist/llm/types.d.ts +4 -0
  136. package/dist/logging/sanitize-messages.js +22 -0
  137. package/dist/lsp/manager.d.ts +1 -1
  138. package/dist/lsp/manager.js +40 -10
  139. package/dist/model-catalog/builtin.d.ts +12 -0
  140. package/dist/model-catalog/builtin.js +407 -0
  141. package/dist/model-catalog/gen-connections.d.ts +20 -0
  142. package/dist/model-catalog/gen-connections.js +28 -0
  143. package/dist/model-catalog/index.d.ts +41 -0
  144. package/dist/model-catalog/index.js +90 -0
  145. package/dist/model-catalog/params.d.ts +20 -0
  146. package/dist/model-catalog/params.js +45 -0
  147. package/dist/model-catalog/resolve.d.ts +48 -0
  148. package/dist/model-catalog/resolve.js +33 -0
  149. package/dist/model-catalog/save-entry.d.ts +32 -0
  150. package/dist/model-catalog/save-entry.js +104 -0
  151. package/dist/model-catalog/types.d.ts +561 -0
  152. package/dist/model-catalog/types.js +93 -0
  153. package/dist/model-catalog/upsert.d.ts +9 -0
  154. package/dist/model-catalog/upsert.js +8 -0
  155. package/dist/onboarding.d.ts +12 -82
  156. package/dist/onboarding.js +61 -326
  157. package/dist/plugins/gitOps.d.ts +19 -0
  158. package/dist/plugins/gitOps.js +73 -4
  159. package/dist/plugins/installer/checkUpdate.d.ts +16 -0
  160. package/dist/plugins/installer/checkUpdate.js +32 -0
  161. package/dist/plugins/installer/codex/convertCommands.d.ts +19 -0
  162. package/dist/plugins/installer/codex/convertCommands.js +46 -0
  163. package/dist/plugins/installer/codex/convertMcp.d.ts +5 -2
  164. package/dist/plugins/installer/codex/convertMcp.js +45 -5
  165. package/dist/plugins/installer/install.js +25 -1
  166. package/dist/plugins/installer/installFromArchive.d.ts +43 -0
  167. package/dist/plugins/installer/installFromArchive.js +134 -0
  168. package/dist/plugins/installer/installFromSource.js +8 -2
  169. package/dist/plugins/installer/loadPluginAgents.js +6 -2
  170. package/dist/plugins/installer/loadPluginMcp.d.ts +9 -2
  171. package/dist/plugins/installer/loadPluginMcp.js +35 -2
  172. package/dist/plugins/installer/pruneDisabled.d.ts +24 -0
  173. package/dist/plugins/installer/pruneDisabled.js +73 -0
  174. package/dist/plugins/installer/types.d.ts +5 -2
  175. package/dist/plugins/installer/types.js +1 -0
  176. package/dist/plugins/installer/uninstall.js +4 -0
  177. package/dist/plugins/installer/unzip.d.ts +14 -0
  178. package/dist/plugins/installer/unzip.js +82 -0
  179. package/dist/plugins/installer/update.d.ts +14 -0
  180. package/dist/plugins/installer/update.js +53 -21
  181. package/dist/plugins/loadPluginHooks.d.ts +47 -1
  182. package/dist/plugins/loadPluginHooks.js +73 -1
  183. package/dist/plugins/marketplaceManager.d.ts +7 -0
  184. package/dist/plugins/marketplaceManager.js +20 -0
  185. package/dist/plugins/pluginCommandHook.js +4 -18
  186. package/dist/plugins/pluginContent.d.ts +30 -0
  187. package/dist/plugins/pluginContent.js +83 -0
  188. package/dist/plugins/pluginInstaller.d.ts +13 -0
  189. package/dist/plugins/pluginInstaller.js +42 -8
  190. package/dist/plugins/schemas.js +1 -0
  191. package/dist/plugins/types.d.ts +6 -0
  192. package/dist/preset/index.d.ts +7 -1
  193. package/dist/preset/index.js +96 -6
  194. package/dist/product/types.d.ts +1 -1
  195. package/dist/prompt/composer.d.ts +27 -0
  196. package/dist/prompt/composer.js +67 -21
  197. package/dist/prompt/instruction-scanner.js +5 -3
  198. package/dist/prompt/section-loader.js +1 -0
  199. package/dist/prompt/sections/base.md +1 -0
  200. package/dist/prompt/sections/browser.md +10 -0
  201. package/dist/prompt/sections/coding.md +4 -0
  202. package/dist/protocol/chat-session-manager.d.ts +8 -2
  203. package/dist/protocol/chat-session-manager.js +36 -0
  204. package/dist/protocol/chat-session.d.ts +65 -0
  205. package/dist/protocol/chat-session.js +94 -2
  206. package/dist/protocol/client.d.ts +27 -0
  207. package/dist/protocol/client.js +38 -0
  208. package/dist/protocol/server.d.ts +112 -0
  209. package/dist/protocol/server.js +586 -16
  210. package/dist/protocol/transport.js +3 -2
  211. package/dist/protocol/types.d.ts +46 -0
  212. package/dist/protocol/types.js +16 -0
  213. package/dist/quota/credentials.d.ts +3 -0
  214. package/dist/quota/credentials.js +80 -0
  215. package/dist/quota/index.d.ts +36 -0
  216. package/dist/quota/index.js +155 -0
  217. package/dist/quota/types.d.ts +48 -0
  218. package/dist/quota/types.js +13 -0
  219. package/dist/review/review-prompt.d.ts +28 -0
  220. package/dist/review/review-prompt.js +81 -0
  221. package/dist/run/FileRunStore.js +8 -3
  222. package/dist/run/RunApprovalBackend.js +25 -5
  223. package/dist/run/RunManager.d.ts +12 -0
  224. package/dist/run/RunManager.js +35 -0
  225. package/dist/run/factory.d.ts +1 -1
  226. package/dist/runtime/background-shell.d.ts +139 -0
  227. package/dist/runtime/background-shell.js +495 -0
  228. package/dist/runtime/output-clean.d.ts +24 -0
  229. package/dist/runtime/output-clean.js +41 -0
  230. package/dist/runtime/ring-file.d.ts +64 -0
  231. package/dist/runtime/ring-file.js +174 -0
  232. package/dist/runtime/safe-spawn.js +15 -34
  233. package/dist/runtime/spawn-common.d.ts +148 -0
  234. package/dist/runtime/spawn-common.js +303 -0
  235. package/dist/runtime/truncate-output.d.ts +22 -0
  236. package/dist/runtime/truncate-output.js +49 -0
  237. package/dist/runtime/utf8-cut.d.ts +11 -0
  238. package/dist/runtime/utf8-cut.js +23 -0
  239. package/dist/services/auto-dream.d.ts +4 -0
  240. package/dist/services/auto-dream.js +26 -26
  241. package/dist/services/diagnostics.d.ts +1 -2
  242. package/dist/services/diagnostics.js +12 -7
  243. package/dist/services/extract-memories.d.ts +14 -1
  244. package/dist/services/extract-memories.js +45 -6
  245. package/dist/services/memory-orchestrator.d.ts +21 -0
  246. package/dist/services/memory-orchestrator.js +125 -50
  247. package/dist/services/session-memory.js +24 -12
  248. package/dist/session/file-history.d.ts +124 -1
  249. package/dist/session/file-history.js +222 -6
  250. package/dist/session/memory.d.ts +116 -2
  251. package/dist/session/memory.js +250 -28
  252. package/dist/session/session-manager.d.ts +40 -0
  253. package/dist/session/session-manager.js +113 -3
  254. package/dist/session/simple-diff.d.ts +23 -0
  255. package/dist/session/simple-diff.js +84 -0
  256. package/dist/session/transcript.d.ts +25 -1
  257. package/dist/session/transcript.js +35 -2
  258. package/dist/session/undo-target.d.ts +67 -0
  259. package/dist/session/undo-target.js +144 -0
  260. package/dist/settings/disk-defaults.d.ts +9 -2
  261. package/dist/settings/disk-defaults.js +11 -2
  262. package/dist/settings/feature-flags.d.ts +64 -0
  263. package/dist/settings/feature-flags.js +61 -0
  264. package/dist/settings/manager.d.ts +68 -1
  265. package/dist/settings/manager.js +266 -29
  266. package/dist/settings/migrate-config.d.ts +45 -0
  267. package/dist/settings/migrate-config.js +125 -0
  268. package/dist/settings/schema-export.d.ts +25 -0
  269. package/dist/settings/schema-export.js +38 -0
  270. package/dist/settings/schema.d.ts +1186 -771
  271. package/dist/settings/schema.js +268 -97
  272. package/dist/skills/scanner.d.ts +9 -0
  273. package/dist/skills/scanner.js +30 -2
  274. package/dist/stt/resolve-transcribe.d.ts +31 -0
  275. package/dist/stt/resolve-transcribe.js +108 -0
  276. package/dist/stt/transcribe.d.ts +51 -0
  277. package/dist/stt/transcribe.js +65 -0
  278. package/dist/tool-system/browser-bridge.d.ts +226 -0
  279. package/dist/tool-system/browser-bridge.js +163 -0
  280. package/dist/tool-system/builtin/agent-heartbeat.d.ts +49 -0
  281. package/dist/tool-system/builtin/agent-heartbeat.js +89 -0
  282. package/dist/tool-system/builtin/agent-notifications.d.ts +12 -3
  283. package/dist/tool-system/builtin/agent-notifications.js +9 -3
  284. package/dist/tool-system/builtin/agent-output-file.d.ts +38 -0
  285. package/dist/tool-system/builtin/agent-output-file.js +72 -0
  286. package/dist/tool-system/builtin/agent-registry.d.ts +12 -0
  287. package/dist/tool-system/builtin/agent-registry.js +8 -0
  288. package/dist/tool-system/builtin/agent.d.ts +21 -1
  289. package/dist/tool-system/builtin/agent.js +489 -42
  290. package/dist/tool-system/builtin/apply-patch/applier.js +66 -8
  291. package/dist/tool-system/builtin/apply-patch/backup-targets.d.ts +10 -0
  292. package/dist/tool-system/builtin/apply-patch/backup-targets.js +30 -0
  293. package/dist/tool-system/builtin/apply-patch/index.js +0 -15
  294. package/dist/tool-system/builtin/background-jobs.d.ts +76 -0
  295. package/dist/tool-system/builtin/background-jobs.js +124 -0
  296. package/dist/tool-system/builtin/background-shell-tools.d.ts +20 -0
  297. package/dist/tool-system/builtin/background-shell-tools.js +108 -0
  298. package/dist/tool-system/builtin/background-work.d.ts +67 -0
  299. package/dist/tool-system/builtin/background-work.js +86 -0
  300. package/dist/tool-system/builtin/bash-output-style.d.ts +32 -0
  301. package/dist/tool-system/builtin/bash-output-style.js +40 -0
  302. package/dist/tool-system/builtin/bash.d.ts +5 -2
  303. package/dist/tool-system/builtin/bash.js +98 -62
  304. package/dist/tool-system/builtin/browser-tools.d.ts +33 -0
  305. package/dist/tool-system/builtin/browser-tools.js +312 -0
  306. package/dist/tool-system/builtin/cancel-goal.d.ts +31 -0
  307. package/dist/tool-system/builtin/cancel-goal.js +64 -0
  308. package/dist/tool-system/builtin/check-quota.d.ts +15 -0
  309. package/dist/tool-system/builtin/check-quota.js +34 -0
  310. package/dist/tool-system/builtin/config.js +7 -0
  311. package/dist/tool-system/builtin/cron.d.ts +7 -0
  312. package/dist/tool-system/builtin/cron.js +55 -3
  313. package/dist/tool-system/builtin/drive-claude-code.d.ts +30 -0
  314. package/dist/tool-system/builtin/drive-claude-code.js +157 -0
  315. package/dist/tool-system/builtin/edit-model-catalog.d.ts +3 -0
  316. package/dist/tool-system/builtin/edit-model-catalog.js +94 -0
  317. package/dist/tool-system/builtin/edit.js +20 -16
  318. package/dist/tool-system/builtin/eol.d.ts +29 -0
  319. package/dist/tool-system/builtin/eol.js +37 -0
  320. package/dist/tool-system/builtin/file-cache.d.ts +6 -0
  321. package/dist/tool-system/builtin/file-cache.js +8 -0
  322. package/dist/tool-system/builtin/generate-image.d.ts +35 -0
  323. package/dist/tool-system/builtin/generate-image.js +278 -50
  324. package/dist/tool-system/builtin/generate-video.d.ts +55 -0
  325. package/dist/tool-system/builtin/generate-video.js +361 -0
  326. package/dist/tool-system/builtin/glob.js +0 -7
  327. package/dist/tool-system/builtin/grep.js +6 -8
  328. package/dist/tool-system/builtin/image-providers.d.ts +86 -0
  329. package/dist/tool-system/builtin/image-providers.js +190 -0
  330. package/dist/tool-system/builtin/image-uploader.d.ts +33 -0
  331. package/dist/tool-system/builtin/image-uploader.js +74 -0
  332. package/dist/tool-system/builtin/index.d.ts +7 -1
  333. package/dist/tool-system/builtin/index.js +249 -25
  334. package/dist/tool-system/builtin/mcp-tools.js +23 -3
  335. package/dist/tool-system/builtin/memory.js +45 -7
  336. package/dist/tool-system/builtin/notebook-edit.js +0 -7
  337. package/dist/tool-system/builtin/powershell.js +4 -1
  338. package/dist/tool-system/builtin/read.js +10 -10
  339. package/dist/tool-system/builtin/repl.js +4 -1
  340. package/dist/tool-system/builtin/skill.js +9 -0
  341. package/dist/tool-system/builtin/sleep.js +3 -2
  342. package/dist/tool-system/builtin/tool-search.js +25 -7
  343. package/dist/tool-system/builtin/video-providers.d.ts +154 -0
  344. package/dist/tool-system/builtin/video-providers.js +235 -0
  345. package/dist/tool-system/builtin/web-fetch.js +12 -2
  346. package/dist/tool-system/builtin/web-search.js +21 -7
  347. package/dist/tool-system/builtin/worktree.d.ts +2 -1
  348. package/dist/tool-system/builtin/worktree.js +31 -4
  349. package/dist/tool-system/builtin/write.js +0 -6
  350. package/dist/tool-system/context.d.ts +154 -6
  351. package/dist/tool-system/executor.d.ts +3 -1
  352. package/dist/tool-system/executor.js +172 -88
  353. package/dist/tool-system/investigation-guard.js +1 -1
  354. package/dist/tool-system/mcp-manager.d.ts +42 -4
  355. package/dist/tool-system/mcp-manager.js +186 -20
  356. package/dist/tool-system/path-policy.d.ts +5 -0
  357. package/dist/tool-system/path-policy.js +307 -8
  358. package/dist/tool-system/permission.d.ts +36 -1
  359. package/dist/tool-system/permission.js +281 -69
  360. package/dist/tool-system/plan-mode-allowlist.d.ts +13 -2
  361. package/dist/tool-system/plan-mode-allowlist.js +24 -2
  362. package/dist/tool-system/registry.d.ts +1 -0
  363. package/dist/tool-system/registry.js +16 -2
  364. package/dist/tool-system/sandbox/index.d.ts +8 -0
  365. package/dist/tool-system/sandbox/index.js +7 -2
  366. package/dist/tool-system/validate-tool-metadata.d.ts +36 -0
  367. package/dist/tool-system/validate-tool-metadata.js +63 -0
  368. package/dist/types.d.ts +217 -6
  369. package/dist/updater.js +20 -9
  370. package/dist/utils/envUtils.d.ts +0 -9
  371. package/dist/utils/envUtils.js +3 -28
  372. package/dist/utils/exec.d.ts +40 -0
  373. package/dist/utils/exec.js +144 -0
  374. package/dist/utils/json.d.ts +12 -0
  375. package/dist/utils/json.js +92 -0
  376. package/dist/utils/theme.d.ts +1 -1
  377. package/dist/utils/theme.js +1 -1
  378. package/dist/utils/toolDisplay.js +0 -1
  379. package/package.json +13 -7
  380. package/dist/agent/coordinator.d.ts +0 -49
  381. package/dist/agent/coordinator.js +0 -77
  382. package/dist/settings/manager.test.js +0 -73
  383. package/dist/tool-system/builtin/remote-trigger.d.ts +0 -6
  384. package/dist/tool-system/builtin/remote-trigger.js +0 -54
  385. package/dist/tool-system/builtin/send-message.d.ts +0 -6
  386. package/dist/tool-system/builtin/send-message.js +0 -47
  387. /package/dist/{settings/manager.test.d.ts → credentials/types.js} +0 -0
@@ -4,6 +4,8 @@
4
4
  * (see src/ui/components/OnboardingPrompt.tsx); this module only exposes
5
5
  * pure(-ish) helpers it consumes, so there's a single input stack.
6
6
  */
7
+ import { PROVIDERS, type ProviderDef } from "./data/model-metadata.js";
8
+ export { PROVIDERS, type ProviderDef };
7
9
  export interface OnboardingResult {
8
10
  /**
9
11
  * Pool alias key (e.g. "deepseek-v4-pro"). The engine uses this to switch
@@ -17,25 +19,6 @@ export interface OnboardingResult {
17
19
  apiKey: string;
18
20
  baseUrl: string;
19
21
  }
20
- export interface ProviderDef {
21
- id: string;
22
- name: string;
23
- envKey: string;
24
- provider: string;
25
- baseUrl: string;
26
- keyUrl: string;
27
- keyPrefix: string;
28
- /**
29
- * The catalog of model IDs to register for this provider. The first
30
- * entry doubles as the zero-config default — auto-activated when the
31
- * user boots with just an env key (no onboarding). Users override by
32
- * picking in the wizard or running `/model`.
33
- */
34
- models: string[];
35
- /** When true, skip API key prompt (e.g. local providers like Ollama). */
36
- noKey?: boolean;
37
- }
38
- export declare const PROVIDERS: ProviderDef[];
39
22
  /**
40
23
  * Resolve the model list a provider should expose right now. For
41
24
  * OpenRouter this comes from the snapshot; for direct providers it
@@ -65,26 +48,6 @@ export declare function validateApiKey(baseUrl: string, apiKey: string): Promise
65
48
  * Priority: 1) command-line option 2) settings.json 3) all provider env vars
66
49
  */
67
50
  export declare function resolveApiKey(optionsApiKey?: string, settingsApiKey?: string): string | undefined;
68
- /**
69
- * Look up a previously-persisted API key for a given provider in
70
- * ~/.code-shell/settings.json. Matches by baseUrl (each ProviderDef.baseUrl
71
- * is unique, while `provider` is a generic kind like "openai" shared across
72
- * multiple endpoints).
73
- *
74
- * Returns the first match found in: settings.models[] (preferred — newer),
75
- * then settings.model (legacy top-level). undefined when nothing matches.
76
- */
77
- export declare function findSavedKeyForProvider(provider: ProviderDef): {
78
- apiKey: string;
79
- baseUrl: string;
80
- } | undefined;
81
- /**
82
- * Return the list of model IDs previously saved under this provider
83
- * (matched by baseUrl). Used by the onboarding wizard to pre-populate the
84
- * "model pool" step with the user's prior choices instead of resetting to
85
- * just the provider's first model.
86
- */
87
- export declare function loadSavedModelsForProvider(provider: ProviderDef): string[];
88
51
  export declare function hasApiKey(): boolean;
89
52
  /**
90
53
  * Resolve a model's max-output-token budget. Lookup order:
@@ -135,55 +98,22 @@ export declare function buildModelPool(provider: ProviderDef, apiKey: string): A
135
98
  maxContextTokens?: number;
136
99
  }>;
137
100
  export declare function modelDisplayName(model: string): string;
138
- export declare function saveSettings(result: OnboardingResult, providerDef?: ProviderDef, poolModels?: string[]): void;
139
101
  /**
140
- * Append-only persistence for the new ProviderModelFlow-based onboarding.
141
- *
142
- * Writes the new shape:
143
- * - settings.activeKey — primary source of truth for active model
144
- * - settings.models[] — self-describing entries (key, provider,
145
- * model, baseUrl, apiKey, maxOutput, maxContext)
146
- * - settings.providers[] — credential source for the wizard
147
- * - settings.model.* — legacy mirror of the active entry, kept in
148
- * sync so legacy boot paths (cli/main.ts,
149
- * repl.ts, run.ts) keep working without
150
- * each having to learn about activeKey
151
- *
152
- * Append-only: never removes existing entries. To start over use /logout.
153
- * Writes atomically via tmp+rename.
102
+ * 持久化 onboarding 结果到统一 catalog(credentials + modelConnections +
103
+ * defaults.text)。Append-only:相同 instanceId 跳过。defaults.text 设为 activeId。
104
+ * 原子写(tmp+rename)。(旧版写 legacy model.* / models / providers / activeKey,已删)
154
105
  */
155
106
  export declare function appendOnboardingResult(opts: {
156
- /** Alias key the engine should switch to after writing. Matches one of addedModels[].key. */
157
- activeKey: string;
158
- /** Active entry's fields, used to mirror into the legacy settings.model.* block. */
159
- activeMirror: {
160
- provider: string;
161
- model: string;
162
- apiKey: string;
163
- baseUrl: string;
164
- };
165
- addedProvider?: {
166
- key: string;
167
- label?: string;
107
+ /** 本次新增的模型实例(每个成为一个 modelConnection + credential)。 */
108
+ models: Array<{
109
+ instanceId: string;
168
110
  kind: string;
169
- baseUrl: string;
170
- apiKey?: string;
171
- protocol?: string;
172
- modelsPath?: string;
173
- };
174
- addedModels: Array<{
175
- key: string;
176
- label?: string;
177
- providerKey?: string;
178
- /** LLM client/protocol ("openai"/"anthropic"). New canonical name. */
179
- protocol?: string;
180
- /** Legacy mirror of `protocol`. Both are written so legacy readers keep working. */
181
- provider?: string;
182
111
  model: string;
183
- baseUrl: string;
184
112
  apiKey?: string;
185
- maxContextTokens?: number;
186
- maxOutputTokens?: number;
113
+ baseUrl?: string;
187
114
  }>;
115
+ /** 选中的活跃实例 id(写入 defaults.text)。 */
116
+ activeId: string;
117
+ tag?: "text" | "image" | "video";
188
118
  }): void;
189
119
  export declare function saveArenaSettingsByKeys(keys: string[]): void;
@@ -4,137 +4,19 @@
4
4
  * (see src/ui/components/OnboardingPrompt.tsx); this module only exposes
5
5
  * pure(-ish) helpers it consumes, so there's a single input stack.
6
6
  */
7
- import { mkdirSync, writeFileSync, readFileSync, existsSync, renameSync, rmSync } from "node:fs";
7
+ import { mkdirSync, writeFileSync, readFileSync, existsSync, renameSync, rmSync, chmodSync } from "node:fs";
8
8
  import { join } from "node:path";
9
9
  import { userHome } from "./settings/manager.js";
10
10
  import { getOpenRouterModels } from "./data/openrouter-models.js";
11
+ import { KNOWN_MAX_OUTPUT, KNOWN_CONTEXT_WINDOWS, OPENROUTER_VENDORS, PROVIDERS, } from "./data/model-metadata.js";
12
+ // Re-exported so existing importers (and tests) can keep importing from
13
+ // onboarding; the catalog data itself now lives in data/model-metadata.json.
14
+ export { PROVIDERS };
11
15
  import { sanitizeApiKey } from "./llm/api-key-sanitize.js";
12
- export const PROVIDERS = [
13
- {
14
- id: "openrouter",
15
- name: "OpenRouter (推荐 — 支持所有模型)",
16
- envKey: "OPENROUTER_API_KEY",
17
- provider: "openai",
18
- baseUrl: "https://openrouter.ai/api/v1",
19
- keyUrl: "https://openrouter.ai/keys",
20
- keyPrefix: "sk-or-",
21
- // First entry is the zero-config default (auto-activated when the
22
- // user starts with only an env key, no onboarding). Sonnet beats Opus
23
- // here because it's ~5x cheaper and a safer pick for someone who
24
- // hasn't picked yet — Opus stays one slot away for anyone who wants it.
25
- models: [
26
- "anthropic/claude-sonnet-4.6",
27
- "anthropic/claude-opus-4.7",
28
- "anthropic/claude-haiku-4.5",
29
- "openai/gpt-5",
30
- "openai/gpt-5-mini",
31
- "openai/gpt-4o",
32
- "openai/o4-mini",
33
- "openai/o3",
34
- "google/gemini-2.5-pro",
35
- "google/gemini-2.5-flash",
36
- "deepseek/deepseek-chat",
37
- "deepseek/deepseek-reasoner",
38
- "qwen/qwen3-coder",
39
- "meta-llama/llama-4-maverick",
40
- ],
41
- },
42
- {
43
- id: "anthropic",
44
- name: "Anthropic (直连 Claude API)",
45
- envKey: "ANTHROPIC_API_KEY",
46
- provider: "anthropic",
47
- baseUrl: "https://api.anthropic.com",
48
- keyUrl: "https://console.anthropic.com/settings/keys",
49
- keyPrefix: "sk-ant-",
50
- models: [
51
- "claude-sonnet-4-6",
52
- "claude-opus-4-7",
53
- "claude-haiku-4-5",
54
- ],
55
- },
56
- {
57
- id: "openai",
58
- name: "OpenAI",
59
- envKey: "OPENAI_API_KEY",
60
- provider: "openai",
61
- baseUrl: "https://api.openai.com/v1",
62
- keyUrl: "https://platform.openai.com/api-keys",
63
- keyPrefix: "sk-",
64
- models: ["gpt-5", "gpt-5-mini", "gpt-5-nano", "gpt-4o", "o4-mini", "o3"],
65
- },
66
- {
67
- id: "deepseek",
68
- name: "DeepSeek (官方直连)",
69
- envKey: "DEEPSEEK_API_KEY",
70
- provider: "openai",
71
- baseUrl: "https://api.deepseek.com/v1",
72
- keyUrl: "https://platform.deepseek.com/api_keys",
73
- keyPrefix: "sk-",
74
- models: ["deepseek-v4-pro", "deepseek-v4-flash", "deepseek-chat"],
75
- },
76
- {
77
- id: "zai",
78
- name: "Z.AI (GLM 官方)",
79
- envKey: "ZAI_API_KEY",
80
- provider: "openai",
81
- baseUrl: "https://api.z.ai/api/paas/v4",
82
- keyUrl: "https://z.ai/manage-apikey/apikey-list",
83
- keyPrefix: "",
84
- models: ["glm-5.1", "glm-4.6", "glm-4.5-air"],
85
- },
86
- {
87
- id: "gemini",
88
- name: "Google Gemini (官方直连)",
89
- envKey: "GEMINI_API_KEY",
90
- provider: "openai",
91
- baseUrl: "https://generativelanguage.googleapis.com/v1beta/openai",
92
- keyUrl: "https://aistudio.google.com/apikey",
93
- keyPrefix: "",
94
- models: [
95
- "gemini-2.5-pro",
96
- "gemini-2.5-flash",
97
- "gemini-2.0-flash",
98
- ],
99
- },
100
- {
101
- id: "ollama",
102
- name: "Ollama (本地,无需 Key)",
103
- envKey: "",
104
- provider: "openai",
105
- baseUrl: "http://localhost:11434/v1",
106
- keyUrl: "https://ollama.com/library",
107
- keyPrefix: "",
108
- models: ["llama3.1", "qwen2.5-coder", "deepseek-r1", "mistral", "gemma3"],
109
- noKey: true,
110
- },
111
- {
112
- id: "custom",
113
- name: "自定义 (任何 OpenAI 兼容 API)",
114
- envKey: "",
115
- provider: "openai",
116
- baseUrl: "",
117
- keyUrl: "",
118
- keyPrefix: "",
119
- models: [],
120
- },
121
- ];
16
+ import { getMergedCatalog } from "./model-catalog/index.js";
17
+ // ProviderDef 类型 + PROVIDERS 目录已外移到 data/model-metadata.json
18
+ // (loader: data/model-metadata.ts),并在文件顶部 re-export。core 只读目录数据。
122
19
  // ─── Dynamic model list (OpenRouter snapshot) ────────────────────
123
- /**
124
- * Curated vendors and how many of their newest models to surface in the
125
- * onboarding picker. Order matters — first vendors appear first.
126
- * Tweak this if a new vendor becomes worth exposing in the picker.
127
- */
128
- const OPENROUTER_VENDORS = [
129
- { prefix: "anthropic/", take: 4 },
130
- { prefix: "openai/", take: 5 },
131
- { prefix: "google/", take: 3 },
132
- { prefix: "deepseek/", take: 3 },
133
- { prefix: "x-ai/", take: 2 },
134
- { prefix: "qwen/", take: 2 },
135
- { prefix: "meta-llama/", take: 2 },
136
- { prefix: "mistralai/", take: 1 },
137
- ];
138
20
  /**
139
21
  * Build the OpenRouter model picker list from the bundled snapshot.
140
22
  * Filters out `:free`/preview variants for the default picker (still
@@ -226,9 +108,12 @@ export function detectProviderFromApiKey(apiKey, baseUrl) {
226
108
  // ─── API key validation ────────────────────────────────────────────
227
109
  export async function validateApiKey(baseUrl, apiKey) {
228
110
  try {
111
+ // 10s timeout so a hung/slow provider doesn't block the onboarding wizard
112
+ // until the OS socket timeout — AbortError is caught below → "let it pass".
229
113
  if (baseUrl.includes("openrouter")) {
230
114
  const res = await fetch("https://openrouter.ai/api/v1/auth/key", {
231
115
  headers: { Authorization: `Bearer ${apiKey}` },
116
+ signal: AbortSignal.timeout(10_000),
232
117
  });
233
118
  const data = await res.json();
234
119
  return !data.error;
@@ -236,6 +121,7 @@ export async function validateApiKey(baseUrl, apiKey) {
236
121
  const url = baseUrl.replace(/\/$/, "") + "/models";
237
122
  const res = await fetch(url, {
238
123
  headers: { Authorization: `Bearer ${apiKey}` },
124
+ signal: AbortSignal.timeout(10_000),
239
125
  });
240
126
  return res.status !== 401 && res.status !== 403;
241
127
  }
@@ -267,87 +153,21 @@ export function resolveApiKey(optionsApiKey, settingsApiKey) {
267
153
  }
268
154
  return undefined;
269
155
  }
270
- /**
271
- * Look up a previously-persisted API key for a given provider in
272
- * ~/.code-shell/settings.json. Matches by baseUrl (each ProviderDef.baseUrl
273
- * is unique, while `provider` is a generic kind like "openai" shared across
274
- * multiple endpoints).
275
- *
276
- * Returns the first match found in: settings.models[] (preferred — newer),
277
- * then settings.model (legacy top-level). undefined when nothing matches.
278
- */
279
- export function findSavedKeyForProvider(provider) {
280
- const file = join(userHome(), ".code-shell", "settings.json");
281
- if (!existsSync(file))
282
- return undefined;
283
- let data;
284
- try {
285
- data = JSON.parse(readFileSync(file, "utf-8"));
286
- }
287
- catch {
288
- return undefined;
289
- }
290
- if (Array.isArray(data?.models)) {
291
- for (const m of data.models) {
292
- if (m?.apiKey && m?.baseUrl === provider.baseUrl) {
293
- return { apiKey: String(m.apiKey), baseUrl: String(m.baseUrl) };
294
- }
295
- }
296
- }
297
- if (data?.model?.apiKey && data?.model?.baseUrl === provider.baseUrl) {
298
- return {
299
- apiKey: String(data.model.apiKey),
300
- baseUrl: String(data.model.baseUrl),
301
- };
302
- }
303
- return undefined;
304
- }
305
- /**
306
- * Return the list of model IDs previously saved under this provider
307
- * (matched by baseUrl). Used by the onboarding wizard to pre-populate the
308
- * "model pool" step with the user's prior choices instead of resetting to
309
- * just the provider's first model.
310
- */
311
- export function loadSavedModelsForProvider(provider) {
312
- const file = join(userHome(), ".code-shell", "settings.json");
313
- if (!existsSync(file))
314
- return [];
315
- let data;
316
- try {
317
- data = JSON.parse(readFileSync(file, "utf-8"));
318
- }
319
- catch {
320
- return [];
321
- }
322
- if (!Array.isArray(data?.models))
323
- return [];
324
- const out = [];
325
- for (const m of data.models) {
326
- if (m?.baseUrl === provider.baseUrl && typeof m?.model === "string") {
327
- out.push(m.model);
328
- }
329
- }
330
- return out;
331
- }
332
156
  export function hasApiKey() {
333
157
  // Env variables alone are NOT enough to skip onboarding — they're surfaced
334
158
  // as a one-click option on the provider page instead. We only skip when the
335
- // user has explicitly persisted a config. Checks all three locations the
336
- // wizard might write to: top-level model.apiKey (legacy), models[].apiKey
337
- // (per-pool-entry), providers[].apiKey (per-provider what the current
338
- // ProviderModelFlow actually writes). Missing any one of these made
339
- // /logout look like a no-op when the others still held credentials.
159
+ // user has explicitly persisted a config. Unified catalog: a credential with
160
+ // an apiKey, or any configured modelConnection, counts as "set up". The
161
+ // legacy model.apiKey / models[] / providers[] locations were removed.
340
162
  // Reads ~/.code-shell/ only — ~/.claude/ compat was dropped because Claude
341
163
  // Code's settings schema diverges and merging broke boot.
342
164
  const p = join(userHome(), ".code-shell", "settings.json");
343
165
  if (existsSync(p)) {
344
166
  try {
345
167
  const data = JSON.parse(readFileSync(p, "utf-8"));
346
- if (data?.model?.apiKey)
347
- return true;
348
- if (Array.isArray(data?.models) && data.models.some((m) => m?.apiKey))
168
+ if (Array.isArray(data?.credentials) && data.credentials.some((c) => c?.apiKey))
349
169
  return true;
350
- if (Array.isArray(data?.providers) && data.providers.some((p) => p?.apiKey))
170
+ if (Array.isArray(data?.modelConnections) && data.modelConnections.length > 0)
351
171
  return true;
352
172
  }
353
173
  catch { /* ignore */ }
@@ -355,54 +175,8 @@ export function hasApiKey() {
355
175
  return false;
356
176
  }
357
177
  // ─── Model pool helpers ───────────────────────────────────────────
358
- /** Known max output tokens for common models. */
359
- const KNOWN_MAX_OUTPUT = {
360
- "anthropic/claude-opus-4.7": 32000,
361
- "anthropic/claude-opus-4-7": 32000,
362
- "claude-opus-4-7": 32000,
363
- "anthropic/claude-sonnet-4.6": 16000,
364
- "anthropic/claude-sonnet-4-6": 16000,
365
- "claude-sonnet-4-6": 16000,
366
- "anthropic/claude-haiku-4.5": 8192,
367
- "anthropic/claude-haiku-4-5": 8192,
368
- "claude-haiku-4-5": 8192,
369
- "openai/gpt-5": 32000,
370
- "openai/gpt-5-mini": 32000,
371
- "openai/gpt-5-nano": 16000,
372
- "gpt-5": 32000,
373
- "gpt-5-mini": 32000,
374
- "gpt-5-nano": 16000,
375
- "openai/gpt-4o": 16384,
376
- "gpt-4o": 16384,
377
- "openai/o4-mini": 100000,
378
- "o4-mini": 100000,
379
- "openai/o3": 100000,
380
- "o3": 100000,
381
- "google/gemini-2.5-pro": 65536,
382
- "google/gemini-2.5-flash": 65536,
383
- "gemini-2.5-pro": 65536,
384
- "gemini-2.5-flash": 65536,
385
- "gemini-2.0-flash": 8192,
386
- "deepseek/deepseek-v3.2": 8192,
387
- "deepseek/deepseek-r1": 8192,
388
- "deepseek-v4-flash": 8192,
389
- "deepseek-v4-pro": 65536,
390
- "deepseek-chat": 8192,
391
- "qwen/qwen3-coder": 16384,
392
- "meta-llama/llama-4-maverick": 32000,
393
- };
394
- /**
395
- * Known context window sizes for direct-provider models (not routed through OpenRouter).
396
- * These are the models whose IDs don't include a "vendor/" prefix.
397
- */
398
- const KNOWN_CONTEXT_WINDOWS = {
399
- "deepseek-v4-pro": 1_000_000,
400
- "deepseek-v4-flash": 1_000_000,
401
- "deepseek-chat": 1_000_000,
402
- "deepseek/deepseek-chat": 1_000_000,
403
- "deepseek/deepseek-v4-pro": 1_000_000,
404
- "deepseek/deepseek-v4-flash": 1_000_000,
405
- };
178
+ // KNOWN_MAX_OUTPUT / KNOWN_CONTEXT_WINDOWS now live in data/model-metadata.json
179
+ // (imported above) so they can be updated without a code change.
406
180
  /**
407
181
  * Resolve a model's max-output-token budget. Lookup order:
408
182
  * 1. KNOWN_MAX_OUTPUT (covers direct providers like Anthropic/DeepSeek
@@ -505,57 +279,22 @@ export function modelDisplayName(model) {
505
279
  return `Gemini ${parts.slice(1).join("-")}`;
506
280
  return base.charAt(0).toUpperCase() + base.slice(1);
507
281
  }
508
- export function saveSettings(result, providerDef, poolModels) {
509
- const dir = join(userHome(), ".code-shell");
510
- const file = join(dir, "settings.json");
511
- mkdirSync(dir, { recursive: true });
512
- let existing = {};
513
- if (existsSync(file)) {
514
- try {
515
- existing = JSON.parse(readFileSync(file, "utf-8"));
516
- }
517
- catch { }
518
- }
519
- const updated = {
520
- ...existing,
521
- model: {
522
- ...(typeof existing.model === "object" ? existing.model : {}),
523
- provider: result.provider,
524
- name: result.model,
525
- apiKey: result.apiKey,
526
- baseUrl: result.baseUrl,
527
- },
528
- };
529
- // Merge model pool: keep entries from other providers (matched by baseUrl)
530
- // and replace just the current provider's slice. A naive overwrite would
531
- // wipe out every other provider's models every time the wizard runs.
532
- if (providerDef && poolModels && poolModels.length > 0) {
533
- const newEntries = buildModelPool(providerDef, result.apiKey).filter((e) => new Set(poolModels).has(e.model));
534
- const existingModels = Array.isArray(existing.models)
535
- ? existing.models
536
- : [];
537
- const otherProvider = existingModels.filter((e) => e?.baseUrl !== providerDef.baseUrl);
538
- updated.models = [...otherProvider, ...newEntries];
539
- }
540
- writeFileSync(file, JSON.stringify(updated, null, 2) + "\n", "utf-8");
282
+ /**
283
+ * Map a provider kind → catalogId. If a builtin (or user) TEXT catalog entry
284
+ * with id===kind exists, use it; otherwise fall back to the generic "custom"
285
+ * OpenAI-compatible entry. resolveInstance() returns null for an unknown
286
+ * catalogId, so every connection's catalogId MUST exist in the merged catalog.
287
+ */
288
+ function catalogIdForKind(kind) {
289
+ return getMergedCatalog().some((e) => e.id === kind && e.tag === "text") ? kind : "custom";
541
290
  }
542
291
  /**
543
- * Append-only persistence for the new ProviderModelFlow-based onboarding.
544
- *
545
- * Writes the new shape:
546
- * - settings.activeKey — primary source of truth for active model
547
- * - settings.models[] — self-describing entries (key, provider,
548
- * model, baseUrl, apiKey, maxOutput, maxContext)
549
- * - settings.providers[] — credential source for the wizard
550
- * - settings.model.* — legacy mirror of the active entry, kept in
551
- * sync so legacy boot paths (cli/main.ts,
552
- * repl.ts, run.ts) keep working without
553
- * each having to learn about activeKey
554
- *
555
- * Append-only: never removes existing entries. To start over use /logout.
556
- * Writes atomically via tmp+rename.
292
+ * 持久化 onboarding 结果到统一 catalog(credentials + modelConnections +
293
+ * defaults.text)。Append-only:相同 instanceId 跳过。defaults.text 设为 activeId。
294
+ * 原子写(tmp+rename)。(旧版写 legacy model.* / models / providers / activeKey,已删)
557
295
  */
558
296
  export function appendOnboardingResult(opts) {
297
+ const tag = opts.tag ?? "text";
559
298
  const dir = join(userHome(), ".code-shell");
560
299
  const file = join(dir, "settings.json");
561
300
  mkdirSync(dir, { recursive: true });
@@ -564,52 +303,44 @@ export function appendOnboardingResult(opts) {
564
303
  try {
565
304
  existing = JSON.parse(readFileSync(file, "utf-8"));
566
305
  }
567
- catch {
568
- /* ignore — corrupt file is replaced */
569
- }
306
+ catch { /* corrupt → replace */ }
570
307
  }
571
- // Append provider (skip if key already present).
572
- const existingProviders = Array.isArray(existing.providers)
573
- ? existing.providers
574
- : [];
575
- let providersOut = existingProviders;
576
- if (opts.addedProvider) {
577
- const has = existingProviders.some((p) => p?.key === opts.addedProvider.key);
578
- if (!has)
579
- providersOut = [...existingProviders, opts.addedProvider];
308
+ const creds = Array.isArray(existing.credentials)
309
+ ? [...existing.credentials] : [];
310
+ const conns = Array.isArray(existing.modelConnections)
311
+ ? [...existing.modelConnections] : [];
312
+ for (const m of opts.models) {
313
+ const catalogId = catalogIdForKind(m.kind);
314
+ const credId = `${m.instanceId}-key`;
315
+ if (!creds.some((c) => c?.id === credId)) {
316
+ creds.push({ id: credId, catalogId, apiKey: m.apiKey, baseUrl: m.baseUrl });
317
+ }
318
+ if (!conns.some((c) => c?.id === m.instanceId)) {
319
+ conns.push({
320
+ id: m.instanceId, catalogId, tag, model: m.model, credentialId: credId,
321
+ ...(m.baseUrl ? { baseUrl: m.baseUrl } : {}),
322
+ });
323
+ }
580
324
  }
581
- // Append models (skip entries whose key already exists — the wizard
582
- // already derives unique keys via deriveModelPoolKey, so a collision
583
- // means the user re-added the exact same alias and we leave the older
584
- // entry alone rather than silently overwriting credentials).
585
- const existingModels = Array.isArray(existing.models)
586
- ? existing.models
587
- : [];
588
- const existingKeys = new Set(existingModels.map((m) => m?.key));
589
- const modelsToAppend = opts.addedModels.filter((m) => !existingKeys.has(m.key));
325
+ const existingDefaults = (typeof existing.defaults === "object" && existing.defaults)
326
+ ? existing.defaults : {};
590
327
  const updated = {
591
328
  ...existing,
592
- activeKey: opts.activeKey,
593
- model: {
594
- ...(typeof existing.model === "object" && existing.model ? existing.model : {}),
595
- provider: opts.activeMirror.provider,
596
- name: opts.activeMirror.model,
597
- apiKey: opts.activeMirror.apiKey,
598
- baseUrl: opts.activeMirror.baseUrl,
599
- },
600
- providers: providersOut,
601
- models: [...existingModels, ...modelsToAppend],
329
+ credentials: creds,
330
+ modelConnections: conns,
331
+ defaults: { ...existingDefaults, [tag]: opts.activeId },
602
332
  };
603
333
  // Atomic write: tmp file in the same dir, then rename (atomic on POSIX).
334
+ // mode 0o600 — settings.json holds plaintext API keys, must be owner-only.
604
335
  const tmp = `${file}.${process.pid}.tmp`;
605
- writeFileSync(tmp, JSON.stringify(updated, null, 2) + "\n", "utf-8");
336
+ writeFileSync(tmp, JSON.stringify(updated, null, 2) + "\n", { encoding: "utf-8", mode: 0o600 });
606
337
  try {
607
338
  renameSync(tmp, file);
608
339
  }
609
340
  catch {
610
341
  // Fallback: best-effort direct write if rename fails (e.g. cross-device),
611
342
  // then remove the orphaned temp file the failed rename left behind.
612
- writeFileSync(file, JSON.stringify(updated, null, 2) + "\n", "utf-8");
343
+ writeFileSync(file, JSON.stringify(updated, null, 2) + "\n", { encoding: "utf-8", mode: 0o600 });
613
344
  rmSync(tmp, { force: true });
614
345
  }
615
346
  }
@@ -628,5 +359,9 @@ export function saveArenaSettingsByKeys(keys) {
628
359
  ...existing,
629
360
  arena: { participants: keys },
630
361
  };
631
- writeFileSync(file, JSON.stringify(updated, null, 2) + "\n", "utf-8");
362
+ writeFileSync(file, JSON.stringify(updated, null, 2) + "\n", { encoding: "utf-8", mode: 0o600 });
363
+ try {
364
+ chmodSync(file, 0o600);
365
+ }
366
+ catch { /* best-effort */ }
632
367
  }
@@ -21,6 +21,14 @@ export type GitResult = {
21
21
  ok: false;
22
22
  error: string;
23
23
  };
24
+ /**
25
+ * On a fresh macOS without the Command Line Tools, `/usr/bin/git` is an `xcrun`
26
+ * stub that spawns fine (so `isGitAvailable()`'s findExecutable check is fooled)
27
+ * but exits non-zero with an xcrun error on stderr. Classify that as a
28
+ * missing-git condition so runGit returns GIT_NOT_FOUND and the host shows the
29
+ * friendly "install Git" guidance instead of leaking the raw xcrun error.
30
+ */
31
+ export declare function isMissingDeveloperToolsStderr(stderr: string): boolean;
24
32
  /**
25
33
  * Force git to never prompt interactively. gitOps runs in headless contexts
26
34
  * (the Electron main process, the agent worker) that have no TTY, so a
@@ -47,10 +55,16 @@ export declare function nonInteractiveGitEnv(base: NodeJS.ProcessEnv): NodeJS.Pr
47
55
  * (.claude-plugin and .agents/plugins). On any failure of the sparse setup we
48
56
  * fall back to checking out the full tree, so correctness never depends on
49
57
  * sparse support being present.
58
+ *
59
+ * Pass `full: true` to skip sparse entirely and check out the whole tree. This
60
+ * is required when the caller reads arbitrary plugin content from the clone
61
+ * (installing a plugin or a plugin subdir), as opposed to a marketplace where
62
+ * only the manifest dirs are needed up front.
50
63
  */
51
64
  export declare function gitClone(url: string, destDir: string, options?: {
52
65
  ref?: string;
53
66
  sparsePaths?: string[];
67
+ full?: boolean;
54
68
  }): Promise<GitResult>;
55
69
  /**
56
70
  * Expand a sparse-checkout to include an additional path (a plugin subdir),
@@ -59,6 +73,11 @@ export declare function gitClone(url: string, destDir: string, options?: {
59
73
  */
60
74
  export declare function gitSparseCheckoutAdd(repoDir: string, relPath: string): Promise<GitResult>;
61
75
  export declare function gitRevParseHead(repoDir: string): Promise<GitResult>;
76
+ /**
77
+ * Resolve a ref (default HEAD) on a remote git URL WITHOUT cloning — one
78
+ * cheap network round-trip. Returns the 40-char SHA on success.
79
+ */
80
+ export declare function gitLsRemote(url: string, ref?: string): Promise<GitResult>;
62
81
  export declare function gitFetchAndReset(repoDir: string, ref?: string): Promise<GitResult>;
63
82
  /**
64
83
  * Github source helper: convert "owner/repo" to an https clone URL.