@kaitranntt/ccs 7.79.1 → 8.0.0-dev.1

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 (338) hide show
  1. package/README.md +29 -11
  2. package/dist/bin/ccsxp-runtime.d.ts.map +1 -1
  3. package/dist/bin/ccsxp-runtime.js +8 -0
  4. package/dist/bin/ccsxp-runtime.js.map +1 -1
  5. package/dist/bin/codex-runtime-router.d.ts +24 -0
  6. package/dist/bin/codex-runtime-router.d.ts.map +1 -0
  7. package/dist/bin/codex-runtime-router.js +117 -0
  8. package/dist/bin/codex-runtime-router.js.map +1 -0
  9. package/dist/bin/codex-runtime.d.ts +1 -0
  10. package/dist/bin/codex-runtime.js +7 -2
  11. package/dist/bin/codex-runtime.js.map +1 -1
  12. package/dist/ccs.js +2 -1
  13. package/dist/ccs.js.map +1 -1
  14. package/dist/cliproxy/ai-providers/codex-plan-compatibility.js +2 -2
  15. package/dist/cliproxy/ai-providers/codex-plan-compatibility.js.map +1 -1
  16. package/dist/cliproxy/ai-providers/codex-reasoning-proxy.d.ts +2 -2
  17. package/dist/cliproxy/ai-providers/codex-reasoning-proxy.d.ts.map +1 -1
  18. package/dist/cliproxy/ai-providers/codex-reasoning-proxy.js +16 -8
  19. package/dist/cliproxy/ai-providers/codex-reasoning-proxy.js.map +1 -1
  20. package/dist/cliproxy/ai-providers/model-id-normalizer.d.ts +8 -0
  21. package/dist/cliproxy/ai-providers/model-id-normalizer.d.ts.map +1 -1
  22. package/dist/cliproxy/ai-providers/model-id-normalizer.js +19 -2
  23. package/dist/cliproxy/ai-providers/model-id-normalizer.js.map +1 -1
  24. package/dist/cliproxy/ai-providers/service.d.ts.map +1 -1
  25. package/dist/cliproxy/ai-providers/service.js +39 -12
  26. package/dist/cliproxy/ai-providers/service.js.map +1 -1
  27. package/dist/cliproxy/auth/oauth-handler.d.ts +13 -1
  28. package/dist/cliproxy/auth/oauth-handler.d.ts.map +1 -1
  29. package/dist/cliproxy/auth/oauth-handler.js +111 -34
  30. package/dist/cliproxy/auth/oauth-handler.js.map +1 -1
  31. package/dist/cliproxy/auth/oauth-trace/redactor.d.ts.map +1 -1
  32. package/dist/cliproxy/auth/oauth-trace/redactor.js +9 -1
  33. package/dist/cliproxy/auth/oauth-trace/redactor.js.map +1 -1
  34. package/dist/cliproxy/config/generator.d.ts.map +1 -1
  35. package/dist/cliproxy/config/generator.js +5 -2
  36. package/dist/cliproxy/config/generator.js.map +1 -1
  37. package/dist/cliproxy/config/thinking-config.js +6 -6
  38. package/dist/cliproxy/config/thinking-config.js.map +1 -1
  39. package/dist/cliproxy/executor/env-resolver.js +1 -1
  40. package/dist/cliproxy/executor/env-resolver.js.map +1 -1
  41. package/dist/cliproxy/executor/session-bridge.d.ts.map +1 -1
  42. package/dist/cliproxy/executor/session-bridge.js +11 -8
  43. package/dist/cliproxy/executor/session-bridge.js.map +1 -1
  44. package/dist/cliproxy/quota/quota-fetcher-claude.d.ts.map +1 -1
  45. package/dist/cliproxy/quota/quota-fetcher-claude.js +35 -4
  46. package/dist/cliproxy/quota/quota-fetcher-claude.js.map +1 -1
  47. package/dist/cliproxy/quota/quota-manager.d.ts +1 -0
  48. package/dist/cliproxy/quota/quota-manager.d.ts.map +1 -1
  49. package/dist/cliproxy/quota/quota-manager.js +53 -2
  50. package/dist/cliproxy/quota/quota-manager.js.map +1 -1
  51. package/dist/cliproxy/services/oauth-usage-log-transformer.d.ts.map +1 -1
  52. package/dist/cliproxy/services/oauth-usage-log-transformer.js +5 -0
  53. package/dist/cliproxy/services/oauth-usage-log-transformer.js.map +1 -1
  54. package/dist/codex-auth/codex-account-identity.d.ts +8 -0
  55. package/dist/codex-auth/codex-account-identity.d.ts.map +1 -0
  56. package/dist/codex-auth/codex-account-identity.js +53 -0
  57. package/dist/codex-auth/codex-account-identity.js.map +1 -0
  58. package/dist/codex-auth/codex-auth-dashboard-service.d.ts +46 -0
  59. package/dist/codex-auth/codex-auth-dashboard-service.d.ts.map +1 -0
  60. package/dist/codex-auth/codex-auth-dashboard-service.js +228 -0
  61. package/dist/codex-auth/codex-auth-dashboard-service.js.map +1 -0
  62. package/dist/codex-auth/codex-auth-help.d.ts +7 -0
  63. package/dist/codex-auth/codex-auth-help.d.ts.map +1 -0
  64. package/dist/codex-auth/codex-auth-help.js +87 -0
  65. package/dist/codex-auth/codex-auth-help.js.map +1 -0
  66. package/dist/codex-auth/codex-auth-router.d.ts +16 -0
  67. package/dist/codex-auth/codex-auth-router.d.ts.map +1 -0
  68. package/dist/codex-auth/codex-auth-router.js +77 -0
  69. package/dist/codex-auth/codex-auth-router.js.map +1 -0
  70. package/dist/codex-auth/codex-config-symlink.d.ts +14 -0
  71. package/dist/codex-auth/codex-config-symlink.d.ts.map +1 -0
  72. package/dist/codex-auth/codex-config-symlink.js +128 -0
  73. package/dist/codex-auth/codex-config-symlink.js.map +1 -0
  74. package/dist/codex-auth/codex-profile-paths.d.ts +5 -0
  75. package/dist/codex-auth/codex-profile-paths.d.ts.map +1 -0
  76. package/dist/codex-auth/codex-profile-paths.js +58 -0
  77. package/dist/codex-auth/codex-profile-paths.js.map +1 -0
  78. package/dist/codex-auth/codex-profile-registry.d.ts +34 -0
  79. package/dist/codex-auth/codex-profile-registry.d.ts.map +1 -0
  80. package/dist/codex-auth/codex-profile-registry.js +360 -0
  81. package/dist/codex-auth/codex-profile-registry.js.map +1 -0
  82. package/dist/codex-auth/codex-profile-resources.d.ts +6 -0
  83. package/dist/codex-auth/codex-profile-resources.d.ts.map +1 -0
  84. package/dist/codex-auth/codex-profile-resources.js +119 -0
  85. package/dist/codex-auth/codex-profile-resources.js.map +1 -0
  86. package/dist/codex-auth/commands/create-command.d.ts +9 -0
  87. package/dist/codex-auth/commands/create-command.d.ts.map +1 -0
  88. package/dist/codex-auth/commands/create-command.js +203 -0
  89. package/dist/codex-auth/commands/create-command.js.map +1 -0
  90. package/dist/codex-auth/commands/import-default-command.d.ts +18 -0
  91. package/dist/codex-auth/commands/import-default-command.d.ts.map +1 -0
  92. package/dist/codex-auth/commands/import-default-command.js +385 -0
  93. package/dist/codex-auth/commands/import-default-command.js.map +1 -0
  94. package/dist/codex-auth/commands/index.d.ts +13 -0
  95. package/dist/codex-auth/commands/index.d.ts.map +1 -0
  96. package/dist/codex-auth/commands/index.js +27 -0
  97. package/dist/codex-auth/commands/index.js.map +1 -0
  98. package/dist/codex-auth/commands/login-command.d.ts +9 -0
  99. package/dist/codex-auth/commands/login-command.d.ts.map +1 -0
  100. package/dist/codex-auth/commands/login-command.js +152 -0
  101. package/dist/codex-auth/commands/login-command.js.map +1 -0
  102. package/dist/codex-auth/commands/remove-command.d.ts +10 -0
  103. package/dist/codex-auth/commands/remove-command.d.ts.map +1 -0
  104. package/dist/codex-auth/commands/remove-command.js +230 -0
  105. package/dist/codex-auth/commands/remove-command.js.map +1 -0
  106. package/dist/codex-auth/commands/show-command.d.ts +10 -0
  107. package/dist/codex-auth/commands/show-command.d.ts.map +1 -0
  108. package/dist/codex-auth/commands/show-command.js +127 -0
  109. package/dist/codex-auth/commands/show-command.js.map +1 -0
  110. package/dist/codex-auth/commands/show-detail-view.d.ts +7 -0
  111. package/dist/codex-auth/commands/show-detail-view.d.ts.map +1 -0
  112. package/dist/codex-auth/commands/show-detail-view.js +134 -0
  113. package/dist/codex-auth/commands/show-detail-view.js.map +1 -0
  114. package/dist/codex-auth/commands/switch-command.d.ts +7 -0
  115. package/dist/codex-auth/commands/switch-command.d.ts.map +1 -0
  116. package/dist/codex-auth/commands/switch-command.js +48 -0
  117. package/dist/codex-auth/commands/switch-command.js.map +1 -0
  118. package/dist/codex-auth/commands/types.d.ts +45 -0
  119. package/dist/codex-auth/commands/types.d.ts.map +1 -0
  120. package/dist/codex-auth/commands/types.js +85 -0
  121. package/dist/codex-auth/commands/types.js.map +1 -0
  122. package/dist/codex-auth/commands/use-command.d.ts +16 -0
  123. package/dist/codex-auth/commands/use-command.d.ts.map +1 -0
  124. package/dist/codex-auth/commands/use-command.js +86 -0
  125. package/dist/codex-auth/commands/use-command.js.map +1 -0
  126. package/dist/codex-auth/decode-id-token.d.ts +12 -0
  127. package/dist/codex-auth/decode-id-token.d.ts.map +1 -0
  128. package/dist/codex-auth/decode-id-token.js +83 -0
  129. package/dist/codex-auth/decode-id-token.js.map +1 -0
  130. package/dist/codex-auth/index.d.ts +9 -0
  131. package/dist/codex-auth/index.d.ts.map +1 -0
  132. package/dist/codex-auth/index.js +22 -0
  133. package/dist/codex-auth/index.js.map +1 -0
  134. package/dist/codex-auth/resolve-active-profile.d.ts +13 -0
  135. package/dist/codex-auth/resolve-active-profile.d.ts.map +1 -0
  136. package/dist/codex-auth/resolve-active-profile.js +161 -0
  137. package/dist/codex-auth/resolve-active-profile.js.map +1 -0
  138. package/dist/codex-auth/shell-detect.d.ts +19 -0
  139. package/dist/codex-auth/shell-detect.d.ts.map +1 -0
  140. package/dist/codex-auth/shell-detect.js +129 -0
  141. package/dist/codex-auth/shell-detect.js.map +1 -0
  142. package/dist/codex-auth/types.d.ts +26 -0
  143. package/dist/codex-auth/types.d.ts.map +1 -0
  144. package/dist/codex-auth/types.js +34 -0
  145. package/dist/codex-auth/types.js.map +1 -0
  146. package/dist/commands/cliproxy/variant-subcommand.js +1 -1
  147. package/dist/commands/cliproxy/variant-subcommand.js.map +1 -1
  148. package/dist/commands/command-catalog.d.ts +1 -1
  149. package/dist/commands/command-catalog.d.ts.map +1 -1
  150. package/dist/commands/command-catalog.js +10 -1
  151. package/dist/commands/command-catalog.js.map +1 -1
  152. package/dist/commands/completion-backend.d.ts.map +1 -1
  153. package/dist/commands/completion-backend.js +2 -0
  154. package/dist/commands/completion-backend.js.map +1 -1
  155. package/dist/commands/config-command.d.ts +2 -0
  156. package/dist/commands/config-command.d.ts.map +1 -1
  157. package/dist/commands/config-command.js +31 -20
  158. package/dist/commands/config-command.js.map +1 -1
  159. package/dist/commands/docker/finalize-key-rotation-subcommand.d.ts +2 -0
  160. package/dist/commands/docker/finalize-key-rotation-subcommand.d.ts.map +1 -0
  161. package/dist/commands/docker/finalize-key-rotation-subcommand.js +79 -0
  162. package/dist/commands/docker/finalize-key-rotation-subcommand.js.map +1 -0
  163. package/dist/commands/docker/help-subcommand.d.ts.map +1 -1
  164. package/dist/commands/docker/help-subcommand.js +6 -0
  165. package/dist/commands/docker/help-subcommand.js.map +1 -1
  166. package/dist/commands/docker/index.d.ts.map +1 -1
  167. package/dist/commands/docker/index.js +4 -0
  168. package/dist/commands/docker/index.js.map +1 -1
  169. package/dist/commands/docker/show-key-subcommand.d.ts +2 -0
  170. package/dist/commands/docker/show-key-subcommand.d.ts.map +1 -0
  171. package/dist/commands/docker/show-key-subcommand.js +96 -0
  172. package/dist/commands/docker/show-key-subcommand.js.map +1 -0
  173. package/dist/commands/docker/up-subcommand.d.ts.map +1 -1
  174. package/dist/commands/docker/up-subcommand.js +4 -0
  175. package/dist/commands/docker/up-subcommand.js.map +1 -1
  176. package/dist/commands/persist-command.d.ts.map +1 -1
  177. package/dist/commands/persist-command.js +77 -5
  178. package/dist/commands/persist-command.js.map +1 -1
  179. package/dist/dispatcher/cli-argument-parser.d.ts +3 -2
  180. package/dist/dispatcher/cli-argument-parser.d.ts.map +1 -1
  181. package/dist/dispatcher/cli-argument-parser.js +37 -7
  182. package/dist/dispatcher/cli-argument-parser.js.map +1 -1
  183. package/dist/dispatcher/pre-dispatch.d.ts.map +1 -1
  184. package/dist/dispatcher/pre-dispatch.js +7 -0
  185. package/dist/dispatcher/pre-dispatch.js.map +1 -1
  186. package/dist/dispatcher/target-executor.d.ts +2 -2
  187. package/dist/dispatcher/target-executor.d.ts.map +1 -1
  188. package/dist/dispatcher/target-executor.js +5 -5
  189. package/dist/dispatcher/target-executor.js.map +1 -1
  190. package/dist/docker/docker-bootstrap.d.ts +1 -1
  191. package/dist/docker/docker-bootstrap.d.ts.map +1 -1
  192. package/dist/docker/docker-bootstrap.js +99 -3
  193. package/dist/docker/docker-bootstrap.js.map +1 -1
  194. package/dist/docker/docker-executor.d.ts +3 -0
  195. package/dist/docker/docker-executor.d.ts.map +1 -1
  196. package/dist/docker/docker-executor.js +53 -0
  197. package/dist/docker/docker-executor.js.map +1 -1
  198. package/dist/docker/docker-key-rotation.d.ts +48 -0
  199. package/dist/docker/docker-key-rotation.d.ts.map +1 -0
  200. package/dist/docker/docker-key-rotation.js +179 -0
  201. package/dist/docker/docker-key-rotation.js.map +1 -0
  202. package/dist/management/checks/config-check.d.ts.map +1 -1
  203. package/dist/management/checks/config-check.js +10 -1
  204. package/dist/management/checks/config-check.js.map +1 -1
  205. package/dist/management/doctor.d.ts +1 -0
  206. package/dist/management/doctor.d.ts.map +1 -1
  207. package/dist/management/doctor.js +23 -0
  208. package/dist/management/doctor.js.map +1 -1
  209. package/dist/proxy/proxy-daemon.d.ts.map +1 -1
  210. package/dist/proxy/proxy-daemon.js +15 -3
  211. package/dist/proxy/proxy-daemon.js.map +1 -1
  212. package/dist/proxy/server/messages-route.d.ts.map +1 -1
  213. package/dist/proxy/server/messages-route.js +27 -1
  214. package/dist/proxy/server/messages-route.js.map +1 -1
  215. package/dist/shared/claude-extension-setup.d.ts.map +1 -1
  216. package/dist/shared/claude-extension-setup.js +21 -1
  217. package/dist/shared/claude-extension-setup.js.map +1 -1
  218. package/dist/shared/stale-codex-translator-settings.d.ts +4 -0
  219. package/dist/shared/stale-codex-translator-settings.d.ts.map +1 -0
  220. package/dist/shared/stale-codex-translator-settings.js +35 -0
  221. package/dist/shared/stale-codex-translator-settings.js.map +1 -0
  222. package/dist/targets/codex-adapter.d.ts.map +1 -1
  223. package/dist/targets/codex-adapter.js +64 -5
  224. package/dist/targets/codex-adapter.js.map +1 -1
  225. package/dist/targets/codex-cliproxy-provider-config.d.ts.map +1 -1
  226. package/dist/targets/codex-cliproxy-provider-config.js +56 -24
  227. package/dist/targets/codex-cliproxy-provider-config.js.map +1 -1
  228. package/dist/ui/assets/Trans-dEd8UC39.js +1 -0
  229. package/dist/ui/assets/accounts-B2THsSu_.js +1 -0
  230. package/dist/ui/assets/{alert-dialog-DC1l1GRX.js → alert-dialog-Vurq1xzV.js} +1 -1
  231. package/dist/ui/assets/api-CjLfG9mL.js +4 -0
  232. package/dist/ui/assets/auth-section-iGkrMaT4.js +1 -0
  233. package/dist/ui/assets/backups-section-DUGG_4KP.js +1 -0
  234. package/dist/ui/assets/channels-CimlCc2d.js +1 -0
  235. package/dist/ui/assets/{charts-CeK2xCSo.js → charts-eIPy2oG6.js} +34 -34
  236. package/dist/ui/assets/{checkbox-Dgd2ucy2.js → checkbox-HiMHasEB.js} +1 -1
  237. package/dist/ui/assets/claude-extension-B2v9bsN9.js +1 -0
  238. package/dist/ui/assets/{cliproxy-ai-providers-DxoCNEaQ.js → cliproxy-ai-providers-2lI5jSHb.js} +6 -6
  239. package/dist/ui/assets/cliproxy-control-panel-63gDI-e5.js +1 -0
  240. package/dist/ui/assets/cliproxy-fai69Vyd.js +4 -0
  241. package/dist/ui/assets/code-highlight-ClSMkeL5.js +1 -0
  242. package/dist/ui/assets/codex-i_hfI4Tv.js +30 -0
  243. package/dist/ui/assets/{confirm-dialog-nDFNrH0F.js → confirm-dialog-B_6SrSxL.js} +1 -1
  244. package/dist/ui/assets/copilot-BgG5x_X6.js +3 -0
  245. package/dist/ui/assets/cursor-DF63lFcy.js +1 -0
  246. package/dist/ui/assets/droid-CqlQmFtN.js +2 -0
  247. package/dist/ui/assets/globalenv-section-CYNmD12i.js +1 -0
  248. package/dist/ui/assets/health-7ZO5PEm9.js +1 -0
  249. package/dist/ui/assets/index-BC5ssPfF.js +1 -0
  250. package/dist/ui/assets/index-BMoGhs28.css +1 -0
  251. package/dist/ui/assets/index-Bgcd4FYK.js +1 -0
  252. package/dist/ui/assets/index-CFu0saCM.js +1 -0
  253. package/dist/ui/assets/index-CqsmdQoA.js +1 -0
  254. package/dist/ui/assets/index-D3kxCuJ7.js +1 -0
  255. package/dist/ui/assets/index-DmV9wJET.js +56 -0
  256. package/dist/ui/assets/index-hHb9o079.js +1 -0
  257. package/dist/ui/assets/logs-Dy-yZhIK.js +1 -0
  258. package/dist/ui/assets/{masked-input-5TJ4LSuz.js → masked-input-BSLeznEs.js} +1 -1
  259. package/dist/ui/assets/proxy-status-widget-hRH1agF9.js +1 -0
  260. package/dist/ui/assets/{raw-json-settings-editor-panel-Fg4WMiuD.js → raw-json-settings-editor-panel-Bs83yILR.js} +1 -1
  261. package/dist/ui/assets/{searchable-select-CPJn5vA1.js → searchable-select-pXUC_0Ih.js} +1 -1
  262. package/dist/ui/assets/{separator-BrQkfpAp.js → separator-FZR_61I9.js} +1 -1
  263. package/dist/ui/assets/shared-BiIwM7--.js +8 -0
  264. package/dist/ui/assets/{table-DRzNRkpJ.js → table-_9IusQ8G.js} +1 -1
  265. package/dist/ui/assets/updates-ButNfJqt.js +1 -0
  266. package/dist/ui/assets/{use-accounts-B6AXtlfF.js → use-accounts-BdtI0lBv.js} +1 -1
  267. package/dist/ui/index.html +3 -3
  268. package/dist/utils/claude-subcommand-detector.d.ts +12 -3
  269. package/dist/utils/claude-subcommand-detector.d.ts.map +1 -1
  270. package/dist/utils/claude-subcommand-detector.js +59 -12
  271. package/dist/utils/claude-subcommand-detector.js.map +1 -1
  272. package/dist/web-server/middleware/auth-middleware.d.ts.map +1 -1
  273. package/dist/web-server/middleware/auth-middleware.js +25 -1
  274. package/dist/web-server/middleware/auth-middleware.js.map +1 -1
  275. package/dist/web-server/routes/claude-extension-routes.d.ts.map +1 -1
  276. package/dist/web-server/routes/claude-extension-routes.js +5 -0
  277. package/dist/web-server/routes/claude-extension-routes.js.map +1 -1
  278. package/dist/web-server/routes/cliproxy-stats-routes.d.ts +8 -0
  279. package/dist/web-server/routes/cliproxy-stats-routes.d.ts.map +1 -1
  280. package/dist/web-server/routes/cliproxy-stats-routes.js +13 -26
  281. package/dist/web-server/routes/cliproxy-stats-routes.js.map +1 -1
  282. package/dist/web-server/routes/codex-routes.d.ts.map +1 -1
  283. package/dist/web-server/routes/codex-routes.js +14 -0
  284. package/dist/web-server/routes/codex-routes.js.map +1 -1
  285. package/dist/web-server/services/cliproxy-dashboard-restart-service.d.ts +21 -0
  286. package/dist/web-server/services/cliproxy-dashboard-restart-service.d.ts.map +1 -0
  287. package/dist/web-server/services/cliproxy-dashboard-restart-service.js +49 -0
  288. package/dist/web-server/services/cliproxy-dashboard-restart-service.js.map +1 -0
  289. package/dist/web-server/services/codex-dashboard-service.d.ts.map +1 -1
  290. package/dist/web-server/services/codex-dashboard-service.js +30 -3
  291. package/dist/web-server/services/codex-dashboard-service.js.map +1 -1
  292. package/dist/web-server/usage/aggregator.d.ts +13 -7
  293. package/dist/web-server/usage/aggregator.d.ts.map +1 -1
  294. package/dist/web-server/usage/aggregator.js +37 -22
  295. package/dist/web-server/usage/aggregator.js.map +1 -1
  296. package/dist/web-server/usage/handlers.d.ts +1 -0
  297. package/dist/web-server/usage/handlers.d.ts.map +1 -1
  298. package/dist/web-server/usage/handlers.js +16 -8
  299. package/dist/web-server/usage/handlers.js.map +1 -1
  300. package/dist/web-server/usage/profile-filter.d.ts +13 -0
  301. package/dist/web-server/usage/profile-filter.d.ts.map +1 -0
  302. package/dist/web-server/usage/profile-filter.js +30 -0
  303. package/dist/web-server/usage/profile-filter.js.map +1 -0
  304. package/dist/web-server/usage/types.d.ts +8 -0
  305. package/dist/web-server/usage/types.d.ts.map +1 -1
  306. package/lib/hooks/websearch-transformer.cjs +12 -3
  307. package/lib/mcp/ccs-browser-server.cjs +217 -12
  308. package/package.json +1 -1
  309. package/scripts/docker-dashboard-sunset-guard.js +171 -0
  310. package/scripts/run-test-bucket.js +1 -0
  311. package/scripts/verify-bundle.js +4 -1
  312. package/dist/ui/assets/accounts-BQu3Aeey.js +0 -1
  313. package/dist/ui/assets/api-BTbrbjic.js +0 -4
  314. package/dist/ui/assets/auth-section-BsSVWOMp.js +0 -1
  315. package/dist/ui/assets/backups-section-BGHYHASS.js +0 -1
  316. package/dist/ui/assets/channels-vJ8L4j-z.js +0 -1
  317. package/dist/ui/assets/claude-extension-B3ern4Ad.js +0 -1
  318. package/dist/ui/assets/cliproxy-CGljI0Or.js +0 -4
  319. package/dist/ui/assets/cliproxy-control-panel-BJ3Mliy1.js +0 -1
  320. package/dist/ui/assets/code-highlight-D4E79GKQ.js +0 -3
  321. package/dist/ui/assets/codex-DBGHPn0v.js +0 -30
  322. package/dist/ui/assets/copilot-CE_Z3NB0.js +0 -3
  323. package/dist/ui/assets/cursor-YzGsSR_d.js +0 -1
  324. package/dist/ui/assets/droid-C-ItViCi.js +0 -2
  325. package/dist/ui/assets/globalenv-section-C9gSGyZ8.js +0 -1
  326. package/dist/ui/assets/health-DEeA97sQ.js +0 -1
  327. package/dist/ui/assets/index-B71yJlMj.css +0 -1
  328. package/dist/ui/assets/index-BPVO-QAw.js +0 -1
  329. package/dist/ui/assets/index-BRZp_Csi.js +0 -72
  330. package/dist/ui/assets/index-BYUwpOeA.js +0 -1
  331. package/dist/ui/assets/index-D2r_fAW5.js +0 -1
  332. package/dist/ui/assets/index-DGiziSVQ.js +0 -1
  333. package/dist/ui/assets/index-DwG6bbUr.js +0 -1
  334. package/dist/ui/assets/index-Dwtj4wGT.js +0 -1
  335. package/dist/ui/assets/logs-Mt2W7M3G.js +0 -1
  336. package/dist/ui/assets/proxy-status-widget-BQOAlYsb.js +0 -1
  337. package/dist/ui/assets/shared-BlkDl2HF.js +0 -8
  338. package/dist/ui/assets/updates-BQNeSzLj.js +0 -1
@@ -874,7 +874,10 @@ function runGeminiCommand(args, timeoutMs) {
874
874
  timeout: timeoutMs,
875
875
  maxBuffer: 1024 * 1024 * 2,
876
876
  stdio: ['pipe', 'pipe', 'pipe'],
877
- shell: isWindows,
877
+ // Never route query-derived prompts through a shell. Node concatenates
878
+ // arguments for shell-backed Windows spawns, which lets shell metacharacters
879
+ // in WebSearch queries escape the intended CLI invocation.
880
+ shell: false,
878
881
  });
879
882
 
880
883
  if (result.error) {
@@ -929,7 +932,10 @@ function tryOpenCodeSearch(query, timeoutSec = DEFAULT_TIMEOUT_SEC) {
929
932
  timeout: timeoutSec * 1000,
930
933
  maxBuffer: 1024 * 1024 * 2,
931
934
  stdio: ['pipe', 'pipe', 'pipe'],
932
- shell: isWindows,
935
+ // Never route query-derived prompts through a shell. Node concatenates
936
+ // arguments for shell-backed Windows spawns, which lets shell metacharacters
937
+ // in WebSearch queries escape the intended CLI invocation.
938
+ shell: false,
933
939
  }
934
940
  );
935
941
 
@@ -965,7 +971,10 @@ function tryGrokSearch(query, timeoutSec = DEFAULT_TIMEOUT_SEC) {
965
971
  timeout: timeoutSec * 1000,
966
972
  maxBuffer: 1024 * 1024 * 2,
967
973
  stdio: ['pipe', 'pipe', 'pipe'],
968
- shell: isWindows,
974
+ // Never route query-derived prompts through a shell. Node concatenates
975
+ // arguments for shell-backed Windows spawns, which lets shell metacharacters
976
+ // in WebSearch queries escape the intended CLI invocation.
977
+ shell: false,
969
978
  });
970
979
 
971
980
  if (result.error) {
@@ -83,6 +83,16 @@ const TOOL_HOVER = 'browser_hover';
83
83
  const TOOL_QUERY = 'browser_query';
84
84
  const TOOL_TAKE_ELEMENT_SCREENSHOT = 'browser_take_element_screenshot';
85
85
  const TOOL_WAIT_FOR_EVENT = 'browser_wait_for_event';
86
+ const SENSITIVE_INTERCEPT_HEADER_NAMES = new Set([
87
+ 'authorization',
88
+ 'cookie',
89
+ 'cookie2',
90
+ 'proxy-authorization',
91
+ 'x-api-key',
92
+ 'x-api-token',
93
+ 'x-auth-token',
94
+ ]);
95
+
86
96
  const TOOL_NAMES = [
87
97
  TOOL_SESSION_INFO,
88
98
  TOOL_URL_TITLE,
@@ -612,10 +622,15 @@ function getTools() {
612
622
  urlRegex: { type: 'string' },
613
623
  headerMatchers: {
614
624
  type: 'array',
625
+ description:
626
+ 'Match non-sensitive request headers. Cookie, Authorization, and token headers are not allowed.',
615
627
  items: {
616
628
  type: 'object',
617
629
  properties: {
618
- name: { type: 'string' },
630
+ name: {
631
+ type: 'string',
632
+ description: 'Non-sensitive request header name to match.',
633
+ },
619
634
  valueIncludes: { type: 'string' },
620
635
  valueRegex: { type: 'string' },
621
636
  },
@@ -624,7 +639,7 @@ function getTools() {
624
639
  },
625
640
  },
626
641
  priority: { type: 'integer' },
627
- action: { type: 'string', enum: ['continue', 'fail', 'fulfill'] },
642
+ action: { type: 'string', enum: getInterceptActionEnum() },
628
643
  statusCode: { type: 'integer', minimum: 100, maximum: 599 },
629
644
  responseHeaders: {
630
645
  type: 'array',
@@ -1194,7 +1209,18 @@ function getTools() {
1194
1209
  },
1195
1210
  event: {
1196
1211
  type: 'object',
1197
- description: 'Required event selector.',
1212
+ description:
1213
+ 'Required event selector. request events require urlIncludes; download events require urlIncludes or suggestedFilenameIncludes. URLs in returned details are redacted.',
1214
+ properties: {
1215
+ kind: { type: 'string', enum: ['dialog', 'navigation', 'request', 'download'] },
1216
+ dialogType: { type: 'string' },
1217
+ messageIncludes: { type: 'string' },
1218
+ urlIncludes: { type: 'string' },
1219
+ method: { type: 'string' },
1220
+ suggestedFilenameIncludes: { type: 'string' },
1221
+ },
1222
+ required: ['kind'],
1223
+ additionalProperties: false,
1198
1224
  },
1199
1225
  },
1200
1226
  required: ['event'],
@@ -1277,9 +1303,30 @@ function parseOptionalPageId(toolArgs) {
1277
1303
  : '';
1278
1304
  }
1279
1305
 
1306
+ function getBrowserInterceptFulfillMode() {
1307
+ return String(process.env.CCS_BROWSER_INTERCEPT_FULFILL_MODE || 'disabled').trim() === 'enabled'
1308
+ ? 'enabled'
1309
+ : 'disabled';
1310
+ }
1311
+
1312
+ function isBrowserInterceptFulfillEnabled() {
1313
+ return getBrowserInterceptFulfillMode() === 'enabled';
1314
+ }
1315
+
1316
+ function getInterceptActionEnum() {
1317
+ return isBrowserInterceptFulfillEnabled()
1318
+ ? ['continue', 'fail', 'fulfill']
1319
+ : ['continue', 'fail'];
1320
+ }
1321
+
1280
1322
  function parseInterceptAction(value) {
1323
+ if (value === 'fulfill' && !isBrowserInterceptFulfillEnabled()) {
1324
+ throw new Error(
1325
+ 'action fulfill is disabled by CCS_BROWSER_INTERCEPT_FULFILL_MODE=disabled; set it to enabled only for trusted local testing'
1326
+ );
1327
+ }
1281
1328
  if (value !== 'continue' && value !== 'fail' && value !== 'fulfill') {
1282
- throw new Error('action must be one of: continue, fail, fulfill');
1329
+ throw new Error(`action must be one of: ${getInterceptActionEnum().join(', ')}`);
1283
1330
  }
1284
1331
  return value;
1285
1332
  }
@@ -1379,6 +1426,10 @@ function parseOptionalPriority(value) {
1379
1426
  return value;
1380
1427
  }
1381
1428
 
1429
+ function isSensitiveInterceptHeaderName(name) {
1430
+ return SENSITIVE_INTERCEPT_HEADER_NAMES.has(name.toLowerCase());
1431
+ }
1432
+
1382
1433
  function parseOptionalHeaderMatchers(value) {
1383
1434
  if (value === undefined) {
1384
1435
  return [];
@@ -1391,6 +1442,9 @@ function parseOptionalHeaderMatchers(value) {
1391
1442
  throw new Error('headerMatchers entries must be objects');
1392
1443
  }
1393
1444
  const name = requireNonEmptyString(entry.name, 'headerMatchers.name');
1445
+ if (isSensitiveInterceptHeaderName(name)) {
1446
+ throw new Error(`headerMatchers.name cannot target sensitive request header: ${name}`);
1447
+ }
1394
1448
  const valueIncludes =
1395
1449
  entry.valueIncludes === undefined
1396
1450
  ? ''
@@ -3305,24 +3359,80 @@ function parseEventCondition(value) {
3305
3359
  };
3306
3360
  }
3307
3361
  if (value.kind === 'request') {
3362
+ const urlIncludes = value.urlIncludes ? String(value.urlIncludes) : undefined;
3363
+ if (!urlIncludes) {
3364
+ throw new Error('request events require urlIncludes to limit network metadata exposure');
3365
+ }
3308
3366
  return {
3309
3367
  kind: 'request',
3310
- urlIncludes: value.urlIncludes ? String(value.urlIncludes) : undefined,
3368
+ urlIncludes,
3311
3369
  method: value.method ? String(value.method) : undefined,
3312
3370
  };
3313
3371
  }
3314
3372
  if (value.kind === 'download') {
3373
+ const urlIncludes = value.urlIncludes ? String(value.urlIncludes) : undefined;
3374
+ const suggestedFilenameIncludes = value.suggestedFilenameIncludes
3375
+ ? String(value.suggestedFilenameIncludes)
3376
+ : undefined;
3377
+ if (!urlIncludes && !suggestedFilenameIncludes) {
3378
+ throw new Error(
3379
+ 'download events require urlIncludes or suggestedFilenameIncludes to limit metadata exposure'
3380
+ );
3381
+ }
3315
3382
  return {
3316
3383
  kind: 'download',
3317
- urlIncludes: value.urlIncludes ? String(value.urlIncludes) : undefined,
3318
- suggestedFilenameIncludes: value.suggestedFilenameIncludes
3319
- ? String(value.suggestedFilenameIncludes)
3320
- : undefined,
3384
+ urlIncludes,
3385
+ suggestedFilenameIncludes,
3321
3386
  };
3322
3387
  }
3323
3388
  throw new Error(`unknown event kind: ${String(value.kind || '')}`);
3324
3389
  }
3325
3390
 
3391
+ function redactUrlForModel(value, options = {}) {
3392
+ const rawUrl = String(value || '');
3393
+ if (!rawUrl) {
3394
+ return '';
3395
+ }
3396
+ try {
3397
+ const url = new URL(rawUrl);
3398
+ if (options.originOnly) {
3399
+ return url.origin;
3400
+ }
3401
+ url.username = '';
3402
+ url.password = '';
3403
+ url.search = '';
3404
+ url.hash = '';
3405
+ return url.toString();
3406
+ } catch {
3407
+ return '[redacted-url]';
3408
+ }
3409
+ }
3410
+
3411
+ function redactObservedEvent(event, observed) {
3412
+ if (!observed || typeof observed !== 'object') {
3413
+ return observed;
3414
+ }
3415
+ if (event.kind === 'request') {
3416
+ return {
3417
+ url: redactUrlForModel(observed.url, { originOnly: true }),
3418
+ method: observed.method || '',
3419
+ };
3420
+ }
3421
+ if (event.kind === 'download') {
3422
+ return {
3423
+ url: redactUrlForModel(observed.url, { originOnly: true }),
3424
+ suggestedFilename: observed.suggestedFilename || '',
3425
+ };
3426
+ }
3427
+ if (event.kind === 'navigation' && Object.prototype.hasOwnProperty.call(observed, 'url')) {
3428
+ return {
3429
+ ...observed,
3430
+ url: redactUrlForModel(observed.url, { originOnly: true }),
3431
+ };
3432
+ }
3433
+ return observed;
3434
+ }
3435
+
3326
3436
  function matchesObservedEvent(event, observed) {
3327
3437
  if (event.kind === 'dialog') {
3328
3438
  return (
@@ -4776,7 +4886,8 @@ async function handleWaitForEvent(toolArgs) {
4776
4886
  );
4777
4887
  const event = parseEventCondition(toolArgs.event);
4778
4888
  const observed = await waitForMatchingEvent({ page, pageIndex, timeoutMs, event });
4779
- return `pageIndex: ${pageIndex}\nevent: ${event.kind}\nstatus: observed\ndetail: ${JSON.stringify(observed)}`;
4889
+ const safeObserved = redactObservedEvent(event, observed);
4890
+ return `pageIndex: ${pageIndex}\nevent: ${event.kind}\nstatus: observed\ndetail: ${JSON.stringify(safeObserved)}`;
4780
4891
  }
4781
4892
 
4782
4893
  function findInterceptRuleIndex(ruleId) {
@@ -5381,7 +5492,10 @@ function buildRecordingInstallExpression(recordingPayload) {
5381
5492
  const recordingPayload = JSON.parse(${JSON.stringify(JSON.stringify(recordingPayload))});
5382
5493
  const existing = globalThis.__CCS_BROWSER_RECORDING_RECORDER__;
5383
5494
  if (existing && existing.installed === true) {
5384
- return { installed: true };
5495
+ if (typeof existing.teardown === 'function') {
5496
+ existing.teardown();
5497
+ }
5498
+ delete globalThis.__CCS_BROWSER_RECORDING_RECORDER__;
5385
5499
  }
5386
5500
 
5387
5501
  const events = Array.isArray(recordingPayload.events) ? [...recordingPayload.events] : [];
@@ -5413,8 +5527,42 @@ function buildRecordingInstallExpression(recordingPayload) {
5413
5527
  timestamp: Date.now(),
5414
5528
  });
5415
5529
  };
5530
+ const sensitiveInputTypes = new Set(['password', 'hidden']);
5531
+ const sensitiveAttributePattern = /(?:pass(?:word|code|phrase)?|pwd|secret|token|api[-_ ]?key|access[-_ ]?key|private[-_ ]?key|credential|otp|one[-_ ]?time[-_ ]?(?:code|password)|verif(?:ication)?[-_ ]?code|security[-_ ]?code|pin|auth(?:orization)?[-_ ]?(?:code|token)|mfa|2fa)/i;
5532
+ const sensitiveAutocompleteValues = new Set([
5533
+ 'current-password',
5534
+ 'new-password',
5535
+ 'one-time-code',
5536
+ 'cc-number',
5537
+ 'cc-csc',
5538
+ ]);
5539
+ const isSensitiveTextTarget = (target) => {
5540
+ if (!target || !(target instanceof Element)) {
5541
+ return false;
5542
+ }
5543
+ if (target instanceof HTMLInputElement) {
5544
+ const inputType = String(target.type || '').toLowerCase();
5545
+ if (sensitiveInputTypes.has(inputType)) {
5546
+ return true;
5547
+ }
5548
+ }
5549
+ const autocompleteTokens = String(target.getAttribute('autocomplete') || '')
5550
+ .toLowerCase()
5551
+ .split(/\s+/)
5552
+ .filter(Boolean);
5553
+ if (autocompleteTokens.some((token) => sensitiveAutocompleteValues.has(token))) {
5554
+ return true;
5555
+ }
5556
+ const attributesToInspect = ['id', 'name', 'placeholder', 'aria-label', 'data-testid'];
5557
+ return attributesToInspect.some((attributeName) =>
5558
+ sensitiveAttributePattern.test(String(target.getAttribute(attributeName) || ''))
5559
+ );
5560
+ };
5416
5561
  const onInput = (event) => {
5417
5562
  const target = event.target;
5563
+ if (isSensitiveTextTarget(target)) {
5564
+ return;
5565
+ }
5418
5566
  let text = '';
5419
5567
  if (target instanceof HTMLInputElement || target instanceof HTMLTextAreaElement) {
5420
5568
  text = target.value;
@@ -5425,7 +5573,19 @@ function buildRecordingInstallExpression(recordingPayload) {
5425
5573
  }
5426
5574
  pushEvent({ kind: 'type', selector: getSelector(target), text, timestamp: Date.now() });
5427
5575
  };
5576
+ const isRecordableKey = (event) => {
5577
+ if (isSensitiveTextTarget(event.target)) {
5578
+ return false;
5579
+ }
5580
+ if (typeof event.key !== 'string' || event.key.length !== 1) {
5581
+ return true;
5582
+ }
5583
+ return event.altKey === true || event.ctrlKey === true || event.metaKey === true;
5584
+ };
5428
5585
  const onKeyDown = (event) => {
5586
+ if (!isRecordableKey(event)) {
5587
+ return;
5588
+ }
5429
5589
  const modifiers = [];
5430
5590
  if (event.altKey) modifiers.push('Alt');
5431
5591
  if (event.ctrlKey) modifiers.push('Control');
@@ -5493,7 +5653,19 @@ async function finalizeRecordingCapture(session) {
5493
5653
  };
5494
5654
 
5495
5655
  const response = await sendCdpCommand(page, 'Runtime.evaluate', {
5496
- expression: `(() => globalThis.__CCS_BROWSER_RECORDING_RECORDER__ || { events: [], warnings: [] })()`,
5656
+ expression: `(() => {
5657
+ const recorder = globalThis.__CCS_BROWSER_RECORDING_RECORDER__;
5658
+ if (!recorder) {
5659
+ return { events: [], warnings: [] };
5660
+ }
5661
+ const events = Array.isArray(recorder.events) ? [...recorder.events] : [];
5662
+ const warnings = Array.isArray(recorder.warnings) ? [...recorder.warnings] : [];
5663
+ if (typeof recorder.teardown === 'function') {
5664
+ recorder.teardown();
5665
+ }
5666
+ delete globalThis.__CCS_BROWSER_RECORDING_RECORDER__;
5667
+ return { events, warnings };
5668
+ })()`,
5497
5669
  returnByValue: true,
5498
5670
  awaitPromise: true,
5499
5671
  });
@@ -5513,6 +5685,28 @@ async function finalizeRecordingCapture(session) {
5513
5685
  session.warnings = warnings.map((warning) => String(warning.message || warning));
5514
5686
  }
5515
5687
 
5688
+ async function teardownRecordingCapture(session) {
5689
+ if (!session || !session.pageWebSocketDebuggerUrl) {
5690
+ return;
5691
+ }
5692
+ const page = {
5693
+ id: session.pageId,
5694
+ webSocketDebuggerUrl: session.pageWebSocketDebuggerUrl,
5695
+ };
5696
+ await sendCdpCommand(page, 'Runtime.evaluate', {
5697
+ expression: `(() => {
5698
+ const recorder = globalThis.__CCS_BROWSER_RECORDING_RECORDER__;
5699
+ if (recorder && typeof recorder.teardown === 'function') {
5700
+ recorder.teardown();
5701
+ }
5702
+ delete globalThis.__CCS_BROWSER_RECORDING_RECORDER__;
5703
+ return { installed: false };
5704
+ })()`,
5705
+ returnByValue: true,
5706
+ awaitPromise: true,
5707
+ });
5708
+ }
5709
+
5516
5710
  async function handleStartRecording(toolArgs) {
5517
5711
  if (activeRecordingSession) {
5518
5712
  throw new Error('recording already active');
@@ -5563,6 +5757,11 @@ async function handleStopRecording() {
5563
5757
  } catch (error) {
5564
5758
  finalizeError = error instanceof Error ? error : new Error(String(error));
5565
5759
  session.warnings.push(`recording capture finalization failed: ${finalizeError.message}`);
5760
+ try {
5761
+ await teardownRecordingCapture(session);
5762
+ } catch {
5763
+ // Preserve the original finalization failure for the caller.
5764
+ }
5566
5765
  }
5567
5766
  session.status = 'stopped';
5568
5767
  session.stoppedAt = new Date().toISOString();
@@ -5583,6 +5782,12 @@ async function handleClearRecording() {
5583
5782
  if (!latestRecordingSession && !activeRecordingSession) {
5584
5783
  throw new Error('no recording available');
5585
5784
  }
5785
+ const session = activeRecordingSession || latestRecordingSession;
5786
+ try {
5787
+ await teardownRecordingCapture(session);
5788
+ } catch {
5789
+ // Clearing session-local recording state should still succeed if the page is already gone.
5790
+ }
5586
5791
  activeRecordingSession = null;
5587
5792
  latestRecordingSession = null;
5588
5793
  return 'status: cleared';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kaitranntt/ccs",
3
- "version": "7.79.1",
3
+ "version": "8.0.0-dev.1",
4
4
  "description": "Claude Code Switch - Instant profile switching between Claude, GLM, Kimi, and more",
5
5
  "keywords": [
6
6
  "cli",
@@ -0,0 +1,171 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const fs = require('node:fs');
5
+ const { execFileSync } = require('node:child_process');
6
+
7
+ function parseStableVersion(value) {
8
+ const match = String(value || '').match(/^v?([0-9]+)\.([0-9]+)\.([0-9]+)$/);
9
+ if (!match) {
10
+ return null;
11
+ }
12
+ return {
13
+ major: Number(match[1]),
14
+ minor: Number(match[2]),
15
+ patch: Number(match[3]),
16
+ raw: `v${Number(match[1])}.${Number(match[2])}.${Number(match[3])}`,
17
+ };
18
+ }
19
+
20
+ function compareVersions(left, right) {
21
+ for (const key of ['major', 'minor', 'patch']) {
22
+ if (left[key] !== right[key]) {
23
+ return left[key] - right[key];
24
+ }
25
+ }
26
+ return 0;
27
+ }
28
+
29
+ function stableVersionKey(version) {
30
+ return `${version.major}.${version.minor}.${version.patch}`;
31
+ }
32
+
33
+ function parseArgs(argv) {
34
+ const args = {};
35
+ for (let i = 0; i < argv.length; i += 1) {
36
+ const arg = argv[i];
37
+ if (!arg.startsWith('--')) {
38
+ throw new Error(`Unexpected argument: ${arg}`);
39
+ }
40
+ const key = arg.slice(2);
41
+ if (key === 'tags-stdin') {
42
+ args.tagsStdin = true;
43
+ continue;
44
+ }
45
+ const value = argv[i + 1];
46
+ if (!value || value.startsWith('--')) {
47
+ throw new Error(`Missing value for --${key}`);
48
+ }
49
+ args[key] = value;
50
+ i += 1;
51
+ }
52
+ return args;
53
+ }
54
+
55
+ function readStableTagsFromGit() {
56
+ const output = execFileSync('git', ['tag', '--list', 'v*'], {
57
+ encoding: 'utf8',
58
+ stdio: ['ignore', 'pipe', 'pipe'],
59
+ });
60
+ return output.split(/\r?\n/).filter(Boolean);
61
+ }
62
+
63
+ function parseStableTags(tags) {
64
+ const byKey = new Map();
65
+ for (const tag of tags) {
66
+ const version = parseStableVersion(tag.trim());
67
+ if (version) {
68
+ byKey.set(stableVersionKey(version), version);
69
+ }
70
+ }
71
+ return Array.from(byKey.values()).sort(compareVersions);
72
+ }
73
+
74
+ function evaluateDashboardSunset({ targetTag, baselineVersion, releaseWindow, stableTags }) {
75
+ const target = parseStableVersion(targetTag);
76
+ if (!target) {
77
+ throw new Error(`Target tag must be stable semver like v1.2.3, got: ${targetTag}`);
78
+ }
79
+
80
+ const baseline = parseStableVersion(baselineVersion);
81
+ if (!baseline) {
82
+ throw new Error(`DEPRECATION_BASELINE_VERSION must be stable semver, got: ${baselineVersion}`);
83
+ }
84
+
85
+ if (!Number.isInteger(releaseWindow) || releaseWindow < 1) {
86
+ throw new Error(`STABLE_RELEASE_WINDOW must be a positive integer, got: ${releaseWindow}`);
87
+ }
88
+
89
+ if (compareVersions(target, baseline) < 0) {
90
+ return {
91
+ publish: true,
92
+ elapsed: 0,
93
+ reason: `${target.raw} is before dashboard deprecation baseline ${baseline.raw}`,
94
+ };
95
+ }
96
+
97
+ const versions = parseStableTags(stableTags);
98
+ const hasBaseline = versions.some((version) => compareVersions(version, baseline) === 0);
99
+ if (compareVersions(target, baseline) > 0 && !hasBaseline) {
100
+ throw new Error(
101
+ `Cannot count dashboard sunset releases: baseline tag ${baseline.raw} is missing from git tags`,
102
+ );
103
+ }
104
+
105
+ if (!versions.some((version) => compareVersions(version, target) === 0)) {
106
+ versions.push(target);
107
+ versions.sort(compareVersions);
108
+ }
109
+
110
+ const elapsed = versions.filter(
111
+ (version) => compareVersions(version, baseline) > 0 && compareVersions(version, target) <= 0,
112
+ ).length;
113
+ const publish = elapsed < releaseWindow;
114
+ const reason = publish
115
+ ? `legacy dashboard publish is still inside sunset window (${elapsed}/${releaseWindow} stable releases elapsed since ${baseline.raw})`
116
+ : `legacy dashboard sunset reached (${elapsed}/${releaseWindow} stable releases elapsed since ${baseline.raw})`;
117
+
118
+ return { publish, elapsed, reason };
119
+ }
120
+
121
+ function appendGithubOutput(values) {
122
+ if (!process.env.GITHUB_OUTPUT) {
123
+ return;
124
+ }
125
+ const lines = Object.entries(values).map(([key, value]) => `${key}=${String(value)}`);
126
+ fs.appendFileSync(process.env.GITHUB_OUTPUT, `${lines.join('\n')}\n`);
127
+ }
128
+
129
+ function main() {
130
+ const args = parseArgs(process.argv.slice(2));
131
+ const targetTag = args.target || process.env.TARGET_TAG;
132
+ const baselineVersion = args.baseline || process.env.DEPRECATION_BASELINE_VERSION;
133
+ const windowValue = args.window || process.env.STABLE_RELEASE_WINDOW || '2';
134
+ const releaseWindow = Number(windowValue);
135
+ const stableTags = args.tagsStdin
136
+ ? fs.readFileSync(0, 'utf8').split(/\r?\n/).filter(Boolean)
137
+ : readStableTagsFromGit();
138
+
139
+ const result = evaluateDashboardSunset({
140
+ targetTag,
141
+ baselineVersion,
142
+ releaseWindow,
143
+ stableTags,
144
+ });
145
+
146
+ appendGithubOutput({
147
+ publish: result.publish ? 'true' : 'false',
148
+ elapsed: result.elapsed,
149
+ reason: result.reason,
150
+ });
151
+
152
+ const status = result.publish ? '[OK]' : '[i]';
153
+ console.log(`${status} ${result.reason}`);
154
+ if (!result.publish) {
155
+ console.log('[i] Skipping ghcr.io/kaitranntt/ccs-dashboard publish; use ghcr.io/kaitranntt/ccs.');
156
+ }
157
+ }
158
+
159
+ if (require.main === module) {
160
+ try {
161
+ main();
162
+ } catch (error) {
163
+ console.error(`[X] ${error.message}`);
164
+ process.exit(1);
165
+ }
166
+ }
167
+
168
+ module.exports = {
169
+ evaluateDashboardSunset,
170
+ parseStableVersion,
171
+ };
@@ -22,6 +22,7 @@ const slowTests = [
22
22
  'tests/integration/cursor-daemon-lifecycle.test.ts',
23
23
  'tests/integration/logging-request-context.test.ts',
24
24
  'tests/integration/proxy/daemon-lifecycle.test.ts',
25
+ 'tests/integration/web-server/codex-profiles-endpoint.test.ts',
25
26
  'tests/unit/commands/persist-command-handler.test.ts',
26
27
  'tests/unit/hooks/browser-mcp-advanced-interactions.test.ts',
27
28
  'tests/unit/hooks/browser-mcp-downloads-and-files.test.ts',
@@ -16,7 +16,10 @@ const path = require('path');
16
16
  const zlib = require('zlib');
17
17
 
18
18
  const UI_DIR = path.join(__dirname, '../dist/ui');
19
- const MAX_SIZE = 1.5 * 1024 * 1024; // 1.5MB - reasonable for full-featured React dashboard
19
+ // 1.75MB - bumped from 1.5MB when the code editor moved from
20
+ // react-simple-code-editor + prism-react-renderer (~18KB) to CodeMirror 6
21
+ // (~80KB gzipped) to restore native selection/copy in the raw config viewers.
22
+ const MAX_SIZE = 1.75 * 1024 * 1024;
20
23
 
21
24
  function getGzipSize(filePath) {
22
25
  const content = fs.readFileSync(filePath);