@jingyi0605/codingns 0.6.0 → 0.6.5

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 (253) hide show
  1. package/bin/codingns.mjs +240 -2
  2. package/dist/public/assets/AdaptiveButlerPage-CfsUVZKl.js +3 -0
  3. package/dist/public/assets/{App-BZvapsi8.js → App-B9HcTkMT.js} +3 -3
  4. package/dist/public/assets/{BootstrapPage-gHSoa4JN.js → BootstrapPage-BgLdZEKQ.js} +1 -1
  5. package/dist/public/assets/ConversationPage-Cj8go7L0.js +4 -0
  6. package/dist/public/assets/{DesktopDetachPreviewPage-4eMRxiBW.js → DesktopDetachPreviewPage-YCBnyC58.js} +1 -1
  7. package/dist/public/assets/DesktopWindowPage-CrvndE23.js +2 -0
  8. package/dist/public/assets/FileContextPanel-CdC7GGw5.js +1 -0
  9. package/dist/public/assets/GitSidebar-z2SBinQh.js +6 -0
  10. package/dist/public/assets/MobileCreateSessionSheet-Cb2HM-y3.js +1 -0
  11. package/dist/public/assets/{MobileTopHeaderFrame-Bwv8Ovm_.js → MobileTopHeaderFrame-etF2HKlm.js} +1 -1
  12. package/dist/public/assets/MobileWorkspaceSwitcherHeader-CuGJ31kb.js +1 -0
  13. package/dist/public/assets/{RelayConnectEntryPage-D_4YL-YH.js → RelayConnectEntryPage-BB6DbGtP.js} +1 -1
  14. package/dist/public/assets/{ServerSettingsModal-CMSm3BZU.js → ServerSettingsModal-Bl1sacZg.js} +1 -1
  15. package/dist/public/assets/SessionIndexPage-NbF9gJnp.js +1 -0
  16. package/dist/public/assets/SettingsPage-DGsmQpLv.js +1 -0
  17. package/dist/public/assets/TerminalManagerPanel-BOm8Hi_v.js +1 -0
  18. package/dist/public/assets/{TerminalPage-DaooFaJ4.js → TerminalPage-B5JNFU6w.js} +19 -19
  19. package/dist/public/assets/TerminalRuntimeFallbackModal-CM3LRKOJ.js +1 -0
  20. package/dist/public/assets/{ToolFilesPage-CGxBvYG0.js → ToolFilesPage-GSqKQsj_.js} +1 -1
  21. package/dist/public/assets/ToolGitPage-BVFWMMQp.js +1 -0
  22. package/dist/public/assets/ToolProcessesPage-DZ456fYz.js +1 -0
  23. package/dist/public/assets/ToolsHomePage-DsJp0y8A.js +1 -0
  24. package/dist/public/assets/WorkbenchLandingPage-DyPei0e-.js +1 -0
  25. package/dist/public/assets/WorkbenchLayout-DlbgBT3n.js +4 -0
  26. package/dist/public/assets/WorkbenchModal-LNfB69qx.js +1 -0
  27. package/dist/public/assets/WorkbenchShellRoute-BsxumYx5.js +1 -0
  28. package/dist/public/assets/WorkbenchShellRoute-DhQo_0vu.css +1 -0
  29. package/dist/public/assets/WorkspaceDebugDetailPage-CaXj5zVI.js +1 -0
  30. package/dist/public/assets/WorkspaceDetailPage-DOexuuaw.js +1 -0
  31. package/dist/public/assets/WorkspaceHomePage-DkCHNjKD.js +1 -0
  32. package/dist/public/assets/{client-runtime-manager-BZpL17fc.js → client-runtime-manager-6OoYHXGd.js} +1 -1
  33. package/dist/public/assets/{file-tree-icon-Db5LXC8h.js → file-tree-icon-9pt1OStn.js} +1 -1
  34. package/dist/public/assets/index-BwlbvwaA.css +1 -0
  35. package/dist/public/assets/index-DSw-TkQL.js +42 -0
  36. package/dist/public/assets/legna-code-6TqgZ4Ls.png +0 -0
  37. package/dist/public/assets/{login-direct-candidate-resolver-1mxe_Oh8.js → login-direct-candidate-resolver-CLlYtBRq.js} +1 -1
  38. package/dist/public/assets/model-switch-api-C-l8-E1S.js +1 -0
  39. package/dist/public/assets/{preferences-service-DWnzl5a0.js → preferences-service-BCcfYP_d.js} +1 -1
  40. package/dist/public/assets/{relay-entry-C5_Iay0I.js → relay-entry-BmLkMKuq.js} +1 -1
  41. package/dist/public/assets/session-runtime-machine-DgtvREca.js +21 -0
  42. package/dist/public/assets/{terminal-runtime-meta-cdtWVfCm.js → terminal-runtime-meta-0h-75uRy.js} +1 -1
  43. package/dist/public/assets/useRegisteredDebugTemplates-rBVmAqh3.js +1 -0
  44. package/dist/public/index.html +2 -2
  45. package/dist/server/config/env.d.ts +2 -0
  46. package/dist/server/config/env.js +7 -0
  47. package/dist/server/config/env.js.map +1 -1
  48. package/dist/server/modules/assistant-capability/assistant-capability-service.d.ts +4 -1
  49. package/dist/server/modules/assistant-capability/assistant-capability-service.js +12 -1
  50. package/dist/server/modules/assistant-capability/assistant-capability-service.js.map +1 -1
  51. package/dist/server/modules/butler/butler-control-session-service.d.ts +4 -1
  52. package/dist/server/modules/butler/butler-control-session-service.js +17 -1
  53. package/dist/server/modules/butler/butler-control-session-service.js.map +1 -1
  54. package/dist/server/modules/butler/butler-profile-service.d.ts +3 -1
  55. package/dist/server/modules/butler/butler-profile-service.js +16 -4
  56. package/dist/server/modules/butler/butler-profile-service.js.map +1 -1
  57. package/dist/server/modules/model-switch/cc-switch-adapter.d.ts +7 -0
  58. package/dist/server/modules/model-switch/cc-switch-adapter.js +17 -0
  59. package/dist/server/modules/model-switch/cc-switch-adapter.js.map +1 -1
  60. package/dist/server/modules/opencli/opencli-bridge-skill-service.d.ts +12 -0
  61. package/dist/server/modules/opencli/opencli-bridge-skill-service.js +124 -0
  62. package/dist/server/modules/opencli/opencli-bridge-skill-service.js.map +1 -0
  63. package/dist/server/modules/opencli/opencli-catalog-service.d.ts +50 -0
  64. package/dist/server/modules/opencli/opencli-catalog-service.js +345 -0
  65. package/dist/server/modules/opencli/opencli-catalog-service.js.map +1 -0
  66. package/dist/server/modules/opencli/opencli-controller.d.ts +13 -0
  67. package/dist/server/modules/opencli/opencli-controller.js +30 -0
  68. package/dist/server/modules/opencli/opencli-controller.js.map +1 -0
  69. package/dist/server/modules/opencli/opencli-health-service.d.ts +28 -0
  70. package/dist/server/modules/opencli/opencli-health-service.js +106 -0
  71. package/dist/server/modules/opencli/opencli-health-service.js.map +1 -0
  72. package/dist/server/modules/opencli/opencli-install-discovery.d.ts +23 -0
  73. package/dist/server/modules/opencli/opencli-install-discovery.js +130 -0
  74. package/dist/server/modules/opencli/opencli-install-discovery.js.map +1 -0
  75. package/dist/server/modules/opencli/opencli-management-service.d.ts +59 -0
  76. package/dist/server/modules/opencli/opencli-management-service.js +152 -0
  77. package/dist/server/modules/opencli/opencli-management-service.js.map +1 -0
  78. package/dist/server/modules/opencli/opencli-runtime-builder.d.ts +11 -0
  79. package/dist/server/modules/opencli/opencli-runtime-builder.js +214 -0
  80. package/dist/server/modules/opencli/opencli-runtime-builder.js.map +1 -0
  81. package/dist/server/modules/opencli/opencli-runtime-layout.d.ts +3 -0
  82. package/dist/server/modules/opencli/opencli-runtime-layout.js +11 -0
  83. package/dist/server/modules/opencli/opencli-runtime-layout.js.map +1 -0
  84. package/dist/server/modules/opencli/opencli-runtime-profile-service.d.ts +29 -0
  85. package/dist/server/modules/opencli/opencli-runtime-profile-service.js +104 -0
  86. package/dist/server/modules/opencli/opencli-runtime-profile-service.js.map +1 -0
  87. package/dist/server/modules/opencli/opencli-runtime-resolver.d.ts +29 -0
  88. package/dist/server/modules/opencli/opencli-runtime-resolver.js +110 -0
  89. package/dist/server/modules/opencli/opencli-runtime-resolver.js.map +1 -0
  90. package/dist/server/modules/opencli/opencli-session-prompt-service.d.ts +11 -0
  91. package/dist/server/modules/opencli/opencli-session-prompt-service.js +66 -0
  92. package/dist/server/modules/opencli/opencli-session-prompt-service.js.map +1 -0
  93. package/dist/server/modules/parallel-sessions/parallel-session-controller.d.ts +4 -0
  94. package/dist/server/modules/parallel-sessions/parallel-session-controller.js +7 -0
  95. package/dist/server/modules/parallel-sessions/parallel-session-controller.js.map +1 -1
  96. package/dist/server/modules/parallel-sessions/parallel-session-group-service.d.ts +6 -1
  97. package/dist/server/modules/parallel-sessions/parallel-session-group-service.js +36 -2
  98. package/dist/server/modules/parallel-sessions/parallel-session-group-service.js.map +1 -1
  99. package/dist/server/modules/provider/opencode-model-options.d.ts +1 -0
  100. package/dist/server/modules/provider/opencode-model-options.js +54 -12
  101. package/dist/server/modules/provider/opencode-model-options.js.map +1 -1
  102. package/dist/server/modules/provider/provider-catalog-service.d.ts +46 -0
  103. package/dist/server/modules/provider/provider-catalog-service.js +249 -0
  104. package/dist/server/modules/provider/provider-catalog-service.js.map +1 -0
  105. package/dist/server/modules/provider/provider-controller.d.ts +20 -2
  106. package/dist/server/modules/provider/provider-controller.js +65 -5
  107. package/dist/server/modules/provider/provider-controller.js.map +1 -1
  108. package/dist/server/modules/provider/provider-disabled.d.ts +8 -0
  109. package/dist/server/modules/provider/provider-disabled.js +45 -0
  110. package/dist/server/modules/provider/provider-disabled.js.map +1 -0
  111. package/dist/server/modules/provider/provider-discovery-helper-client.d.ts +3 -0
  112. package/dist/server/modules/provider/provider-discovery-helper-client.js.map +1 -1
  113. package/dist/server/modules/provider/provider-discovery-helper-process.js +4 -4
  114. package/dist/server/modules/provider/provider-discovery-helper-process.js.map +1 -1
  115. package/dist/server/modules/provider/provider-discovery-runtime.d.ts +1 -1
  116. package/dist/server/modules/provider/provider-discovery-runtime.js +17 -9
  117. package/dist/server/modules/provider/provider-discovery-runtime.js.map +1 -1
  118. package/dist/server/modules/sessions/claude-compatible-provider-registry.d.ts +16 -0
  119. package/dist/server/modules/sessions/claude-compatible-provider-registry.js +91 -0
  120. package/dist/server/modules/sessions/claude-compatible-provider-registry.js.map +1 -0
  121. package/dist/server/modules/sessions/claude-runtime-helper-client.d.ts +1 -0
  122. package/dist/server/modules/sessions/claude-runtime-helper-client.js +14 -0
  123. package/dist/server/modules/sessions/claude-runtime-helper-client.js.map +1 -1
  124. package/dist/server/modules/sessions/codex-app-server-helper-client.d.ts +1 -0
  125. package/dist/server/modules/sessions/codex-app-server-helper-client.js +10 -0
  126. package/dist/server/modules/sessions/codex-app-server-helper-client.js.map +1 -1
  127. package/dist/server/modules/sessions/provider-session-delete-cli.js +2 -0
  128. package/dist/server/modules/sessions/provider-session-delete-cli.js.map +1 -1
  129. package/dist/server/modules/sessions/session-controller.d.ts +7 -0
  130. package/dist/server/modules/sessions/session-controller.js +22 -0
  131. package/dist/server/modules/sessions/session-controller.js.map +1 -1
  132. package/dist/server/modules/sessions/session-history-service.d.ts +18 -2
  133. package/dist/server/modules/sessions/session-history-service.js +330 -29
  134. package/dist/server/modules/sessions/session-history-service.js.map +1 -1
  135. package/dist/server/modules/sessions/session-live-runtime-router-service.js +9 -4
  136. package/dist/server/modules/sessions/session-live-runtime-router-service.js.map +1 -1
  137. package/dist/server/modules/sessions/session-live-runtime-service.d.ts +22 -5
  138. package/dist/server/modules/sessions/session-live-runtime-service.js +350 -122
  139. package/dist/server/modules/sessions/session-live-runtime-service.js.map +1 -1
  140. package/dist/server/modules/sessions/session-message-attachment-service.js +2 -2
  141. package/dist/server/modules/sessions/session-message-attachment-service.js.map +1 -1
  142. package/dist/server/modules/sessions/session-permission-request-service.d.ts +5 -2
  143. package/dist/server/modules/sessions/session-permission-request-service.js +26 -27
  144. package/dist/server/modules/sessions/session-permission-request-service.js.map +1 -1
  145. package/dist/server/modules/sessions/session-provider-config-service.d.ts +82 -0
  146. package/dist/server/modules/sessions/session-provider-config-service.js +925 -0
  147. package/dist/server/modules/sessions/session-provider-config-service.js.map +1 -0
  148. package/dist/server/modules/sessions/session-provider-error-mapper.d.ts +2 -0
  149. package/dist/server/modules/sessions/session-provider-error-mapper.js +42 -0
  150. package/dist/server/modules/sessions/session-provider-error-mapper.js.map +1 -1
  151. package/dist/server/modules/skills/skill-manager-service.d.ts +5 -0
  152. package/dist/server/modules/skills/skill-manager-service.js +26 -0
  153. package/dist/server/modules/skills/skill-manager-service.js.map +1 -1
  154. package/dist/server/modules/tasks/task-helper-process-handlers.d.ts +1 -0
  155. package/dist/server/modules/tasks/task-helper-process-handlers.js +1 -1
  156. package/dist/server/modules/tasks/task-helper-process-handlers.js.map +1 -1
  157. package/dist/server/routes/opencli.d.ts +3 -0
  158. package/dist/server/routes/opencli.js +7 -0
  159. package/dist/server/routes/opencli.js.map +1 -0
  160. package/dist/server/routes/providers.js +4 -2
  161. package/dist/server/routes/providers.js.map +1 -1
  162. package/dist/server/server/create-server.d.ts +8 -0
  163. package/dist/server/server/create-server.js +48 -12
  164. package/dist/server/server/create-server.js.map +1 -1
  165. package/dist/server/storage/repositories/opencli-catalog-entry-repository.d.ts +9 -0
  166. package/dist/server/storage/repositories/opencli-catalog-entry-repository.js +85 -0
  167. package/dist/server/storage/repositories/opencli-catalog-entry-repository.js.map +1 -0
  168. package/dist/server/storage/repositories/opencli-provider-repository.d.ts +8 -0
  169. package/dist/server/storage/repositories/opencli-provider-repository.js +88 -0
  170. package/dist/server/storage/repositories/opencli-provider-repository.js.map +1 -0
  171. package/dist/server/storage/repositories/opencli-runtime-profile-repository.d.ts +11 -0
  172. package/dist/server/storage/repositories/opencli-runtime-profile-repository.js +127 -0
  173. package/dist/server/storage/repositories/opencli-runtime-profile-repository.js.map +1 -0
  174. package/dist/server/storage/repositories/provider-control-repository.d.ts +9 -0
  175. package/dist/server/storage/repositories/provider-control-repository.js +51 -0
  176. package/dist/server/storage/repositories/provider-control-repository.js.map +1 -0
  177. package/dist/server/storage/repositories/session-binding-repository.js +44 -5
  178. package/dist/server/storage/repositories/session-binding-repository.js.map +1 -1
  179. package/dist/server/storage/repositories/session-index-repository.js +6 -0
  180. package/dist/server/storage/repositories/session-index-repository.js.map +1 -1
  181. package/dist/server/storage/sqlite/client.js +72 -0
  182. package/dist/server/storage/sqlite/client.js.map +1 -1
  183. package/dist/server/storage/sqlite/schema.sql +71 -0
  184. package/dist/server/types/domain.d.ts +56 -0
  185. package/node_modules/@codingns/session-sync-core/dist/claude-message-utils.d.ts +5 -2
  186. package/node_modules/@codingns/session-sync-core/dist/claude-message-utils.js +40 -8
  187. package/node_modules/@codingns/session-sync-core/dist/claude-message-utils.js.map +1 -1
  188. package/node_modules/@codingns/session-sync-core/dist/index.d.ts +2 -0
  189. package/node_modules/@codingns/session-sync-core/dist/index.js +2 -0
  190. package/node_modules/@codingns/session-sync-core/dist/index.js.map +1 -1
  191. package/node_modules/@codingns/session-sync-core/dist/providers/claude-code.d.ts +10 -1
  192. package/node_modules/@codingns/session-sync-core/dist/providers/claude-code.js +110 -35
  193. package/node_modules/@codingns/session-sync-core/dist/providers/claude-code.js.map +1 -1
  194. package/node_modules/@codingns/session-sync-core/dist/providers/claude-session-store.d.ts +11 -0
  195. package/node_modules/@codingns/session-sync-core/dist/providers/claude-session-store.js +105 -0
  196. package/node_modules/@codingns/session-sync-core/dist/providers/claude-session-store.js.map +1 -0
  197. package/node_modules/@codingns/session-sync-core/dist/providers/gemini.js +131 -39
  198. package/node_modules/@codingns/session-sync-core/dist/providers/gemini.js.map +1 -1
  199. package/node_modules/@codingns/session-sync-core/dist/providers/legna-code.d.ts +9 -0
  200. package/node_modules/@codingns/session-sync-core/dist/providers/legna-code.js +17 -0
  201. package/node_modules/@codingns/session-sync-core/dist/providers/legna-code.js.map +1 -0
  202. package/node_modules/@codingns/session-sync-core/dist/providers/opencode-shared.d.ts +8 -1
  203. package/node_modules/@codingns/session-sync-core/dist/providers/opencode-shared.js +19 -6
  204. package/node_modules/@codingns/session-sync-core/dist/providers/opencode-shared.js.map +1 -1
  205. package/node_modules/@codingns/session-sync-core/dist/providers/opencode.d.ts +1 -0
  206. package/node_modules/@codingns/session-sync-core/dist/providers/opencode.js +13 -8
  207. package/node_modules/@codingns/session-sync-core/dist/providers/opencode.js.map +1 -1
  208. package/node_modules/@codingns/session-sync-core/dist/runtime/claude-runtime.d.ts +5 -1
  209. package/node_modules/@codingns/session-sync-core/dist/runtime/claude-runtime.js +103 -51
  210. package/node_modules/@codingns/session-sync-core/dist/runtime/claude-runtime.js.map +1 -1
  211. package/node_modules/@codingns/session-sync-core/dist/runtime/codex-runtime.d.ts +2 -1
  212. package/node_modules/@codingns/session-sync-core/dist/runtime/codex-runtime.js +41 -21
  213. package/node_modules/@codingns/session-sync-core/dist/runtime/codex-runtime.js.map +1 -1
  214. package/node_modules/@codingns/session-sync-core/dist/runtime/gemini-runtime.js +32 -8
  215. package/node_modules/@codingns/session-sync-core/dist/runtime/gemini-runtime.js.map +1 -1
  216. package/node_modules/@codingns/session-sync-core/dist/runtime/legna-runtime.d.ts +15 -0
  217. package/node_modules/@codingns/session-sync-core/dist/runtime/legna-runtime.js +16 -0
  218. package/node_modules/@codingns/session-sync-core/dist/runtime/legna-runtime.js.map +1 -0
  219. package/node_modules/@codingns/session-sync-core/dist/runtime/opencode-runtime.js +167 -10
  220. package/node_modules/@codingns/session-sync-core/dist/runtime/opencode-runtime.js.map +1 -1
  221. package/node_modules/@codingns/session-sync-core/dist/runtime/types.d.ts +2 -0
  222. package/node_modules/@codingns/session-sync-core/dist/types.d.ts +1 -1
  223. package/node_modules/@codingns/session-sync-core/dist/types.js +1 -1
  224. package/node_modules/@codingns/session-sync-core/dist/types.js.map +1 -1
  225. package/package.json +1 -1
  226. package/dist/public/assets/AdaptiveButlerPage-uFwDdN-F.js +0 -3
  227. package/dist/public/assets/ConversationPage-z3sXtKZ7.js +0 -4
  228. package/dist/public/assets/DesktopWindowPage-CZcoGApB.js +0 -2
  229. package/dist/public/assets/FileContextPanel-C3qex8bb.js +0 -1
  230. package/dist/public/assets/GitSidebar-BK6H16XU.js +0 -6
  231. package/dist/public/assets/MobileCreateSessionSheet-BYfbvK8o.js +0 -1
  232. package/dist/public/assets/MobileSheet-Ckug8hTb.js +0 -1
  233. package/dist/public/assets/MobileWorkspaceSwitcherHeader-RqWrBdn2.js +0 -1
  234. package/dist/public/assets/SessionIndexPage-DuK10DL5.js +0 -1
  235. package/dist/public/assets/SettingsPage-fyD-xaHL.js +0 -1
  236. package/dist/public/assets/TerminalManagerPanel-CCLr1Ypk.js +0 -1
  237. package/dist/public/assets/TerminalRuntimeFallbackModal-aUzjEBwP.js +0 -1
  238. package/dist/public/assets/ToolGitPage-C264yjS9.js +0 -1
  239. package/dist/public/assets/ToolProcessesPage-BOP4A1cb.js +0 -1
  240. package/dist/public/assets/ToolsHomePage-CQxGiKQA.js +0 -1
  241. package/dist/public/assets/WorkbenchLandingPage-CvAY68ca.js +0 -1
  242. package/dist/public/assets/WorkbenchLayout-DGm8Tc5M.js +0 -3
  243. package/dist/public/assets/WorkbenchModal-0tPIIhca.js +0 -1
  244. package/dist/public/assets/WorkbenchShellRoute-BF0nHWOk.css +0 -1
  245. package/dist/public/assets/WorkbenchShellRoute-DBBOsJo9.js +0 -1
  246. package/dist/public/assets/WorkspaceDebugDetailPage-CDerFYd2.js +0 -1
  247. package/dist/public/assets/WorkspaceDetailPage-BlJc1CHE.js +0 -1
  248. package/dist/public/assets/WorkspaceHomePage-BUsKJ3lv.js +0 -1
  249. package/dist/public/assets/default-session-permission-mode-DT4SGiwp.js +0 -1
  250. package/dist/public/assets/index-BZLcEHW3.js +0 -42
  251. package/dist/public/assets/index-BbspQPC2.css +0 -1
  252. package/dist/public/assets/session-runtime-machine-DdLeDqQr.js +0 -17
  253. package/dist/public/assets/useRegisteredDebugTemplates-oFAQNIqh.js +0 -1
@@ -0,0 +1,925 @@
1
+ import fs from "node:fs";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+ import { AppError } from "../../shared/errors/app-error.js";
5
+ const SESSION_RUNTIME_METADATA_FILE = ".codingns-provider-runtime.json";
6
+ const PROVIDER_DEFAULT_MODEL_ID = "provider-default";
7
+ const SUPPORTED_SESSION_PRESET_PROVIDERS = new Set([
8
+ "claude-code",
9
+ "codex",
10
+ "gemini"
11
+ ]);
12
+ const CLAUDE_STANDARD_MODEL_IDS = new Set([
13
+ "sonnet",
14
+ "opus",
15
+ "haiku"
16
+ ]);
17
+ const CLAUDE_RUNTIME_STATE_FILES = [
18
+ ".claude.json",
19
+ "history.jsonl",
20
+ "stats-cache.json"
21
+ ];
22
+ const CLAUDE_RUNTIME_STATE_DIRECTORIES = [
23
+ "plans",
24
+ "session-env",
25
+ "sessions",
26
+ "shell-snapshots",
27
+ "todos"
28
+ ];
29
+ const CLAUDE_STANDARD_MODEL_PREFIX = "claude-";
30
+ const CLAUDE_MODEL_ALIASES = [
31
+ {
32
+ id: "sonnet",
33
+ label: "Sonnet",
34
+ envKey: "ANTHROPIC_DEFAULT_SONNET_MODEL"
35
+ },
36
+ {
37
+ id: "opus",
38
+ label: "Opus",
39
+ envKey: "ANTHROPIC_DEFAULT_OPUS_MODEL"
40
+ },
41
+ {
42
+ id: "haiku",
43
+ label: "Haiku",
44
+ envKey: "ANTHROPIC_DEFAULT_HAIKU_MODEL"
45
+ }
46
+ ];
47
+ export class SessionProviderConfigService {
48
+ config;
49
+ ccSwitchAdapter;
50
+ openCliRuntimeResolver;
51
+ openCliBridgeSkillService;
52
+ constructor(config, ccSwitchAdapter, openCliRuntimeResolver, openCliBridgeSkillService) {
53
+ this.config = config;
54
+ this.ccSwitchAdapter = ccSwitchAdapter;
55
+ this.openCliRuntimeResolver = openCliRuntimeResolver;
56
+ this.openCliBridgeSkillService = openCliBridgeSkillService;
57
+ }
58
+ prepareSessionBinding(input) {
59
+ const selection = this.resolveRequestedSelection({
60
+ providerConfigMode: input.providerConfigMode ?? undefined,
61
+ providerPresetId: input.providerPresetId ?? undefined
62
+ });
63
+ if (selection.providerConfigMode === "global-default") {
64
+ if (!this.shouldUseManagedRuntimeHome(input.provider)) {
65
+ return {
66
+ providerConfigMode: selection.providerConfigMode,
67
+ providerPresetId: null,
68
+ runtimeHomeDir: null
69
+ };
70
+ }
71
+ const runtimeHomeDir = this.resolveRuntimeHomeDir(input.provider, input.sessionId);
72
+ this.materializeGlobalRuntimeHome(input.provider, runtimeHomeDir);
73
+ return {
74
+ providerConfigMode: selection.providerConfigMode,
75
+ providerPresetId: null,
76
+ runtimeHomeDir
77
+ };
78
+ }
79
+ this.assertProviderSupportsSessionPreset(input.provider);
80
+ const presetId = selection.providerPresetId;
81
+ const app = mapProviderToModelSwitchApp(input.provider);
82
+ const preset = this.ccSwitchAdapter.readPresetRuntimeConfig(app, presetId);
83
+ if (!preset) {
84
+ throw new AppError({
85
+ statusCode: 404,
86
+ errorCode: "MODEL_PRESET_NOT_FOUND",
87
+ detail: `未找到 provider preset:${presetId}`,
88
+ field: "providerPresetId"
89
+ });
90
+ }
91
+ const runtimeHomeDir = this.resolveRuntimeHomeDir(input.provider, input.sessionId);
92
+ this.materializeRuntimeHome(input.provider, runtimeHomeDir, preset);
93
+ return {
94
+ providerConfigMode: selection.providerConfigMode,
95
+ providerPresetId: selection.providerPresetId,
96
+ runtimeHomeDir
97
+ };
98
+ }
99
+ resolveSessionBinding(input) {
100
+ const existingSelection = input.existingBinding
101
+ ? {
102
+ providerConfigMode: input.existingBinding.providerConfigMode,
103
+ providerPresetId: input.existingBinding.providerPresetId
104
+ }
105
+ : null;
106
+ const selection = this.resolveRequestedSelection({
107
+ providerConfigMode: input.providerConfigMode ?? undefined,
108
+ providerPresetId: input.providerPresetId ?? undefined,
109
+ fallback: existingSelection
110
+ });
111
+ const existingRuntimeHomeDir = input.existingBinding?.runtimeHomeDir?.trim() ?? "";
112
+ if (selection.providerConfigMode === "global-default") {
113
+ if (input.existingBinding?.providerConfigMode === "global-default"
114
+ && existingRuntimeHomeDir.length > 0) {
115
+ if (this.shouldUseManagedRuntimeHome(input.provider)) {
116
+ this.materializeGlobalRuntimeHome(input.provider, existingRuntimeHomeDir);
117
+ }
118
+ return {
119
+ providerConfigMode: "global-default",
120
+ providerPresetId: null,
121
+ runtimeHomeDir: existingRuntimeHomeDir
122
+ };
123
+ }
124
+ if (!this.shouldUseManagedRuntimeHome(input.provider)) {
125
+ return {
126
+ providerConfigMode: "global-default",
127
+ providerPresetId: null,
128
+ runtimeHomeDir: null
129
+ };
130
+ }
131
+ const preparedBinding = this.prepareSessionBinding({
132
+ sessionId: input.sessionId,
133
+ provider: input.provider,
134
+ providerConfigMode: selection.providerConfigMode,
135
+ providerPresetId: selection.providerPresetId
136
+ });
137
+ this.syncProviderRuntimeStateToPreparedHome(input.provider, input.existingBinding, preparedBinding.runtimeHomeDir);
138
+ return preparedBinding;
139
+ }
140
+ if (input.existingBinding?.providerConfigMode === "cc-switch-preset"
141
+ && input.existingBinding.providerPresetId === selection.providerPresetId
142
+ && existingRuntimeHomeDir.length > 0) {
143
+ return {
144
+ providerConfigMode: "cc-switch-preset",
145
+ providerPresetId: selection.providerPresetId,
146
+ runtimeHomeDir: existingRuntimeHomeDir
147
+ };
148
+ }
149
+ const preparedBinding = this.prepareSessionBinding({
150
+ sessionId: input.sessionId,
151
+ provider: input.provider,
152
+ providerConfigMode: selection.providerConfigMode,
153
+ providerPresetId: selection.providerPresetId
154
+ });
155
+ this.syncProviderRuntimeStateToPreparedHome(input.provider, input.existingBinding, preparedBinding.runtimeHomeDir);
156
+ return preparedBinding;
157
+ }
158
+ resolveCapabilities(input) {
159
+ const selection = this.resolveRequestedSelection({
160
+ providerConfigMode: input.providerConfigMode ?? undefined,
161
+ providerPresetId: input.providerPresetId ?? undefined
162
+ });
163
+ if (selection.providerConfigMode === "global-default") {
164
+ return input.baseCapabilities;
165
+ }
166
+ this.assertProviderSupportsSessionPreset(input.provider);
167
+ const presetId = selection.providerPresetId;
168
+ const app = mapProviderToModelSwitchApp(input.provider);
169
+ const preset = this.ccSwitchAdapter.readPresetRuntimeConfig(app, presetId);
170
+ if (!preset) {
171
+ throw new AppError({
172
+ statusCode: 404,
173
+ errorCode: "MODEL_PRESET_NOT_FOUND",
174
+ detail: `未找到 provider preset:${presetId}`,
175
+ field: "providerPresetId"
176
+ });
177
+ }
178
+ switch (input.provider) {
179
+ case "claude-code":
180
+ return buildClaudePresetCapabilities(input.baseCapabilities, preset.settingsConfig);
181
+ case "codex":
182
+ return buildCodexPresetCapabilities(input.baseCapabilities, preset.settingsConfig);
183
+ case "gemini":
184
+ return buildGeminiPresetCapabilities(input.baseCapabilities, preset.settingsConfig);
185
+ default:
186
+ return input.baseCapabilities;
187
+ }
188
+ }
189
+ resolveLaunchContext(binding) {
190
+ const baseLaunchContext = this.resolveBaseLaunchContext(binding);
191
+ const openCliResolution = this.openCliRuntimeResolver?.resolveSessionRuntime();
192
+ this.refreshOpenCliBridgeSkill(binding, openCliResolution);
193
+ if (!openCliResolution || openCliResolution.availability !== "ready" || !openCliResolution.runtimeBinPath) {
194
+ return baseLaunchContext;
195
+ }
196
+ return {
197
+ runtimeHomeDir: baseLaunchContext.runtimeHomeDir,
198
+ runtimeEnv: mergeLaunchRuntimeEnv(baseLaunchContext.runtimeEnv, openCliResolution)
199
+ };
200
+ }
201
+ resolveBaseLaunchContext(binding) {
202
+ const runtimeHomeDir = binding.runtimeHomeDir?.trim() ?? "";
203
+ if (!runtimeHomeDir) {
204
+ return {
205
+ runtimeHomeDir: null,
206
+ runtimeEnv: {}
207
+ };
208
+ }
209
+ const metadata = this.readRuntimeMetadata(runtimeHomeDir, binding.provider, binding.providerPresetId);
210
+ return {
211
+ runtimeHomeDir,
212
+ runtimeEnv: metadata.runtimeEnv
213
+ };
214
+ }
215
+ describeBinding(binding) {
216
+ const summary = {
217
+ provider: binding.provider,
218
+ providerConfigMode: binding.providerConfigMode,
219
+ providerPresetId: binding.providerPresetId,
220
+ providerPresetName: null,
221
+ runtimeHomeDir: binding.runtimeHomeDir ?? null,
222
+ modelProvider: null,
223
+ model: null,
224
+ baseUrl: null,
225
+ authEnvKeys: []
226
+ };
227
+ if (binding.providerConfigMode !== "cc-switch-preset") {
228
+ return summary;
229
+ }
230
+ try {
231
+ const app = mapProviderToModelSwitchApp(binding.provider);
232
+ const preset = binding.providerPresetId
233
+ ? this.ccSwitchAdapter.readPresetRuntimeConfig(app, binding.providerPresetId)
234
+ : null;
235
+ summary.providerPresetName = preset?.name ?? null;
236
+ }
237
+ catch {
238
+ return summary;
239
+ }
240
+ const runtimeHomeDir = binding.runtimeHomeDir?.trim() ?? "";
241
+ if (!runtimeHomeDir) {
242
+ return summary;
243
+ }
244
+ const configPath = path.join(runtimeHomeDir, "config.toml");
245
+ if (fs.existsSync(configPath) && fs.statSync(configPath).isFile()) {
246
+ const document = parseSimpleTomlDocument(fs.readFileSync(configPath, "utf8"));
247
+ const modelProvider = decodeSimpleTomlStringValue(document.rootValues.get("model_provider"));
248
+ const model = decodeSimpleTomlStringValue(document.rootValues.get("model"));
249
+ summary.modelProvider = modelProvider;
250
+ summary.model = model;
251
+ if (modelProvider) {
252
+ const providerTable = document.tables.get(`model_providers.${modelProvider}`);
253
+ summary.baseUrl = decodeSimpleTomlStringValue(providerTable?.values.get("base_url"));
254
+ }
255
+ }
256
+ try {
257
+ const metadata = this.readRuntimeMetadata(runtimeHomeDir, binding.provider, binding.providerPresetId);
258
+ summary.authEnvKeys = Object.keys(metadata.runtimeEnv).sort();
259
+ }
260
+ catch {
261
+ return summary;
262
+ }
263
+ return summary;
264
+ }
265
+ assertProviderSupportsSessionPreset(provider) {
266
+ if (SUPPORTED_SESSION_PRESET_PROVIDERS.has(provider)) {
267
+ return;
268
+ }
269
+ throw new AppError({
270
+ statusCode: 400,
271
+ errorCode: "PROVIDER_PRESET_NOT_SUPPORTED",
272
+ detail: `${provider} 当前不支持会话级 cc-switch preset`,
273
+ field: "provider"
274
+ });
275
+ }
276
+ resolveRequestedSelection(input) {
277
+ const normalizedPresetId = input.providerPresetId?.trim() || null;
278
+ if (input.providerConfigMode === undefined && input.providerPresetId === undefined) {
279
+ return input.fallback ?? {
280
+ providerConfigMode: "global-default",
281
+ providerPresetId: null
282
+ };
283
+ }
284
+ const providerConfigMode = input.providerConfigMode ?? (normalizedPresetId ? "cc-switch-preset" : "global-default");
285
+ if (providerConfigMode === "global-default") {
286
+ return {
287
+ providerConfigMode,
288
+ providerPresetId: null
289
+ };
290
+ }
291
+ if (!normalizedPresetId) {
292
+ throw new AppError({
293
+ statusCode: 400,
294
+ errorCode: "INVALID_INPUT",
295
+ detail: "使用 cc-switch preset 时必须提供 providerPresetId",
296
+ field: "providerPresetId"
297
+ });
298
+ }
299
+ return {
300
+ providerConfigMode,
301
+ providerPresetId: normalizedPresetId
302
+ };
303
+ }
304
+ resolveRuntimeHomeDir(provider, sessionId) {
305
+ return path.resolve(path.dirname(this.config.databasePath), "session-provider-runtime", provider, sessionId);
306
+ }
307
+ materializeRuntimeHome(provider, runtimeHomeDir, preset) {
308
+ fs.mkdirSync(runtimeHomeDir, { recursive: true });
309
+ const runtimeEnv = normalizeRuntimeEnv(preset.settingsConfig);
310
+ this.writeRuntimeMetadata(runtimeHomeDir, {
311
+ provider,
312
+ providerPresetId: preset.id,
313
+ runtimeEnv
314
+ });
315
+ switch (provider) {
316
+ case "claude-code":
317
+ this.materializeClaudeRuntimeHome(runtimeHomeDir, preset.settingsConfig);
318
+ return;
319
+ case "codex":
320
+ this.materializeCodexRuntimeHome(runtimeHomeDir, preset.settingsConfig);
321
+ return;
322
+ case "gemini":
323
+ this.materializeGeminiRuntimeHome(runtimeHomeDir);
324
+ return;
325
+ default:
326
+ throw new AppError({
327
+ statusCode: 400,
328
+ errorCode: "PROVIDER_PRESET_NOT_SUPPORTED",
329
+ detail: `${provider} 当前不支持会话级 cc-switch preset`
330
+ });
331
+ }
332
+ this.refreshOpenCliBridgeSkill({
333
+ provider,
334
+ runtimeHomeDir
335
+ }, this.openCliRuntimeResolver?.resolveSessionRuntime());
336
+ }
337
+ materializeGlobalRuntimeHome(provider, runtimeHomeDir) {
338
+ fs.mkdirSync(runtimeHomeDir, { recursive: true });
339
+ this.writeRuntimeMetadata(runtimeHomeDir, {
340
+ provider,
341
+ providerPresetId: "",
342
+ runtimeEnv: {}
343
+ });
344
+ switch (provider) {
345
+ case "claude-code":
346
+ this.materializeClaudeRuntimeHome(runtimeHomeDir, {});
347
+ break;
348
+ case "codex":
349
+ this.materializeCodexRuntimeHome(runtimeHomeDir, {});
350
+ break;
351
+ default:
352
+ return;
353
+ }
354
+ this.refreshOpenCliBridgeSkill({
355
+ provider,
356
+ runtimeHomeDir
357
+ }, this.openCliRuntimeResolver?.resolveSessionRuntime());
358
+ }
359
+ materializeClaudeRuntimeHome(runtimeHomeDir, settingsConfig) {
360
+ const sourceHomeDir = path.resolve(this.config.claudeCodeHomeDir);
361
+ const mergedSettings = mergeJsonObjects(readJsonObject(path.join(sourceHomeDir, "settings.json")), readJsonObject(path.join(sourceHomeDir, "settings.local.json")), settingsConfig);
362
+ syncOptionalFile(path.join(sourceHomeDir, "config.json"), path.join(runtimeHomeDir, "config.json"));
363
+ syncOptionalFile(path.join(sourceHomeDir, "project-config.json"), path.join(runtimeHomeDir, "project-config.json"));
364
+ syncOptionalDirectory(path.join(sourceHomeDir, "plugins"), path.join(runtimeHomeDir, "plugins"));
365
+ syncOptionalDirectory(path.join(sourceHomeDir, "skills"), path.join(runtimeHomeDir, "skills"));
366
+ writeJsonFile(path.join(runtimeHomeDir, "settings.json"), mergedSettings);
367
+ removeFileIfExists(path.join(runtimeHomeDir, "settings.local.json"));
368
+ }
369
+ materializeCodexRuntimeHome(runtimeHomeDir, settingsConfig) {
370
+ const sourceHomeDir = resolveCodexSourceHomeDir(this.config.codexHomeDir, runtimeHomeDir);
371
+ const sourceConfigPath = path.join(sourceHomeDir, "config.toml");
372
+ const configuredText = normalizeText(settingsConfig.config) ?? normalizeText(settingsConfig.toml) ?? "";
373
+ const sourceConfigText = sourceHomeDir !== runtimeHomeDir && fs.existsSync(sourceConfigPath) && fs.statSync(sourceConfigPath).isFile()
374
+ ? fs.readFileSync(sourceConfigPath, "utf8")
375
+ : "";
376
+ syncOptionalFile(path.join(sourceHomeDir, "auth.json"), path.join(runtimeHomeDir, "auth.json"));
377
+ syncOptionalDirectory(path.join(sourceHomeDir, "skills"), path.join(runtimeHomeDir, "skills"));
378
+ writeTextFile(path.join(runtimeHomeDir, "config.toml"), `${composeCodexConfigContent(sourceConfigText, configuredText)}\n`);
379
+ }
380
+ materializeGeminiRuntimeHome(runtimeHomeDir) {
381
+ fs.mkdirSync(path.join(runtimeHomeDir, "tmp"), { recursive: true });
382
+ }
383
+ syncProviderRuntimeStateToPreparedHome(provider, existingBinding, targetRuntimeHomeDir) {
384
+ if (!existingBinding || !targetRuntimeHomeDir) {
385
+ return;
386
+ }
387
+ switch (provider) {
388
+ case "claude-code":
389
+ this.syncClaudeSessionRuntimeState(existingBinding, targetRuntimeHomeDir);
390
+ return;
391
+ default:
392
+ return;
393
+ }
394
+ }
395
+ syncClaudeSessionRuntimeState(existingBinding, targetRuntimeHomeDir) {
396
+ const sourceSessionFilePath = this.resolveClaudeSessionFilePath(existingBinding);
397
+ const sourceRuntimeHomeDir = this.resolveClaudeSourceHomeDir(existingBinding, sourceSessionFilePath);
398
+ if (sourceRuntimeHomeDir) {
399
+ this.syncClaudeRuntimeStateEntries(sourceRuntimeHomeDir, targetRuntimeHomeDir);
400
+ }
401
+ if (!sourceSessionFilePath) {
402
+ return;
403
+ }
404
+ const sourceSessionDirectory = path.dirname(sourceSessionFilePath);
405
+ const targetSessionDirectory = resolveClaudeSessionTargetDirectory(sourceSessionDirectory, targetRuntimeHomeDir);
406
+ if (path.resolve(sourceSessionDirectory) === path.resolve(targetSessionDirectory)) {
407
+ return;
408
+ }
409
+ syncOptionalDirectory(sourceSessionDirectory, targetSessionDirectory);
410
+ }
411
+ resolveClaudeSessionFilePath(binding) {
412
+ const rawStoreRef = binding.rawStoreRef?.trim() ?? "";
413
+ if (rawStoreRef && fs.existsSync(rawStoreRef) && fs.statSync(rawStoreRef).isFile()) {
414
+ return rawStoreRef;
415
+ }
416
+ const providerSessionId = binding.providerSessionId?.trim() ?? "";
417
+ if (!providerSessionId) {
418
+ return null;
419
+ }
420
+ const candidateHomes = this.listClaudeCandidateHomes(binding);
421
+ for (const homeDir of candidateHomes) {
422
+ const matched = findClaudeSessionFileInHome(homeDir, providerSessionId);
423
+ if (matched) {
424
+ return matched;
425
+ }
426
+ }
427
+ return null;
428
+ }
429
+ resolveClaudeSourceHomeDir(binding, sourceSessionFilePath) {
430
+ const candidateHomes = this.listClaudeCandidateHomes(binding);
431
+ const normalizedSessionFilePath = sourceSessionFilePath ? path.resolve(sourceSessionFilePath) : null;
432
+ if (normalizedSessionFilePath) {
433
+ for (const homeDir of candidateHomes) {
434
+ const projectsRoot = path.join(homeDir, "projects");
435
+ const normalizedProjectsRoot = path.resolve(projectsRoot);
436
+ if (normalizedSessionFilePath === normalizedProjectsRoot
437
+ || normalizedSessionFilePath.startsWith(`${normalizedProjectsRoot}${path.sep}`)) {
438
+ return homeDir;
439
+ }
440
+ }
441
+ }
442
+ const existingRuntimeHomeDir = binding.runtimeHomeDir?.trim() ?? "";
443
+ if (existingRuntimeHomeDir.length > 0
444
+ && fs.existsSync(existingRuntimeHomeDir)
445
+ && fs.statSync(existingRuntimeHomeDir).isDirectory()) {
446
+ return path.resolve(existingRuntimeHomeDir);
447
+ }
448
+ return candidateHomes[0] ?? null;
449
+ }
450
+ listClaudeCandidateHomes(binding) {
451
+ return [
452
+ binding.runtimeHomeDir?.trim() ?? "",
453
+ path.resolve(this.config.claudeCodeHomeDir)
454
+ ].filter((value, index, values) => value.length > 0 && values.indexOf(value) === index);
455
+ }
456
+ syncClaudeRuntimeStateEntries(sourceHomeDir, targetRuntimeHomeDir) {
457
+ if (path.resolve(sourceHomeDir) === path.resolve(targetRuntimeHomeDir)) {
458
+ return;
459
+ }
460
+ CLAUDE_RUNTIME_STATE_FILES.forEach((entry) => {
461
+ syncOptionalFile(path.join(sourceHomeDir, entry), path.join(targetRuntimeHomeDir, entry));
462
+ });
463
+ CLAUDE_RUNTIME_STATE_DIRECTORIES.forEach((entry) => {
464
+ syncOptionalDirectory(path.join(sourceHomeDir, entry), path.join(targetRuntimeHomeDir, entry));
465
+ });
466
+ }
467
+ writeRuntimeMetadata(runtimeHomeDir, metadata) {
468
+ writeJsonFile(path.join(runtimeHomeDir, SESSION_RUNTIME_METADATA_FILE), metadata);
469
+ }
470
+ readRuntimeMetadata(runtimeHomeDir, provider, providerPresetId) {
471
+ const filePath = path.join(runtimeHomeDir, SESSION_RUNTIME_METADATA_FILE);
472
+ if (!fs.existsSync(filePath) || !fs.statSync(filePath).isFile()) {
473
+ throw new AppError({
474
+ statusCode: 409,
475
+ errorCode: "SESSION_PROVIDER_RUNTIME_METADATA_MISSING",
476
+ detail: "当前会话的 provider 运行配置已经丢失,请重新创建会话"
477
+ });
478
+ }
479
+ try {
480
+ const parsed = JSON.parse(fs.readFileSync(filePath, "utf8"));
481
+ if (!parsed || parsed.provider !== provider) {
482
+ throw new Error("PROVIDER_MISMATCH");
483
+ }
484
+ if ((parsed.providerPresetId ?? "").trim() !== (providerPresetId ?? "").trim()) {
485
+ throw new Error("PRESET_MISMATCH");
486
+ }
487
+ return {
488
+ provider,
489
+ providerPresetId: parsed.providerPresetId,
490
+ runtimeEnv: normalizeRuntimeEnv({
491
+ env: parsed.runtimeEnv
492
+ })
493
+ };
494
+ }
495
+ catch {
496
+ throw new AppError({
497
+ statusCode: 409,
498
+ errorCode: "SESSION_PROVIDER_RUNTIME_METADATA_INVALID",
499
+ detail: "当前会话的 provider 运行配置已损坏,请重新创建会话"
500
+ });
501
+ }
502
+ }
503
+ shouldUseManagedRuntimeHome(provider) {
504
+ if (!this.openCliBridgeSkillService?.supportsProvider(provider)) {
505
+ return false;
506
+ }
507
+ if (!this.openCliBridgeSkillService.hasEnabledCommands()) {
508
+ return false;
509
+ }
510
+ const runtimeResolution = this.openCliRuntimeResolver?.resolveSessionRuntime();
511
+ return runtimeResolution?.availability === "ready";
512
+ }
513
+ refreshOpenCliBridgeSkill(binding, openCliResolution) {
514
+ const runtimeHomeDir = binding.runtimeHomeDir?.trim() ?? "";
515
+ if (!runtimeHomeDir || !this.openCliBridgeSkillService?.supportsProvider(binding.provider)) {
516
+ return;
517
+ }
518
+ if (openCliResolution?.availability === "ready" && this.openCliBridgeSkillService.hasEnabledCommands()) {
519
+ this.openCliBridgeSkillService.syncRuntimeSkill(binding.provider, runtimeHomeDir);
520
+ return;
521
+ }
522
+ this.openCliBridgeSkillService.removeRuntimeSkill(binding.provider, runtimeHomeDir);
523
+ }
524
+ }
525
+ function mergeLaunchRuntimeEnv(baseRuntimeEnv, openCliResolution) {
526
+ const runtimeEnv = {
527
+ ...baseRuntimeEnv
528
+ };
529
+ const basePath = runtimeEnv.PATH?.trim() || process.env.PATH?.trim() || "";
530
+ const pathEntries = [openCliResolution.runtimeBinPath, basePath].filter((entry) => Boolean(entry && entry.trim()));
531
+ runtimeEnv.PATH = pathEntries.join(path.delimiter);
532
+ if (openCliResolution.runtimeRootPath) {
533
+ runtimeEnv.CODINGNS_OPENCLI_RUNTIME_ROOT = openCliResolution.runtimeRootPath;
534
+ }
535
+ if (openCliResolution.realHome) {
536
+ runtimeEnv.CODINGNS_OPENCLI_REAL_HOME = openCliResolution.realHome;
537
+ }
538
+ if (openCliResolution.realUserProfile) {
539
+ runtimeEnv.CODINGNS_OPENCLI_REAL_USERPROFILE = openCliResolution.realUserProfile;
540
+ }
541
+ return runtimeEnv;
542
+ }
543
+ function mapProviderToModelSwitchApp(provider) {
544
+ switch (provider) {
545
+ case "claude-code":
546
+ case "codex":
547
+ case "gemini":
548
+ return provider;
549
+ default:
550
+ throw new Error(`UNSUPPORTED_MODEL_SWITCH_PROVIDER:${provider}`);
551
+ }
552
+ }
553
+ function buildClaudePresetCapabilities(baseCapabilities, settingsConfig) {
554
+ const env = normalizeRuntimeEnv(settingsConfig);
555
+ const defaultModel = normalizeText(env.ANTHROPIC_MODEL);
556
+ const aliasTargets = CLAUDE_MODEL_ALIASES.map((alias) => ({
557
+ ...alias,
558
+ target: normalizeText(env[alias.envKey])
559
+ }));
560
+ const customModels = new Set();
561
+ if (defaultModel && isClaudeCustomModel(defaultModel)) {
562
+ customModels.add(defaultModel);
563
+ }
564
+ aliasTargets.forEach((alias) => {
565
+ if (alias.target && isClaudeCustomModel(alias.target)) {
566
+ customModels.add(alias.target);
567
+ }
568
+ });
569
+ return {
570
+ ...baseCapabilities,
571
+ modelOptions: [
572
+ buildPresetDefaultModelOption(defaultModel),
573
+ ...aliasTargets.map((alias) => ({
574
+ id: alias.id,
575
+ name: alias.target ? `${alias.label}(当前:${alias.target})` : alias.label
576
+ })),
577
+ ...Array.from(customModels).map((modelId) => ({
578
+ id: modelId,
579
+ name: modelId
580
+ }))
581
+ ]
582
+ };
583
+ }
584
+ function buildCodexPresetCapabilities(baseCapabilities, settingsConfig) {
585
+ const configuredText = normalizeText(settingsConfig.config)
586
+ ?? normalizeText(settingsConfig.toml)
587
+ ?? "";
588
+ const currentModel = readTomlStringValue(configuredText, "model");
589
+ const currentReasoningLevel = readTomlStringValue(configuredText, "model_reasoning_effort");
590
+ const modelOptions = appendMissingModelOption(withPresetDefaultModelOption(baseCapabilities.modelOptions, currentModel), currentModel);
591
+ return {
592
+ ...baseCapabilities,
593
+ modelOptions,
594
+ defaultReasoningLevel: normalizeReasoningLevel(currentReasoningLevel) ?? baseCapabilities.defaultReasoningLevel ?? null
595
+ };
596
+ }
597
+ function buildGeminiPresetCapabilities(baseCapabilities, settingsConfig) {
598
+ const currentModel = resolveGeminiPresetModel(settingsConfig);
599
+ return {
600
+ ...baseCapabilities,
601
+ modelOptions: appendMissingModelOption(withPresetDefaultModelOption(baseCapabilities.modelOptions, currentModel), currentModel)
602
+ };
603
+ }
604
+ function withPresetDefaultModelOption(options, currentModel) {
605
+ const preserved = (options ?? []).filter((option) => option.id !== PROVIDER_DEFAULT_MODEL_ID);
606
+ return [
607
+ buildPresetDefaultModelOption(currentModel),
608
+ ...preserved
609
+ ];
610
+ }
611
+ function appendMissingModelOption(options, currentModel) {
612
+ if (!currentModel || options.some((option) => option.id === currentModel)) {
613
+ return options;
614
+ }
615
+ return [
616
+ ...options,
617
+ {
618
+ id: currentModel,
619
+ name: currentModel
620
+ }
621
+ ];
622
+ }
623
+ function buildPresetDefaultModelOption(currentModel) {
624
+ return {
625
+ id: PROVIDER_DEFAULT_MODEL_ID,
626
+ name: currentModel ? `跟随配置文件默认模型(当前:${currentModel})` : "跟随配置文件默认模型",
627
+ usesProviderDefault: true
628
+ };
629
+ }
630
+ function isClaudeCustomModel(modelId) {
631
+ if (CLAUDE_STANDARD_MODEL_IDS.has(modelId)) {
632
+ return false;
633
+ }
634
+ if (modelId.startsWith(CLAUDE_STANDARD_MODEL_PREFIX)) {
635
+ return false;
636
+ }
637
+ return true;
638
+ }
639
+ function readTomlStringValue(content, key) {
640
+ const matcher = new RegExp(`(^|\\n)\\s*${escapeRegExp(key)}\\s*=\\s*["']([^"']+)["']`, "i");
641
+ const match = matcher.exec(content);
642
+ return normalizeText(match?.[2]);
643
+ }
644
+ function resolveGeminiPresetModel(settingsConfig) {
645
+ const env = normalizeRuntimeEnv(settingsConfig);
646
+ const configRecord = asRecord(settingsConfig.config);
647
+ return normalizeText(env.GEMINI_MODEL)
648
+ ?? normalizeText(env.GOOGLE_MODEL)
649
+ ?? normalizeText(env.GEMINI_DEFAULT_MODEL)
650
+ ?? normalizeText(configRecord?.model)
651
+ ?? normalizeText(configRecord?.defaultModel);
652
+ }
653
+ function normalizeReasoningLevel(value) {
654
+ if (value === "low" || value === "medium" || value === "high" || value === "xhigh") {
655
+ return value;
656
+ }
657
+ return null;
658
+ }
659
+ function escapeRegExp(value) {
660
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
661
+ }
662
+ function normalizeRuntimeEnv(settingsConfig) {
663
+ return {
664
+ ...normalizeStringRecord(asRecord(settingsConfig.env)),
665
+ ...normalizeStringRecord(asRecord(settingsConfig.auth))
666
+ };
667
+ }
668
+ function readJsonObject(filePath) {
669
+ if (!fs.existsSync(filePath) || !fs.statSync(filePath).isFile()) {
670
+ return {};
671
+ }
672
+ try {
673
+ const parsed = JSON.parse(fs.readFileSync(filePath, "utf8"));
674
+ return asRecord(parsed) ?? {};
675
+ }
676
+ catch {
677
+ return {};
678
+ }
679
+ }
680
+ function mergeJsonObjects(...records) {
681
+ return records.reduce((current, record) => deepMergeRecord(current, record), {});
682
+ }
683
+ function deepMergeRecord(left, right) {
684
+ const next = {
685
+ ...left
686
+ };
687
+ for (const [key, value] of Object.entries(right)) {
688
+ const leftValue = next[key];
689
+ if (asRecord(leftValue) && asRecord(value)) {
690
+ next[key] = deepMergeRecord(asRecord(leftValue) ?? {}, asRecord(value) ?? {});
691
+ continue;
692
+ }
693
+ next[key] = value;
694
+ }
695
+ return next;
696
+ }
697
+ function composeCodexConfigContent(sourceConfigContent, presetConfigContent) {
698
+ const merged = mergeCodexTomlDocuments(parseSimpleTomlDocument(sourceConfigContent), parseSimpleTomlDocument(presetConfigContent));
699
+ return serializeSimpleTomlDocument(merged);
700
+ }
701
+ function resolveCodexSourceHomeDir(sourceCodexHomeDir, targetHomeDir) {
702
+ const resolvedConfiguredSource = path.resolve(sourceCodexHomeDir);
703
+ if (resolvedConfiguredSource !== targetHomeDir) {
704
+ return resolvedConfiguredSource;
705
+ }
706
+ const fallbackHomeDir = path.resolve(path.join(os.homedir(), ".codex"));
707
+ if (fallbackHomeDir !== targetHomeDir) {
708
+ return fallbackHomeDir;
709
+ }
710
+ return targetHomeDir;
711
+ }
712
+ function writeJsonFile(filePath, value) {
713
+ writeTextFile(filePath, `${JSON.stringify(value, null, 2)}\n`);
714
+ }
715
+ function writeTextFile(filePath, content) {
716
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
717
+ if (fs.existsSync(filePath) && fs.readFileSync(filePath, "utf8") === content) {
718
+ return;
719
+ }
720
+ fs.writeFileSync(filePath, content, "utf8");
721
+ }
722
+ function syncOptionalFile(sourcePath, targetPath) {
723
+ if (!fs.existsSync(sourcePath) || !fs.statSync(sourcePath).isFile()) {
724
+ return;
725
+ }
726
+ writeTextFile(targetPath, fs.readFileSync(sourcePath, "utf8"));
727
+ }
728
+ function syncOptionalDirectory(sourcePath, targetPath) {
729
+ if (!fs.existsSync(sourcePath) || !fs.statSync(sourcePath).isDirectory()) {
730
+ return;
731
+ }
732
+ if (path.resolve(sourcePath) === path.resolve(targetPath)) {
733
+ return;
734
+ }
735
+ fs.rmSync(targetPath, { recursive: true, force: true });
736
+ fs.mkdirSync(path.dirname(targetPath), { recursive: true });
737
+ fs.cpSync(sourcePath, targetPath, { recursive: true });
738
+ }
739
+ function findClaudeSessionFileInHome(homeDir, providerSessionId) {
740
+ const projectsDir = path.join(homeDir, "projects");
741
+ if (!fs.existsSync(projectsDir) || !fs.statSync(projectsDir).isDirectory()) {
742
+ return null;
743
+ }
744
+ const projectDirectories = fs.readdirSync(projectsDir, { withFileTypes: true })
745
+ .filter((entry) => entry.isDirectory())
746
+ .map((entry) => path.join(projectsDir, entry.name, `${providerSessionId}.jsonl`));
747
+ for (const candidatePath of projectDirectories) {
748
+ if (fs.existsSync(candidatePath) && fs.statSync(candidatePath).isFile()) {
749
+ return candidatePath;
750
+ }
751
+ }
752
+ return null;
753
+ }
754
+ function resolveClaudeSessionTargetDirectory(sourceSessionDirectory, targetRuntimeHomeDir) {
755
+ const normalizedSourceDirectory = path.resolve(sourceSessionDirectory);
756
+ const projectsMarker = `${path.sep}projects${path.sep}`;
757
+ const markerIndex = normalizedSourceDirectory.lastIndexOf(projectsMarker);
758
+ const relativeProjectPath = markerIndex >= 0
759
+ ? normalizedSourceDirectory.slice(markerIndex + projectsMarker.length)
760
+ : path.basename(normalizedSourceDirectory);
761
+ return path.join(targetRuntimeHomeDir, "projects", relativeProjectPath);
762
+ }
763
+ function removeFileIfExists(filePath) {
764
+ if (!fs.existsSync(filePath)) {
765
+ return;
766
+ }
767
+ fs.rmSync(filePath, { force: true });
768
+ }
769
+ function asRecord(value) {
770
+ return value && typeof value === "object" && !Array.isArray(value)
771
+ ? value
772
+ : null;
773
+ }
774
+ function normalizeStringRecord(record) {
775
+ if (!record) {
776
+ return {};
777
+ }
778
+ return Object.fromEntries(Object.entries(record)
779
+ .filter((entry) => typeof entry[1] === "string" && entry[1].trim().length > 0)
780
+ .map(([key, value]) => [key.trim(), value.trim()])
781
+ .filter(([key, value]) => key.length > 0 && value.length > 0));
782
+ }
783
+ function normalizeText(value) {
784
+ return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
785
+ }
786
+ function decodeSimpleTomlStringValue(value) {
787
+ const normalizedValue = value?.trim();
788
+ if (!normalizedValue) {
789
+ return null;
790
+ }
791
+ if ((normalizedValue.startsWith("\"") && normalizedValue.endsWith("\""))
792
+ || (normalizedValue.startsWith("'") && normalizedValue.endsWith("'"))) {
793
+ return normalizedValue.slice(1, -1).trim() || null;
794
+ }
795
+ return normalizedValue;
796
+ }
797
+ function parseSimpleTomlDocument(content) {
798
+ const document = {
799
+ rootOrder: [],
800
+ rootValues: new Map(),
801
+ tableOrder: [],
802
+ tables: new Map()
803
+ };
804
+ let currentTableName = null;
805
+ for (const line of content.split(/\r?\n/u)) {
806
+ const trimmed = line.trim();
807
+ if (!trimmed || trimmed.startsWith("#")) {
808
+ continue;
809
+ }
810
+ const tableMatch = /^\[([^\]]+)\]$/u.exec(trimmed);
811
+ if (tableMatch) {
812
+ currentTableName = tableMatch[1]?.trim() || null;
813
+ if (currentTableName && !document.tables.has(currentTableName)) {
814
+ document.tableOrder.push(currentTableName);
815
+ document.tables.set(currentTableName, {
816
+ order: [],
817
+ values: new Map()
818
+ });
819
+ }
820
+ continue;
821
+ }
822
+ const delimiterIndex = trimmed.indexOf("=");
823
+ if (delimiterIndex <= 0) {
824
+ continue;
825
+ }
826
+ const key = trimmed.slice(0, delimiterIndex).trim();
827
+ const value = trimmed.slice(delimiterIndex + 1).trim();
828
+ if (!key || !value) {
829
+ continue;
830
+ }
831
+ if (!currentTableName) {
832
+ if (!document.rootValues.has(key)) {
833
+ document.rootOrder.push(key);
834
+ }
835
+ document.rootValues.set(key, value);
836
+ continue;
837
+ }
838
+ const currentTable = document.tables.get(currentTableName);
839
+ if (!currentTable) {
840
+ continue;
841
+ }
842
+ if (!currentTable.values.has(key)) {
843
+ currentTable.order.push(key);
844
+ }
845
+ currentTable.values.set(key, value);
846
+ }
847
+ return document;
848
+ }
849
+ function mergeCodexTomlDocuments(source, preset) {
850
+ const merged = {
851
+ rootOrder: [...source.rootOrder],
852
+ rootValues: new Map(source.rootValues),
853
+ tableOrder: [...source.tableOrder],
854
+ tables: new Map(Array.from(source.tables.entries()).map(([tableName, table]) => [
855
+ tableName,
856
+ {
857
+ order: [...table.order],
858
+ values: new Map(table.values)
859
+ }
860
+ ]))
861
+ };
862
+ for (const key of preset.rootOrder) {
863
+ if (!merged.rootValues.has(key)) {
864
+ merged.rootOrder.push(key);
865
+ }
866
+ const value = preset.rootValues.get(key);
867
+ if (value) {
868
+ merged.rootValues.set(key, value);
869
+ }
870
+ }
871
+ for (const tableName of preset.tableOrder) {
872
+ const presetTable = preset.tables.get(tableName);
873
+ if (!presetTable) {
874
+ continue;
875
+ }
876
+ if (!merged.tables.has(tableName)) {
877
+ merged.tableOrder.push(tableName);
878
+ merged.tables.set(tableName, {
879
+ order: [],
880
+ values: new Map()
881
+ });
882
+ }
883
+ const mergedTable = merged.tables.get(tableName);
884
+ for (const key of presetTable.order) {
885
+ if (!mergedTable.values.has(key)) {
886
+ mergedTable.order.push(key);
887
+ }
888
+ const value = presetTable.values.get(key);
889
+ if (value) {
890
+ mergedTable.values.set(key, value);
891
+ }
892
+ }
893
+ }
894
+ return merged;
895
+ }
896
+ function serializeSimpleTomlDocument(document) {
897
+ const lines = ["# 会话级 Codex 配置(系统自动生成)"];
898
+ if (document.rootOrder.length > 0) {
899
+ lines.push("");
900
+ for (const key of document.rootOrder) {
901
+ const value = document.rootValues.get(key);
902
+ if (!value) {
903
+ continue;
904
+ }
905
+ lines.push(`${key} = ${value}`);
906
+ }
907
+ }
908
+ for (const tableName of document.tableOrder) {
909
+ const table = document.tables.get(tableName);
910
+ if (!table || table.order.length === 0) {
911
+ continue;
912
+ }
913
+ lines.push("");
914
+ lines.push(`[${tableName}]`);
915
+ for (const key of table.order) {
916
+ const value = table.values.get(key);
917
+ if (!value) {
918
+ continue;
919
+ }
920
+ lines.push(`${key} = ${value}`);
921
+ }
922
+ }
923
+ return lines.join("\n");
924
+ }
925
+ //# sourceMappingURL=session-provider-config-service.js.map