harness-mix 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (632) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +14 -0
  3. package/README.md +184 -0
  4. package/Start-Codex.cmd +5 -0
  5. package/config/codex-desktop-compatibility.json +23 -0
  6. package/docs/chatgpt-web-sidebar.md +27 -0
  7. package/docs/harness-management.md +41 -0
  8. package/docs/images/harness-mix-home.png +0 -0
  9. package/docs/images/harness-mix-session.png +0 -0
  10. package/docs/multi-agent-collaboration.md +89 -0
  11. package/docs/native-codex.md +72 -0
  12. package/licenses/codex-host-MIT.txt +21 -0
  13. package/output/native-build/desktop-controller.mjs +1460 -0
  14. package/output/native-build/harness-mix-appx.exe +0 -0
  15. package/output/native-build/harness-mix-shim.exe +0 -0
  16. package/output/native-build/renderer-extension.js +28884 -0
  17. package/package.json +142 -0
  18. package/scripts/acp-capabilities-probe.cjs +100 -0
  19. package/scripts/adapters-test.cjs +17 -0
  20. package/scripts/antigravity-adapter-test.cjs +174 -0
  21. package/scripts/architecture-test.cjs +62 -0
  22. package/scripts/build-native.cjs +46 -0
  23. package/scripts/catalog-test.cjs +25 -0
  24. package/scripts/cdp-eval.cjs +40 -0
  25. package/scripts/cdp-watch.cjs +36 -0
  26. package/scripts/check.cjs +23 -0
  27. package/scripts/codex-adapter-test.cjs +83 -0
  28. package/scripts/collaboration-recovery-test.cjs +91 -0
  29. package/scripts/collaboration-test.cjs +102 -0
  30. package/scripts/collaboration-ui-smoke.cjs +52 -0
  31. package/scripts/concurrency-layers-test.cjs +179 -0
  32. package/scripts/contracts-test.cjs +105 -0
  33. package/scripts/core-concurrency-test.cjs +103 -0
  34. package/scripts/core-replay-test.cjs +179 -0
  35. package/scripts/core-runtime-test.cjs +104 -0
  36. package/scripts/core-services-test.cjs +50 -0
  37. package/scripts/determinism-test.cjs +36 -0
  38. package/scripts/docs-command-test.cjs +49 -0
  39. package/scripts/dsh-adapter-test.cjs +87 -0
  40. package/scripts/dsh-native.cjs +9 -0
  41. package/scripts/dsh-native.cmd +2 -0
  42. package/scripts/e2e-codex.cjs +82 -0
  43. package/scripts/e2e-collaboration.cjs +58 -0
  44. package/scripts/e2e-core-files.cjs +58 -0
  45. package/scripts/e2e-core-fork.cjs +49 -0
  46. package/scripts/e2e-core-resume.cjs +49 -0
  47. package/scripts/e2e-delegate.cjs +38 -0
  48. package/scripts/e2e-dsh.cjs +23 -0
  49. package/scripts/e2e-native-commands.cjs +54 -0
  50. package/scripts/e2e-native-host.cjs +144 -0
  51. package/scripts/e2e-openclaw-image.cjs +59 -0
  52. package/scripts/e2e-openclaw.cjs +21 -0
  53. package/scripts/e2e-pi.cjs +23 -0
  54. package/scripts/e2e-shadow.cjs +52 -0
  55. package/scripts/fixture-capture.cjs +103 -0
  56. package/scripts/git-test.cjs +33 -0
  57. package/scripts/launch-codex.cjs +5 -0
  58. package/scripts/native-compatibility-test.cjs +42 -0
  59. package/scripts/native-config-test.cjs +25 -0
  60. package/scripts/native-file-change-test.cjs +94 -0
  61. package/scripts/native-host.cjs +8 -0
  62. package/scripts/native-images-test.cjs +56 -0
  63. package/scripts/native-protocol-test.cjs +233 -0
  64. package/scripts/native-rollback-test.cjs +46 -0
  65. package/scripts/native-sidebar-test.cjs +88 -0
  66. package/scripts/native-ui-smoke.cjs +94 -0
  67. package/scripts/native-updater-test.cjs +100 -0
  68. package/scripts/native-vendor-adapters-test.cjs +40 -0
  69. package/scripts/openclaw-acp-probe.cjs +39 -0
  70. package/scripts/openclaw-adapter-test.cjs +180 -0
  71. package/scripts/openclaw-models-probe.cjs +13 -0
  72. package/scripts/projector-test.cjs +144 -0
  73. package/scripts/sequence-test.cjs +57 -0
  74. package/scripts/shadow-test.cjs +154 -0
  75. package/scripts/support/legacy-projection.cjs +95 -0
  76. package/scripts/support/legacy-transcript.cjs +48 -0
  77. package/scripts/support/parity-observer.cjs +27 -0
  78. package/scripts/support/shadow-comparator.cjs +62 -0
  79. package/scripts/support/shadow.cjs +114 -0
  80. package/scripts/switch-harness-test.cjs +145 -0
  81. package/scripts/tool-concurrency-regression-test.cjs +118 -0
  82. package/scripts/transcript-test.cjs +24 -0
  83. package/scripts/turn-manager-test.cjs +91 -0
  84. package/scripts/workspace-test.cjs +98 -0
  85. package/src/assets/brand-harness-mix.png +0 -0
  86. package/src/assets/icons/activity-compact.svg +1 -0
  87. package/src/assets/icons/activity-edit.svg +1 -0
  88. package/src/assets/icons/activity-terminal.svg +1 -0
  89. package/src/assets/icons/antigravity-color.svg +1 -0
  90. package/src/assets/icons/claude-color.svg +1 -0
  91. package/src/assets/icons/codex-color.svg +1 -0
  92. package/src/assets/icons/codex-harness.svg +1 -0
  93. package/src/assets/icons/commands.svg +1 -0
  94. package/src/assets/icons/deepseek-color.svg +1 -0
  95. package/src/assets/icons/grok-color.svg +1 -0
  96. package/src/assets/icons/hermes-color.svg +1 -0
  97. package/src/assets/icons/home-chat.svg +1 -0
  98. package/src/assets/icons/home-folder.svg +1 -0
  99. package/src/assets/icons/model-astra.svg +1 -0
  100. package/src/assets/icons/model-claude.svg +1 -0
  101. package/src/assets/icons/model-deepseek.svg +1 -0
  102. package/src/assets/icons/model-gemini.svg +1 -0
  103. package/src/assets/icons/model-hunyuan.svg +1 -0
  104. package/src/assets/icons/model-kimi.svg +1 -0
  105. package/src/assets/icons/model-minimax.svg +1 -0
  106. package/src/assets/icons/model-openai.svg +1 -0
  107. package/src/assets/icons/model-qwen-color.svg +1 -0
  108. package/src/assets/icons/model-xiaomimimo.svg +1 -0
  109. package/src/assets/icons/model-zai.svg +1 -0
  110. package/src/assets/icons/omp-color.svg +1 -0
  111. package/src/assets/icons/openclaw-color.svg +1 -0
  112. package/src/assets/icons/opencode-color.svg +1 -0
  113. package/src/assets/icons/pi.svg +1 -0
  114. package/src/assets/icons/pinumber1_80899.svg +48 -0
  115. package/src/assets/icons/qoder-color.svg +1 -0
  116. package/src/assets/icons/thread-fork.svg +1 -0
  117. package/src/assets/icons/trae-color.svg +1 -0
  118. package/src/assets/icons/workbuddy-color.svg +1 -0
  119. package/src/assets/icons/zcode-color.svg +1 -0
  120. package/src/main/adapters/acp.js +171 -0
  121. package/src/main/adapters/antigravity.js +895 -0
  122. package/src/main/adapters/claude.js +399 -0
  123. package/src/main/adapters/codex-app-server.js +119 -0
  124. package/src/main/adapters/codex.js +547 -0
  125. package/src/main/adapters/dsh-web-host.js +207 -0
  126. package/src/main/adapters/dsh.js +415 -0
  127. package/src/main/adapters/grok.js +161 -0
  128. package/src/main/adapters/hermes.js +24 -0
  129. package/src/main/adapters/index.js +30 -0
  130. package/src/main/adapters/omp.js +12 -0
  131. package/src/main/adapters/openclaw-gateway.js +215 -0
  132. package/src/main/adapters/openclaw.js +337 -0
  133. package/src/main/adapters/opencode-server.js +72 -0
  134. package/src/main/adapters/opencode.js +166 -0
  135. package/src/main/adapters/pi-family.js +315 -0
  136. package/src/main/adapters/pi-usage.js +24 -0
  137. package/src/main/adapters/pi.js +10 -0
  138. package/src/main/adapters/qoder.js +35 -0
  139. package/src/main/adapters/trae.js +19 -0
  140. package/src/main/adapters/workbuddy.js +67 -0
  141. package/src/main/adapters/zcode.js +38 -0
  142. package/src/main/harness-adapter/contract-test.js +53 -0
  143. package/src/main/harness-adapter/contract.js +34 -0
  144. package/src/main/harness-adapter/event-normalizer.js +233 -0
  145. package/src/main/harness-adapter/fixture-recorder.js +56 -0
  146. package/src/main/harness-adapter/index.js +6 -0
  147. package/src/main/harness-adapter/manifest.js +44 -0
  148. package/src/main/host/collaboration-mcp.cjs +35 -0
  149. package/src/main/host/collaboration-pi.mjs +17 -0
  150. package/src/main/host/collaboration-tools.js +16 -0
  151. package/src/main/host/collaboration-worktree.js +82 -0
  152. package/src/main/host/collaboration.js +238 -0
  153. package/src/main/host/core-session.js +81 -0
  154. package/src/main/host/handoff.js +46 -0
  155. package/src/main/host/history-import.js +55 -0
  156. package/src/main/host/jsonl.js +115 -0
  157. package/src/main/host/native-history.js +74 -0
  158. package/src/main/host/runtime.js +927 -0
  159. package/src/main/host/session-history.js +63 -0
  160. package/src/main/host/store.js +42 -0
  161. package/src/main/native/compatibility.js +55 -0
  162. package/src/main/native/config.js +49 -0
  163. package/src/main/native/host.js +108 -0
  164. package/src/main/native/icons.js +101 -0
  165. package/src/main/native/input.js +43 -0
  166. package/src/main/native/launcher.js +100 -0
  167. package/src/main/native/protocol.js +552 -0
  168. package/src/main/native/rs/Cargo.lock +11 -0
  169. package/src/main/native/rs/Cargo.toml +9 -0
  170. package/src/main/native/rs/crates/appx/Cargo.toml +13 -0
  171. package/src/main/native/rs/crates/appx/src/main.rs +309 -0
  172. package/src/main/native/rs/crates/shim/Cargo.toml +10 -0
  173. package/src/main/native/rs/crates/shim/src/main.rs +207 -0
  174. package/src/main/native/thread-list.js +38 -0
  175. package/src/main/native/updater.js +102 -0
  176. package/src/main/native/usage.js +29 -0
  177. package/src/main/protocol-core/capability-manager.js +16 -0
  178. package/src/main/protocol-core/event-router.js +32 -0
  179. package/src/main/protocol-core/file-change-projector.js +45 -0
  180. package/src/main/protocol-core/index.js +8 -0
  181. package/src/main/protocol-core/interaction-router.js +30 -0
  182. package/src/main/protocol-core/projector.js +238 -0
  183. package/src/main/protocol-core/protocol-core.js +132 -0
  184. package/src/main/protocol-core/sequence-validator.js +44 -0
  185. package/src/main/protocol-core/thread-manager.js +50 -0
  186. package/src/main/protocol-core/turn-manager.js +63 -0
  187. package/src/main/shared-contracts/capability.js +35 -0
  188. package/src/main/shared-contracts/event.js +55 -0
  189. package/src/main/shared-contracts/ids.js +12 -0
  190. package/src/main/shared-contracts/index.js +11 -0
  191. package/src/main/shared-contracts/interaction.js +37 -0
  192. package/src/main/shared-contracts/item.js +50 -0
  193. package/src/main/shared-contracts/native-ref.js +24 -0
  194. package/src/main/shared-contracts/thread.js +36 -0
  195. package/src/main/shared-contracts/turn.js +54 -0
  196. package/src/main/workspace/core-review.js +53 -0
  197. package/src/main/workspace/diff.js +27 -0
  198. package/src/main/workspace/file-changes.js +21 -0
  199. package/src/main/workspace/files.js +65 -0
  200. package/src/main/workspace/git.js +73 -0
  201. package/src/main/workspace/ipc.js +50 -0
  202. package/src/main/workspace/review-controller.js +102 -0
  203. package/src/main/workspace/review.js +83 -0
  204. package/src/main/workspace/terminal.js +36 -0
  205. package/src/native-ui/LICENSE +21 -0
  206. package/src/native-ui/README.md +12 -0
  207. package/src/native-ui/desktop-control/dist/cdp-client.d.ts +53 -0
  208. package/src/native-ui/desktop-control/dist/cdp-client.d.ts.map +1 -0
  209. package/src/native-ui/desktop-control/dist/cdp-client.js +258 -0
  210. package/src/native-ui/desktop-control/dist/cdp-client.js.map +1 -0
  211. package/src/native-ui/desktop-control/dist/contract-audit.d.ts +73 -0
  212. package/src/native-ui/desktop-control/dist/contract-audit.d.ts.map +1 -0
  213. package/src/native-ui/desktop-control/dist/contract-audit.js +152 -0
  214. package/src/native-ui/desktop-control/dist/contract-audit.js.map +1 -0
  215. package/src/native-ui/desktop-control/dist/controller-attachment-server.d.ts +10 -0
  216. package/src/native-ui/desktop-control/dist/controller-attachment-server.d.ts.map +1 -0
  217. package/src/native-ui/desktop-control/dist/controller-attachment-server.js +77 -0
  218. package/src/native-ui/desktop-control/dist/controller-attachment-server.js.map +1 -0
  219. package/src/native-ui/desktop-control/dist/index.d.ts +21 -0
  220. package/src/native-ui/desktop-control/dist/index.d.ts.map +1 -0
  221. package/src/native-ui/desktop-control/dist/index.js +14 -0
  222. package/src/native-ui/desktop-control/dist/index.js.map +1 -0
  223. package/src/native-ui/desktop-control/dist/main-process-title-policy.d.ts +24 -0
  224. package/src/native-ui/desktop-control/dist/main-process-title-policy.d.ts.map +1 -0
  225. package/src/native-ui/desktop-control/dist/main-process-title-policy.js +246 -0
  226. package/src/native-ui/desktop-control/dist/main-process-title-policy.js.map +1 -0
  227. package/src/native-ui/desktop-control/dist/production-controller.d.ts +32 -0
  228. package/src/native-ui/desktop-control/dist/production-controller.d.ts.map +1 -0
  229. package/src/native-ui/desktop-control/dist/production-controller.js +291 -0
  230. package/src/native-ui/desktop-control/dist/production-controller.js.map +1 -0
  231. package/src/native-ui/desktop-control/dist/release-main.d.ts +2 -0
  232. package/src/native-ui/desktop-control/dist/release-main.d.ts.map +1 -0
  233. package/src/native-ui/desktop-control/dist/release-main.js +17 -0
  234. package/src/native-ui/desktop-control/dist/release-main.js.map +1 -0
  235. package/src/native-ui/desktop-control/dist/renderer-cdp-control-session.d.ts +49 -0
  236. package/src/native-ui/desktop-control/dist/renderer-cdp-control-session.d.ts.map +1 -0
  237. package/src/native-ui/desktop-control/dist/renderer-cdp-control-session.js +214 -0
  238. package/src/native-ui/desktop-control/dist/renderer-cdp-control-session.js.map +1 -0
  239. package/src/native-ui/desktop-control/dist/renderer-control-session.d.ts +79 -0
  240. package/src/native-ui/desktop-control/dist/renderer-control-session.d.ts.map +1 -0
  241. package/src/native-ui/desktop-control/dist/renderer-control-session.js +366 -0
  242. package/src/native-ui/desktop-control/dist/renderer-control-session.js.map +1 -0
  243. package/src/native-ui/desktop-control/dist/renderer-dom.d.ts +24 -0
  244. package/src/native-ui/desktop-control/dist/renderer-dom.d.ts.map +1 -0
  245. package/src/native-ui/desktop-control/dist/renderer-dom.js +110 -0
  246. package/src/native-ui/desktop-control/dist/renderer-dom.js.map +1 -0
  247. package/src/native-ui/desktop-control/dist/renderer-draft-prewarm-policy.d.ts +19 -0
  248. package/src/native-ui/desktop-control/dist/renderer-draft-prewarm-policy.d.ts.map +1 -0
  249. package/src/native-ui/desktop-control/dist/renderer-draft-prewarm-policy.js +162 -0
  250. package/src/native-ui/desktop-control/dist/renderer-draft-prewarm-policy.js.map +1 -0
  251. package/src/native-ui/desktop-control/dist/renderer-draft-prewarm-runtime.d.ts +38 -0
  252. package/src/native-ui/desktop-control/dist/renderer-draft-prewarm-runtime.d.ts.map +1 -0
  253. package/src/native-ui/desktop-control/dist/renderer-draft-prewarm-runtime.js +633 -0
  254. package/src/native-ui/desktop-control/dist/renderer-draft-prewarm-runtime.js.map +1 -0
  255. package/src/native-ui/desktop-control/dist/tsconfig.tsbuildinfo +1 -0
  256. package/src/native-ui/desktop-control/package.json +22 -0
  257. package/src/native-ui/desktop-control/scripts/build-release.mjs +94 -0
  258. package/src/native-ui/desktop-control/src/cdp-client.ts +347 -0
  259. package/src/native-ui/desktop-control/src/contract-audit.ts +291 -0
  260. package/src/native-ui/desktop-control/src/controller-attachment-server.ts +93 -0
  261. package/src/native-ui/desktop-control/src/index.ts +91 -0
  262. package/src/native-ui/desktop-control/src/main-process-title-policy.ts +334 -0
  263. package/src/native-ui/desktop-control/src/production-controller.ts +344 -0
  264. package/src/native-ui/desktop-control/src/release-main.ts +18 -0
  265. package/src/native-ui/desktop-control/src/renderer-cdp-control-session.ts +358 -0
  266. package/src/native-ui/desktop-control/src/renderer-control-session.ts +595 -0
  267. package/src/native-ui/desktop-control/src/renderer-dom.ts +144 -0
  268. package/src/native-ui/desktop-control/src/renderer-draft-prewarm-policy.ts +209 -0
  269. package/src/native-ui/desktop-control/src/renderer-draft-prewarm-runtime.ts +746 -0
  270. package/src/native-ui/desktop-control/test/cdp-client.test.ts +157 -0
  271. package/src/native-ui/desktop-control/test/contract-audit.test.ts +56 -0
  272. package/src/native-ui/desktop-control/test/controller-attachment-server.test.ts +98 -0
  273. package/src/native-ui/desktop-control/test/index.test.ts +11 -0
  274. package/src/native-ui/desktop-control/test/main-process-title-policy.test.ts +166 -0
  275. package/src/native-ui/desktop-control/test/production-controller.test.ts +389 -0
  276. package/src/native-ui/desktop-control/test/renderer-cdp-control-session.test.ts +205 -0
  277. package/src/native-ui/desktop-control/test/renderer-control-session.test.ts +451 -0
  278. package/src/native-ui/desktop-control/test/renderer-dom.test.ts +62 -0
  279. package/src/native-ui/desktop-control/test/renderer-draft-prewarm-policy.test.ts +998 -0
  280. package/src/native-ui/desktop-control/tsconfig.json +12 -0
  281. package/src/native-ui/renderer-extension/dist/types/agent-group-preference.d.ts +39 -0
  282. package/src/native-ui/renderer-extension/dist/types/agent-group-preference.d.ts.map +1 -0
  283. package/src/native-ui/renderer-extension/dist/types/agent-selection-state.d.ts +83 -0
  284. package/src/native-ui/renderer-extension/dist/types/agent-selection-state.d.ts.map +1 -0
  285. package/src/native-ui/renderer-extension/dist/types/audit-entry.d.ts +2 -0
  286. package/src/native-ui/renderer-extension/dist/types/audit-entry.d.ts.map +1 -0
  287. package/src/native-ui/renderer-extension/dist/types/codex-locale-adapter.d.ts +23 -0
  288. package/src/native-ui/renderer-extension/dist/types/codex-locale-adapter.d.ts.map +1 -0
  289. package/src/native-ui/renderer-extension/dist/types/collaboration-icon.d.ts +2 -0
  290. package/src/native-ui/renderer-extension/dist/types/collaboration-icon.d.ts.map +1 -0
  291. package/src/native-ui/renderer-extension/dist/types/contract-audit.d.ts +37 -0
  292. package/src/native-ui/renderer-extension/dist/types/contract-audit.d.ts.map +1 -0
  293. package/src/native-ui/renderer-extension/dist/types/harness-mix-icons.d.ts +3 -0
  294. package/src/native-ui/renderer-extension/dist/types/harness-mix-icons.d.ts.map +1 -0
  295. package/src/native-ui/renderer-extension/dist/types/harness-mix-settings.d.ts +3 -0
  296. package/src/native-ui/renderer-extension/dist/types/harness-mix-settings.d.ts.map +1 -0
  297. package/src/native-ui/renderer-extension/dist/types/index.d.ts +49 -0
  298. package/src/native-ui/renderer-extension/dist/types/index.d.ts.map +1 -0
  299. package/src/native-ui/renderer-extension/dist/types/install-renderer-binding.d.ts +4 -0
  300. package/src/native-ui/renderer-extension/dist/types/install-renderer-binding.d.ts.map +1 -0
  301. package/src/native-ui/renderer-extension/dist/types/probe-entry.d.ts +2 -0
  302. package/src/native-ui/renderer-extension/dist/types/probe-entry.d.ts.map +1 -0
  303. package/src/native-ui/renderer-extension/dist/types/production-entry.d.ts +9 -0
  304. package/src/native-ui/renderer-extension/dist/types/production-entry.d.ts.map +1 -0
  305. package/src/native-ui/renderer-extension/dist/types/renderer-agent-icon.d.ts +4 -0
  306. package/src/native-ui/renderer-extension/dist/types/renderer-agent-icon.d.ts.map +1 -0
  307. package/src/native-ui/renderer-extension/dist/types/renderer-agent-picker.d.ts +62 -0
  308. package/src/native-ui/renderer-extension/dist/types/renderer-agent-picker.d.ts.map +1 -0
  309. package/src/native-ui/renderer-extension/dist/types/renderer-binding-probe.d.ts +70 -0
  310. package/src/native-ui/renderer-extension/dist/types/renderer-binding-probe.d.ts.map +1 -0
  311. package/src/native-ui/renderer-extension/dist/types/renderer-codex-account-options.d.ts +34 -0
  312. package/src/native-ui/renderer-extension/dist/types/renderer-codex-account-options.d.ts.map +1 -0
  313. package/src/native-ui/renderer-extension/dist/types/renderer-codex-account-state.d.ts +19 -0
  314. package/src/native-ui/renderer-extension/dist/types/renderer-codex-account-state.d.ts.map +1 -0
  315. package/src/native-ui/renderer-extension/dist/types/renderer-composer-dom.d.ts +82 -0
  316. package/src/native-ui/renderer-extension/dist/types/renderer-composer-dom.d.ts.map +1 -0
  317. package/src/native-ui/renderer-extension/dist/types/renderer-credits-control.d.ts +21 -0
  318. package/src/native-ui/renderer-extension/dist/types/renderer-credits-control.d.ts.map +1 -0
  319. package/src/native-ui/renderer-extension/dist/types/renderer-external-steering.d.ts +7 -0
  320. package/src/native-ui/renderer-extension/dist/types/renderer-external-steering.d.ts.map +1 -0
  321. package/src/native-ui/renderer-extension/dist/types/renderer-fork-control.d.ts +34 -0
  322. package/src/native-ui/renderer-extension/dist/types/renderer-fork-control.d.ts.map +1 -0
  323. package/src/native-ui/renderer-extension/dist/types/renderer-harness-command-claim.d.ts +4 -0
  324. package/src/native-ui/renderer-extension/dist/types/renderer-harness-command-claim.d.ts.map +1 -0
  325. package/src/native-ui/renderer-extension/dist/types/renderer-harness-command-control.d.ts +15 -0
  326. package/src/native-ui/renderer-extension/dist/types/renderer-harness-command-control.d.ts.map +1 -0
  327. package/src/native-ui/renderer-extension/dist/types/renderer-harness-localization.d.ts +25 -0
  328. package/src/native-ui/renderer-extension/dist/types/renderer-harness-localization.d.ts.map +1 -0
  329. package/src/native-ui/renderer-extension/dist/types/renderer-harness-mentions.d.ts +23 -0
  330. package/src/native-ui/renderer-extension/dist/types/renderer-harness-mentions.d.ts.map +1 -0
  331. package/src/native-ui/renderer-extension/dist/types/renderer-model-client.d.ts +94 -0
  332. package/src/native-ui/renderer-extension/dist/types/renderer-model-client.d.ts.map +1 -0
  333. package/src/native-ui/renderer-extension/dist/types/renderer-model-picker-positioning.d.ts +22 -0
  334. package/src/native-ui/renderer-extension/dist/types/renderer-model-picker-positioning.d.ts.map +1 -0
  335. package/src/native-ui/renderer-extension/dist/types/renderer-model-picker.d.ts +54 -0
  336. package/src/native-ui/renderer-extension/dist/types/renderer-model-picker.d.ts.map +1 -0
  337. package/src/native-ui/renderer-extension/dist/types/renderer-new-thread-preference.d.ts +18 -0
  338. package/src/native-ui/renderer-extension/dist/types/renderer-new-thread-preference.d.ts.map +1 -0
  339. package/src/native-ui/renderer-extension/dist/types/renderer-permission-mode-picker.d.ts +42 -0
  340. package/src/native-ui/renderer-extension/dist/types/renderer-permission-mode-picker.d.ts.map +1 -0
  341. package/src/native-ui/renderer-extension/dist/types/renderer-permission-mode-preference.d.ts +9 -0
  342. package/src/native-ui/renderer-extension/dist/types/renderer-permission-mode-preference.d.ts.map +1 -0
  343. package/src/native-ui/renderer-extension/dist/types/renderer-request-sender.d.ts +9 -0
  344. package/src/native-ui/renderer-extension/dist/types/renderer-request-sender.d.ts.map +1 -0
  345. package/src/native-ui/renderer-extension/dist/types/renderer-session-import-client.d.ts +12 -0
  346. package/src/native-ui/renderer-extension/dist/types/renderer-session-import-client.d.ts.map +1 -0
  347. package/src/native-ui/renderer-extension/dist/types/renderer-settings-lifecycle.d.ts +18 -0
  348. package/src/native-ui/renderer-extension/dist/types/renderer-settings-lifecycle.d.ts.map +1 -0
  349. package/src/native-ui/renderer-extension/dist/types/renderer-sidebar-agent-icons.d.ts +45 -0
  350. package/src/native-ui/renderer-extension/dist/types/renderer-sidebar-agent-icons.d.ts.map +1 -0
  351. package/src/native-ui/renderer-extension/dist/types/renderer-transcript-dom.d.ts +23 -0
  352. package/src/native-ui/renderer-extension/dist/types/renderer-transcript-dom.d.ts.map +1 -0
  353. package/src/native-ui/renderer-extension/dist/types/renderer-trigger-chip-style.d.ts +3 -0
  354. package/src/native-ui/renderer-extension/dist/types/renderer-trigger-chip-style.d.ts.map +1 -0
  355. package/src/native-ui/renderer-extension/dist/types/renderer-usage-control.d.ts +72 -0
  356. package/src/native-ui/renderer-extension/dist/types/renderer-usage-control.d.ts.map +1 -0
  357. package/src/native-ui/renderer-extension/dist/types/settings/accounts-list.d.ts +24 -0
  358. package/src/native-ui/renderer-extension/dist/types/settings/accounts-list.d.ts.map +1 -0
  359. package/src/native-ui/renderer-extension/dist/types/settings/accounts-page.d.ts +18 -0
  360. package/src/native-ui/renderer-extension/dist/types/settings/accounts-page.d.ts.map +1 -0
  361. package/src/native-ui/renderer-extension/dist/types/settings/accounts-usage.d.ts +27 -0
  362. package/src/native-ui/renderer-extension/dist/types/settings/accounts-usage.d.ts.map +1 -0
  363. package/src/native-ui/renderer-extension/dist/types/settings/connections-page.d.ts +42 -0
  364. package/src/native-ui/renderer-extension/dist/types/settings/connections-page.d.ts.map +1 -0
  365. package/src/native-ui/renderer-extension/dist/types/settings/core.d.ts +38 -0
  366. package/src/native-ui/renderer-extension/dist/types/settings/core.d.ts.map +1 -0
  367. package/src/native-ui/renderer-extension/dist/types/settings/harness-accounts.d.ts +14 -0
  368. package/src/native-ui/renderer-extension/dist/types/settings/harness-accounts.d.ts.map +1 -0
  369. package/src/native-ui/renderer-extension/dist/types/settings/icons.d.ts +6 -0
  370. package/src/native-ui/renderer-extension/dist/types/settings/icons.d.ts.map +1 -0
  371. package/src/native-ui/renderer-extension/dist/types/settings/localization.d.ts +231 -0
  372. package/src/native-ui/renderer-extension/dist/types/settings/localization.d.ts.map +1 -0
  373. package/src/native-ui/renderer-extension/dist/types/settings/pages.d.ts +22 -0
  374. package/src/native-ui/renderer-extension/dist/types/settings/pages.d.ts.map +1 -0
  375. package/src/native-ui/renderer-extension/dist/types/settings/release-notes.d.ts +4 -0
  376. package/src/native-ui/renderer-extension/dist/types/settings/release-notes.d.ts.map +1 -0
  377. package/src/native-ui/renderer-extension/dist/types/settings/session-import-list-controls.d.ts +12 -0
  378. package/src/native-ui/renderer-extension/dist/types/settings/session-import-list-controls.d.ts.map +1 -0
  379. package/src/native-ui/renderer-extension/dist/types/settings/session-import-page.d.ts +8 -0
  380. package/src/native-ui/renderer-extension/dist/types/settings/session-import-page.d.ts.map +1 -0
  381. package/src/native-ui/renderer-extension/dist/types/settings/shell.d.ts +24 -0
  382. package/src/native-ui/renderer-extension/dist/types/settings/shell.d.ts.map +1 -0
  383. package/src/native-ui/renderer-extension/dist/types/settings/trigger.d.ts +45 -0
  384. package/src/native-ui/renderer-extension/dist/types/settings/trigger.d.ts.map +1 -0
  385. package/src/native-ui/renderer-extension/dist/types/settings/update-request.d.ts +6 -0
  386. package/src/native-ui/renderer-extension/dist/types/settings/update-request.d.ts.map +1 -0
  387. package/src/native-ui/renderer-extension/dist/types/tsconfig.tsbuildinfo +1 -0
  388. package/src/native-ui/renderer-extension/dist/types/versioned-renderer-adapter.d.ts +143 -0
  389. package/src/native-ui/renderer-extension/dist/types/versioned-renderer-adapter.d.ts.map +1 -0
  390. package/src/native-ui/renderer-extension/package.json +22 -0
  391. package/src/native-ui/renderer-extension/src/agent-group-preference.ts +174 -0
  392. package/src/native-ui/renderer-extension/src/agent-selection-state.ts +610 -0
  393. package/src/native-ui/renderer-extension/src/assets/README.md +43 -0
  394. package/src/native-ui/renderer-extension/src/assets/antigravity-agent.svg +1 -0
  395. package/src/native-ui/renderer-extension/src/assets/claude-agent.svg +3 -0
  396. package/src/native-ui/renderer-extension/src/assets/codex-agent.png +0 -0
  397. package/src/native-ui/renderer-extension/src/assets/codex-logo-bright.png +0 -0
  398. package/src/native-ui/renderer-extension/src/assets/codex-logo-transparent.png +0 -0
  399. package/src/native-ui/renderer-extension/src/assets/codex-logo.png +0 -0
  400. package/src/native-ui/renderer-extension/src/assets/codexhost-icon.png +0 -0
  401. package/src/native-ui/renderer-extension/src/assets/codexhost-logo-transparent.png +0 -0
  402. package/src/native-ui/renderer-extension/src/assets/codexhost-logo.png +0 -0
  403. package/src/native-ui/renderer-extension/src/assets/codexhost-readme.svg +8 -0
  404. package/src/native-ui/renderer-extension/src/assets/grok-agent.png +0 -0
  405. package/src/native-ui/renderer-extension/src/assets/kiro-agent.svg +11 -0
  406. package/src/native-ui/renderer-extension/src/assets/omp-agent.svg +14 -0
  407. package/src/native-ui/renderer-extension/src/assets/opencode-agent.png +0 -0
  408. package/src/native-ui/renderer-extension/src/assets/pi-agent.svg +4 -0
  409. package/src/native-ui/renderer-extension/src/assets.d.ts +26 -0
  410. package/src/native-ui/renderer-extension/src/audit-entry.ts +5 -0
  411. package/src/native-ui/renderer-extension/src/codex-locale-adapter.ts +321 -0
  412. package/src/native-ui/renderer-extension/src/collaboration-icon.ts +13 -0
  413. package/src/native-ui/renderer-extension/src/contract-audit.ts +102 -0
  414. package/src/native-ui/renderer-extension/src/harness-mix-icons.ts +24 -0
  415. package/src/native-ui/renderer-extension/src/harness-mix-settings.ts +80 -0
  416. package/src/native-ui/renderer-extension/src/index.ts +266 -0
  417. package/src/native-ui/renderer-extension/src/install-renderer-binding.ts +30 -0
  418. package/src/native-ui/renderer-extension/src/probe-entry.ts +4 -0
  419. package/src/native-ui/renderer-extension/src/production-entry.ts +23 -0
  420. package/src/native-ui/renderer-extension/src/renderer-agent-icon.ts +145 -0
  421. package/src/native-ui/renderer-extension/src/renderer-agent-picker.ts +813 -0
  422. package/src/native-ui/renderer-extension/src/renderer-binding-probe.ts +2936 -0
  423. package/src/native-ui/renderer-extension/src/renderer-codex-account-options.ts +281 -0
  424. package/src/native-ui/renderer-extension/src/renderer-codex-account-state.ts +53 -0
  425. package/src/native-ui/renderer-extension/src/renderer-composer-dom.ts +782 -0
  426. package/src/native-ui/renderer-extension/src/renderer-credits-control.ts +500 -0
  427. package/src/native-ui/renderer-extension/src/renderer-external-steering.ts +339 -0
  428. package/src/native-ui/renderer-extension/src/renderer-fork-control.ts +273 -0
  429. package/src/native-ui/renderer-extension/src/renderer-harness-command-claim.ts +64 -0
  430. package/src/native-ui/renderer-extension/src/renderer-harness-command-control.ts +417 -0
  431. package/src/native-ui/renderer-extension/src/renderer-harness-localization.ts +144 -0
  432. package/src/native-ui/renderer-extension/src/renderer-harness-mentions.ts +213 -0
  433. package/src/native-ui/renderer-extension/src/renderer-model-client.ts +567 -0
  434. package/src/native-ui/renderer-extension/src/renderer-model-picker-positioning.ts +65 -0
  435. package/src/native-ui/renderer-extension/src/renderer-model-picker.ts +640 -0
  436. package/src/native-ui/renderer-extension/src/renderer-new-thread-preference.ts +175 -0
  437. package/src/native-ui/renderer-extension/src/renderer-permission-mode-picker.ts +413 -0
  438. package/src/native-ui/renderer-extension/src/renderer-permission-mode-preference.ts +49 -0
  439. package/src/native-ui/renderer-extension/src/renderer-request-sender.ts +43 -0
  440. package/src/native-ui/renderer-extension/src/renderer-session-import-client.ts +68 -0
  441. package/src/native-ui/renderer-extension/src/renderer-settings-lifecycle.ts +239 -0
  442. package/src/native-ui/renderer-extension/src/renderer-sidebar-agent-icons.ts +456 -0
  443. package/src/native-ui/renderer-extension/src/renderer-transcript-dom.ts +47 -0
  444. package/src/native-ui/renderer-extension/src/renderer-trigger-chip-style.ts +52 -0
  445. package/src/native-ui/renderer-extension/src/renderer-usage-control.ts +602 -0
  446. package/src/native-ui/renderer-extension/src/settings/accounts-list.ts +236 -0
  447. package/src/native-ui/renderer-extension/src/settings/accounts-page.ts +585 -0
  448. package/src/native-ui/renderer-extension/src/settings/accounts-quota-interactive.prototype.html +1418 -0
  449. package/src/native-ui/renderer-extension/src/settings/accounts-usage.ts +221 -0
  450. package/src/native-ui/renderer-extension/src/settings/accounts.css +607 -0
  451. package/src/native-ui/renderer-extension/src/settings/connections-page.ts +1354 -0
  452. package/src/native-ui/renderer-extension/src/settings/core.ts +158 -0
  453. package/src/native-ui/renderer-extension/src/settings/harness-accounts.ts +134 -0
  454. package/src/native-ui/renderer-extension/src/settings/icons.ts +141 -0
  455. package/src/native-ui/renderer-extension/src/settings/localization.ts +752 -0
  456. package/src/native-ui/renderer-extension/src/settings/pages.ts +615 -0
  457. package/src/native-ui/renderer-extension/src/settings/release-notes.ts +222 -0
  458. package/src/native-ui/renderer-extension/src/settings/session-import-list-controls.ts +128 -0
  459. package/src/native-ui/renderer-extension/src/settings/session-import-page.ts +461 -0
  460. package/src/native-ui/renderer-extension/src/settings/shell.css +2149 -0
  461. package/src/native-ui/renderer-extension/src/settings/shell.ts +329 -0
  462. package/src/native-ui/renderer-extension/src/settings/trigger.ts +323 -0
  463. package/src/native-ui/renderer-extension/src/settings/update-notes.preview.html +491 -0
  464. package/src/native-ui/renderer-extension/src/settings/update-request.ts +49 -0
  465. package/src/native-ui/renderer-extension/src/settings/windows-update.preview.html +2135 -0
  466. package/src/native-ui/renderer-extension/src/versioned-renderer-adapter.ts +1278 -0
  467. package/src/native-ui/renderer-extension/test/agent-selection-state.test.ts +611 -0
  468. package/src/native-ui/renderer-extension/test/codex-locale-adapter.test.ts +152 -0
  469. package/src/native-ui/renderer-extension/test/contract-audit.test.ts +71 -0
  470. package/src/native-ui/renderer-extension/test/index.test.ts +9 -0
  471. package/src/native-ui/renderer-extension/test/renderer-agent-icon.test.ts +98 -0
  472. package/src/native-ui/renderer-extension/test/renderer-agent-picker.test.ts +226 -0
  473. package/src/native-ui/renderer-extension/test/renderer-binding-probe-host-catalog.test.ts +728 -0
  474. package/src/native-ui/renderer-extension/test/renderer-binding-probe.test.ts +1290 -0
  475. package/src/native-ui/renderer-extension/test/renderer-codex-account-state.test.ts +65 -0
  476. package/src/native-ui/renderer-extension/test/renderer-composer-permissions.test.ts +75 -0
  477. package/src/native-ui/renderer-extension/test/renderer-credits-control.test.ts +70 -0
  478. package/src/native-ui/renderer-extension/test/renderer-external-steering-rpc.test.ts +184 -0
  479. package/src/native-ui/renderer-extension/test/renderer-external-steering.test.ts +279 -0
  480. package/src/native-ui/renderer-extension/test/renderer-fork-control.test.ts +363 -0
  481. package/src/native-ui/renderer-extension/test/renderer-harness-command-claim.test.ts +167 -0
  482. package/src/native-ui/renderer-extension/test/renderer-harness-command-control.test.ts +54 -0
  483. package/src/native-ui/renderer-extension/test/renderer-model-client.test.ts +708 -0
  484. package/src/native-ui/renderer-extension/test/renderer-model-picker.test.ts +302 -0
  485. package/src/native-ui/renderer-extension/test/renderer-native-thread-ownership.test.ts +84 -0
  486. package/src/native-ui/renderer-extension/test/renderer-new-thread-preference.test.ts +81 -0
  487. package/src/native-ui/renderer-extension/test/renderer-permission-mode-picker.test.ts +269 -0
  488. package/src/native-ui/renderer-extension/test/renderer-permission-mode-preference.test.ts +48 -0
  489. package/src/native-ui/renderer-extension/test/renderer-settings-lifecycle.test.ts +156 -0
  490. package/src/native-ui/renderer-extension/test/renderer-sidebar-agent-icons.test.ts +575 -0
  491. package/src/native-ui/renderer-extension/test/renderer-unsupported-methods.test.ts +167 -0
  492. package/src/native-ui/renderer-extension/test/renderer-usage-control.test.ts +96 -0
  493. package/src/native-ui/renderer-extension/test/settings/accounts-usage.test.ts +208 -0
  494. package/src/native-ui/renderer-extension/test/settings/core.test.ts +145 -0
  495. package/src/native-ui/renderer-extension/test/settings/harness-settings.test.ts +88 -0
  496. package/src/native-ui/renderer-extension/test/settings/localization.test.ts +80 -0
  497. package/src/native-ui/renderer-extension/test/settings/pages.test.ts +2000 -0
  498. package/src/native-ui/renderer-extension/test/settings/release-notes.test.ts +163 -0
  499. package/src/native-ui/renderer-extension/test/settings/shell.test.ts +74 -0
  500. package/src/native-ui/renderer-extension/test/settings/trigger.test.ts +270 -0
  501. package/src/native-ui/renderer-extension/test/settings/update-request.test.ts +48 -0
  502. package/src/native-ui/renderer-extension/test/versioned-renderer-adapter.test.ts +682 -0
  503. package/src/native-ui/renderer-extension/tsconfig.json +15 -0
  504. package/src/native-ui/shared-contracts/dist/codex-accounts.d.ts +246 -0
  505. package/src/native-ui/shared-contracts/dist/codex-accounts.d.ts.map +1 -0
  506. package/src/native-ui/shared-contracts/dist/codex-accounts.js +99 -0
  507. package/src/native-ui/shared-contracts/dist/codex-accounts.js.map +1 -0
  508. package/src/native-ui/shared-contracts/dist/deepseek-modern-sessions.d.ts +37 -0
  509. package/src/native-ui/shared-contracts/dist/deepseek-modern-sessions.d.ts.map +1 -0
  510. package/src/native-ui/shared-contracts/dist/deepseek-modern-sessions.js +36 -0
  511. package/src/native-ui/shared-contracts/dist/deepseek-modern-sessions.js.map +1 -0
  512. package/src/native-ui/shared-contracts/dist/errors.d.ts +17 -0
  513. package/src/native-ui/shared-contracts/dist/errors.d.ts.map +1 -0
  514. package/src/native-ui/shared-contracts/dist/errors.js +14 -0
  515. package/src/native-ui/shared-contracts/dist/errors.js.map +1 -0
  516. package/src/native-ui/shared-contracts/dist/external-thread-fork.d.ts +11 -0
  517. package/src/native-ui/shared-contracts/dist/external-thread-fork.d.ts.map +1 -0
  518. package/src/native-ui/shared-contracts/dist/external-thread-fork.js +14 -0
  519. package/src/native-ui/shared-contracts/dist/external-thread-fork.js.map +1 -0
  520. package/src/native-ui/shared-contracts/dist/harness-accounts.d.ts +64 -0
  521. package/src/native-ui/shared-contracts/dist/harness-accounts.d.ts.map +1 -0
  522. package/src/native-ui/shared-contracts/dist/harness-accounts.js +24 -0
  523. package/src/native-ui/shared-contracts/dist/harness-accounts.js.map +1 -0
  524. package/src/native-ui/shared-contracts/dist/harness-commands.d.ts +46 -0
  525. package/src/native-ui/shared-contracts/dist/harness-commands.d.ts.map +1 -0
  526. package/src/native-ui/shared-contracts/dist/harness-commands.js +61 -0
  527. package/src/native-ui/shared-contracts/dist/harness-commands.js.map +1 -0
  528. package/src/native-ui/shared-contracts/dist/harness-models.d.ts +278 -0
  529. package/src/native-ui/shared-contracts/dist/harness-models.d.ts.map +1 -0
  530. package/src/native-ui/shared-contracts/dist/harness-models.js +317 -0
  531. package/src/native-ui/shared-contracts/dist/harness-models.js.map +1 -0
  532. package/src/native-ui/shared-contracts/dist/harness-permission-modes.d.ts +30 -0
  533. package/src/native-ui/shared-contracts/dist/harness-permission-modes.d.ts.map +1 -0
  534. package/src/native-ui/shared-contracts/dist/harness-permission-modes.js +57 -0
  535. package/src/native-ui/shared-contracts/dist/harness-permission-modes.js.map +1 -0
  536. package/src/native-ui/shared-contracts/dist/harness-plugins.d.ts +56 -0
  537. package/src/native-ui/shared-contracts/dist/harness-plugins.d.ts.map +1 -0
  538. package/src/native-ui/shared-contracts/dist/harness-plugins.js +75 -0
  539. package/src/native-ui/shared-contracts/dist/harness-plugins.js.map +1 -0
  540. package/src/native-ui/shared-contracts/dist/harness-route.d.ts +16 -0
  541. package/src/native-ui/shared-contracts/dist/harness-route.d.ts.map +1 -0
  542. package/src/native-ui/shared-contracts/dist/harness-route.js +42 -0
  543. package/src/native-ui/shared-contracts/dist/harness-route.js.map +1 -0
  544. package/src/native-ui/shared-contracts/dist/harness-session-import.d.ts +54 -0
  545. package/src/native-ui/shared-contracts/dist/harness-session-import.d.ts.map +1 -0
  546. package/src/native-ui/shared-contracts/dist/harness-session-import.js +72 -0
  547. package/src/native-ui/shared-contracts/dist/harness-session-import.js.map +1 -0
  548. package/src/native-ui/shared-contracts/dist/ids.d.ts +12 -0
  549. package/src/native-ui/shared-contracts/dist/ids.d.ts.map +1 -0
  550. package/src/native-ui/shared-contracts/dist/ids.js +10 -0
  551. package/src/native-ui/shared-contracts/dist/ids.js.map +1 -0
  552. package/src/native-ui/shared-contracts/dist/index.d.ts +47 -0
  553. package/src/native-ui/shared-contracts/dist/index.d.ts.map +1 -0
  554. package/src/native-ui/shared-contracts/dist/index.js +29 -0
  555. package/src/native-ui/shared-contracts/dist/index.js.map +1 -0
  556. package/src/native-ui/shared-contracts/dist/json-rpc.d.ts +84 -0
  557. package/src/native-ui/shared-contracts/dist/json-rpc.d.ts.map +1 -0
  558. package/src/native-ui/shared-contracts/dist/json-rpc.js +65 -0
  559. package/src/native-ui/shared-contracts/dist/json-rpc.js.map +1 -0
  560. package/src/native-ui/shared-contracts/dist/json-value.d.ts +13 -0
  561. package/src/native-ui/shared-contracts/dist/json-value.d.ts.map +1 -0
  562. package/src/native-ui/shared-contracts/dist/json-value.js +60 -0
  563. package/src/native-ui/shared-contracts/dist/json-value.js.map +1 -0
  564. package/src/native-ui/shared-contracts/dist/native-refs.d.ts +43 -0
  565. package/src/native-ui/shared-contracts/dist/native-refs.d.ts.map +1 -0
  566. package/src/native-ui/shared-contracts/dist/native-refs.js +35 -0
  567. package/src/native-ui/shared-contracts/dist/native-refs.js.map +1 -0
  568. package/src/native-ui/shared-contracts/dist/reasoning-transcript.d.ts +7 -0
  569. package/src/native-ui/shared-contracts/dist/reasoning-transcript.d.ts.map +1 -0
  570. package/src/native-ui/shared-contracts/dist/reasoning-transcript.js +7 -0
  571. package/src/native-ui/shared-contracts/dist/reasoning-transcript.js.map +1 -0
  572. package/src/native-ui/shared-contracts/dist/thread-delegate.d.ts +22 -0
  573. package/src/native-ui/shared-contracts/dist/thread-delegate.d.ts.map +1 -0
  574. package/src/native-ui/shared-contracts/dist/thread-delegate.js +30 -0
  575. package/src/native-ui/shared-contracts/dist/thread-delegate.js.map +1 -0
  576. package/src/native-ui/shared-contracts/dist/thread-harness-switch.d.ts +16 -0
  577. package/src/native-ui/shared-contracts/dist/thread-harness-switch.d.ts.map +1 -0
  578. package/src/native-ui/shared-contracts/dist/thread-harness-switch.js +19 -0
  579. package/src/native-ui/shared-contracts/dist/thread-harness-switch.js.map +1 -0
  580. package/src/native-ui/shared-contracts/dist/thread-usage.d.ts +106 -0
  581. package/src/native-ui/shared-contracts/dist/thread-usage.d.ts.map +1 -0
  582. package/src/native-ui/shared-contracts/dist/thread-usage.js +103 -0
  583. package/src/native-ui/shared-contracts/dist/thread-usage.js.map +1 -0
  584. package/src/native-ui/shared-contracts/dist/tsconfig.tsbuildinfo +1 -0
  585. package/src/native-ui/shared-contracts/dist/updates.d.ts +128 -0
  586. package/src/native-ui/shared-contracts/dist/updates.d.ts.map +1 -0
  587. package/src/native-ui/shared-contracts/dist/updates.js +58 -0
  588. package/src/native-ui/shared-contracts/dist/updates.js.map +1 -0
  589. package/src/native-ui/shared-contracts/dist/version.d.ts +2 -0
  590. package/src/native-ui/shared-contracts/dist/version.d.ts.map +1 -0
  591. package/src/native-ui/shared-contracts/dist/version.js +2 -0
  592. package/src/native-ui/shared-contracts/dist/version.js.map +1 -0
  593. package/src/native-ui/shared-contracts/package.json +25 -0
  594. package/src/native-ui/shared-contracts/src/codex-accounts.ts +140 -0
  595. package/src/native-ui/shared-contracts/src/deepseek-modern-sessions.ts +67 -0
  596. package/src/native-ui/shared-contracts/src/errors.ts +25 -0
  597. package/src/native-ui/shared-contracts/src/external-thread-fork.ts +20 -0
  598. package/src/native-ui/shared-contracts/src/harness-accounts.ts +29 -0
  599. package/src/native-ui/shared-contracts/src/harness-commands.ts +81 -0
  600. package/src/native-ui/shared-contracts/src/harness-models.ts +401 -0
  601. package/src/native-ui/shared-contracts/src/harness-permission-modes.ts +73 -0
  602. package/src/native-ui/shared-contracts/src/harness-plugins.ts +96 -0
  603. package/src/native-ui/shared-contracts/src/harness-route.ts +47 -0
  604. package/src/native-ui/shared-contracts/src/harness-session-import.ts +90 -0
  605. package/src/native-ui/shared-contracts/src/ids.ts +20 -0
  606. package/src/native-ui/shared-contracts/src/index.ts +320 -0
  607. package/src/native-ui/shared-contracts/src/json-rpc.ts +80 -0
  608. package/src/native-ui/shared-contracts/src/json-value.ts +78 -0
  609. package/src/native-ui/shared-contracts/src/native-refs.ts +58 -0
  610. package/src/native-ui/shared-contracts/src/reasoning-transcript.ts +6 -0
  611. package/src/native-ui/shared-contracts/src/thread-delegate.ts +40 -0
  612. package/src/native-ui/shared-contracts/src/thread-harness-switch.ts +25 -0
  613. package/src/native-ui/shared-contracts/src/thread-usage.ts +126 -0
  614. package/src/native-ui/shared-contracts/src/updates.ts +78 -0
  615. package/src/native-ui/shared-contracts/src/version.ts +1 -0
  616. package/src/native-ui/shared-contracts/test/browser-bundle.test.ts +36 -0
  617. package/src/native-ui/shared-contracts/test/deepseek-modern-sessions.test.ts +120 -0
  618. package/src/native-ui/shared-contracts/test/errors.test.ts +72 -0
  619. package/src/native-ui/shared-contracts/test/harness-commands.test.ts +64 -0
  620. package/src/native-ui/shared-contracts/test/harness-models.test.ts +390 -0
  621. package/src/native-ui/shared-contracts/test/harness-permission-modes.test.ts +134 -0
  622. package/src/native-ui/shared-contracts/test/harness-plugins.test.ts +113 -0
  623. package/src/native-ui/shared-contracts/test/harness-session-import.test.ts +117 -0
  624. package/src/native-ui/shared-contracts/test/ids.test.ts +69 -0
  625. package/src/native-ui/shared-contracts/test/index.test.ts +80 -0
  626. package/src/native-ui/shared-contracts/test/json-rpc.test.ts +177 -0
  627. package/src/native-ui/shared-contracts/test/json-value.test.ts +62 -0
  628. package/src/native-ui/shared-contracts/test/native-refs.test.ts +95 -0
  629. package/src/native-ui/shared-contracts/test/thread-usage.test.ts +115 -0
  630. package/src/native-ui/shared-contracts/test/updates.test.ts +120 -0
  631. package/src/native-ui/shared-contracts/tsconfig.json +10 -0
  632. package/src/tsconfig.base.json +19 -0
@@ -0,0 +1,1354 @@
1
+ import type { CodexhostError, HarnessInspection } from "@codexhost/shared-contracts";
2
+
3
+ import {
4
+ getSharedAgentGroupPreferenceStore,
5
+ type AgentGroupPreferenceStore,
6
+ type AgentGroupSection,
7
+ } from "../agent-group-preference.js";
8
+ import type { ExternalRendererAgent, RendererAgentAvailability } from "../agent-selection-state.js";
9
+ import {
10
+ readNewThreadExternalConfigurationPreference,
11
+ writeNewThreadExternalConfigurationPreference,
12
+ } from "../renderer-new-thread-preference.js";
13
+ import { createRendererAgentIcon, RENDERER_AGENT_LABELS } from "../renderer-agent-icon.js";
14
+ import type { RendererAdapterStatus } from "../versioned-renderer-adapter.js";
15
+ import type { RendererSettingsPageDefinition, RendererSettingsPageMountContext } from "./core.js";
16
+ import { createRendererSettingsIcon } from "./icons.js";
17
+ import type { RendererSettingsMessages } from "./localization.js";
18
+
19
+ export const CODEXHOST_GITHUB_ISSUES_NEW_URL =
20
+ "https://github.com/BytePioneer-AI/codex-host/issues/new";
21
+
22
+ export const HARNESS_INSTALL_COMMANDS: Readonly<Record<ExternalRendererAgent, { command: string }>> = Object.freeze({
23
+ qoder: { command: "npm install -g @qoder-ai/qodercli" },
24
+ workbuddy: { command: "npm install -g @tencent/codebuddy" },
25
+ zcode: { command: "pip install zcode-cli" },
26
+ trae: { command: "npm install -g traecli" },
27
+ codex: { command: "npm install -g @openai/codex" },
28
+ pi: { command: "npm install -g @mariozechner/pi-coding-agent" },
29
+ "claude-code": { command: "npm install -g @anthropic-ai/claude-code" },
30
+ "deepseek-harness": { command: "pip install deepseek-harness" },
31
+ opencode: { command: "npm install -g opencode-ai" },
32
+ grok: { command: "npm install -g @xai/grok-cli" },
33
+ omp: { command: "npm install -g @oh-my-prompt/omp" },
34
+ antigravity: { command: "npm install -g @google/antigravity-cli" },
35
+ "kiro-cli": { command: "npm install -g kiro-cli" },
36
+ openclaw: { command: "npm install -g openclaw" },
37
+ hermes: { command: "pip install hermes-agent" },
38
+ "codex-harness": { command: "npm install -g @openai/codex" },
39
+ });
40
+
41
+ const HARNESS_INSTALL_URLS: Readonly<Record<ExternalRendererAgent, string>> = Object.freeze({
42
+ pi: "https://pi.dev/",
43
+ "claude-code": "https://code.claude.com/docs/en/quickstart",
44
+ "deepseek-harness": "https://deepseek-harness.github.io/deepseek-harness/",
45
+ opencode: "https://opencode.ai/docs/",
46
+ grok: "https://grok.com/",
47
+ omp: "https://github.com/can1357/oh-my-pi",
48
+ antigravity: "https://antigravity.google/product/antigravity-cli",
49
+ "kiro-cli": "https://kiro.dev/docs/cli/",
50
+ openclaw: "https://docs.openclaw.ai/",
51
+ hermes: "https://hermes-agent.nousresearch.com/",
52
+ qoder: "https://qoder.com/",
53
+ workbuddy: "https://workbuddy.ai/",
54
+ zcode: "https://zcode.z.ai/",
55
+ trae: "https://www.trae.ai/",
56
+ 'codex-harness': 'https://developers.openai.com/codex/',
57
+ });
58
+
59
+ export interface RendererConnectionAgentSnapshot {
60
+ readonly agent: ExternalRendererAgent;
61
+ readonly availability: RendererAgentAvailability;
62
+ readonly error: CodexhostError | null;
63
+ readonly webUiAvailable?: true;
64
+ }
65
+
66
+ export interface RendererConnectionHostSnapshot {
67
+ readonly hostId: string;
68
+ readonly active: boolean;
69
+ readonly agents: readonly RendererConnectionAgentSnapshot[];
70
+ }
71
+
72
+ export interface RendererConnectionSnapshot {
73
+ readonly adapter: RendererAdapterStatus;
74
+ readonly hosts: readonly RendererConnectionHostSnapshot[];
75
+ }
76
+
77
+ export interface RendererConnectionDiagnostics {
78
+ snapshot(): RendererConnectionSnapshot;
79
+ refresh(): Promise<void>;
80
+ openWebUi?(hostId: string, agent: ExternalRendererAgent): Promise<void>;
81
+ inspectHarness?(hostId: string, agent: ExternalRendererAgent): Promise<HarnessInspection>;
82
+ installHarness?(hostId: string, agent: ExternalRendererAgent): Promise<{ success: boolean; command?: string; stdout?: string; stderr?: string; error?: string }>;
83
+ subscribe(listener: () => void): () => void;
84
+ }
85
+
86
+ type ConnectionAvailability = RendererAgentAvailability | RendererAdapterStatus["state"];
87
+ type ConnectionTone = "ready" | "checking" | "setup" | "failed";
88
+
89
+ interface ConnectionListItem {
90
+ readonly key: string;
91
+ readonly name: string;
92
+ readonly availability: ConnectionAvailability;
93
+ readonly error: CodexhostError | null;
94
+ readonly agentSnapshot?: RendererConnectionAgentSnapshot;
95
+ readonly openWebUi?: () => Promise<void>;
96
+ }
97
+
98
+ function connectionStatusLabel(
99
+ availability: ConnectionAvailability,
100
+ messages: RendererSettingsMessages,
101
+ hasError = false,
102
+ ): string {
103
+ if (hasError && availability !== "notInstalled") return messages.connectionStatusError;
104
+ if (availability === "ready") return messages.connectionStatusReady;
105
+ if (availability === "checking") return messages.connectionStatusChecking;
106
+ if (availability === "notInstalled") return messages.connectionStatusNotInstalled;
107
+ if (availability === "unavailable" || availability === "error") {
108
+ return availability === "error"
109
+ ? messages.connectionStatusError
110
+ : messages.connectionStatusUnavailable;
111
+ }
112
+ return availability === "installing"
113
+ ? messages.connectionStatusInstalling
114
+ : messages.connectionStatusUnsupported;
115
+ }
116
+
117
+ function connectionStatusTone(
118
+ availability: ConnectionAvailability,
119
+ hasError = false,
120
+ ): ConnectionTone {
121
+ if (hasError && availability !== "notInstalled") return "failed";
122
+ if (availability === "ready") return "ready";
123
+ if (availability === "checking" || availability === "installing") return "checking";
124
+ if (availability === "notInstalled") return "setup";
125
+ return "failed";
126
+ }
127
+
128
+ function diagnosticText(
129
+ hostId: string,
130
+ item: Pick<ConnectionListItem, "name" | "availability" | "error">,
131
+ ): string {
132
+ const error = item.error;
133
+ return [
134
+ "codexhost connection diagnostics",
135
+ `host: ${hostId}`,
136
+ `agent: ${item.name}`,
137
+ `status: ${item.availability}`,
138
+ ...(error
139
+ ? [
140
+ `error.code: ${error.code}`,
141
+ `error.message: ${error.message}`,
142
+ `retryable: ${error.retryable}`,
143
+ ...(error.stage ? [`stage: ${error.stage}`] : []),
144
+ ...(error.durationMs !== undefined ? [`durationMs: ${error.durationMs}`] : []),
145
+ ...(error.diagnostic ? [`diagnostic: ${error.diagnostic}`] : []),
146
+ ...(error.stderrTail ? [`stderr:\n${error.stderrTail}`] : []),
147
+ ]
148
+ : []),
149
+ ].join("\n");
150
+ }
151
+
152
+ function detailLine(document: Document, label: string, value: string): HTMLElement {
153
+ const line = document.createElement("div");
154
+ line.className = "settings-connection-detail-line";
155
+ const name = document.createElement("span");
156
+ name.textContent = label;
157
+ const content = document.createElement("code");
158
+ content.textContent = value;
159
+ line.append(name, content);
160
+ return line;
161
+ }
162
+
163
+ function setCopyButtonLabel(button: HTMLButtonElement, label: string): void {
164
+ button.replaceChildren(createRendererSettingsIcon("copy", 16), label);
165
+ }
166
+
167
+ function showCopyButtonFeedback(
168
+ button: HTMLButtonElement,
169
+ label: string,
170
+ restoreLabel: string,
171
+ ): void {
172
+ setCopyButtonLabel(button, label);
173
+ button.ownerDocument.defaultView?.setTimeout(() => {
174
+ setCopyButtonLabel(button, restoreLabel);
175
+ }, 2_000);
176
+ }
177
+
178
+ function copyDiagnosticsToClipboard(
179
+ document: Document,
180
+ button: HTMLButtonElement,
181
+ report: string,
182
+ messages: RendererSettingsMessages,
183
+ restoreLabel: string,
184
+ ): void {
185
+ const clipboard = document.defaultView?.navigator.clipboard;
186
+ if (!clipboard) {
187
+ showCopyButtonFeedback(button, messages.connectionCopyFailed, restoreLabel);
188
+ return;
189
+ }
190
+ void clipboard.writeText(report).then(
191
+ () => showCopyButtonFeedback(button, messages.connectionCopied, restoreLabel),
192
+ () => showCopyButtonFeedback(button, messages.connectionCopyFailed, restoreLabel),
193
+ );
194
+ }
195
+
196
+ function connectionHostName(hostId: string, messages: RendererSettingsMessages): string {
197
+ if (hostId === "local") return messages.connectionLocalHost;
198
+ const separator = hostId.lastIndexOf(":");
199
+ const encodedName = separator >= 0 ? hostId.slice(separator + 1) : hostId;
200
+ try {
201
+ return decodeURIComponent(encodedName);
202
+ } catch {
203
+ return encodedName;
204
+ }
205
+ }
206
+
207
+ function createHostScrollButton(
208
+ document: Document,
209
+ direction: "left" | "right",
210
+ messages: RendererSettingsMessages,
211
+ ): HTMLButtonElement {
212
+ const button = document.createElement("button");
213
+ button.type = "button";
214
+ button.className = "settings-connection-host-scroll";
215
+ button.dataset.connectionHostScroll = direction;
216
+ const label =
217
+ direction === "left" ? messages.connectionHostsScrollLeft : messages.connectionHostsScrollRight;
218
+ button.setAttribute("aria-label", label);
219
+ button.title = label;
220
+ button.append(
221
+ createRendererSettingsIcon(direction === "left" ? "chevron-left" : "chevron-right", 16),
222
+ );
223
+ return button;
224
+ }
225
+
226
+ function configureHostScroller(
227
+ document: Document,
228
+ strip: HTMLElement,
229
+ tabs: HTMLElement,
230
+ left: HTMLButtonElement,
231
+ right: HTMLButtonElement,
232
+ ): () => void {
233
+ const maxScrollLeft = (): number =>
234
+ Math.max(0, (tabs.scrollWidth || 0) - (tabs.clientWidth || 0));
235
+ const updateButtons = (): void => {
236
+ const maximum = maxScrollLeft();
237
+ strip.dataset.connectionHostOverflow = String(maximum > 1);
238
+ left.disabled = tabs.scrollLeft <= 1;
239
+ right.disabled = maximum <= 1 || tabs.scrollLeft >= maximum - 1;
240
+ };
241
+ const scroll = (direction: -1 | 1): void => {
242
+ const distance = Math.max(180, Math.round((tabs.clientWidth || 250) * 0.72));
243
+ if (typeof tabs.scrollBy === "function") {
244
+ tabs.scrollBy({ left: direction * distance, behavior: "smooth" });
245
+ } else {
246
+ tabs.scrollLeft += direction * distance;
247
+ updateButtons();
248
+ }
249
+ };
250
+ const onLeft = (): void => scroll(-1);
251
+ const onRight = (): void => scroll(1);
252
+ const onWheel = (event: WheelEvent): void => {
253
+ const delta = Math.abs(event.deltaX) > Math.abs(event.deltaY) ? event.deltaX : event.deltaY;
254
+ const maximum = maxScrollLeft();
255
+ const canScroll = delta < 0 ? tabs.scrollLeft > 1 : tabs.scrollLeft < maximum - 1;
256
+ if (!delta || maximum <= 1 || !canScroll) return;
257
+ event.preventDefault();
258
+ tabs.scrollLeft += delta;
259
+ };
260
+ left.addEventListener("click", onLeft);
261
+ right.addEventListener("click", onRight);
262
+ tabs.addEventListener("scroll", updateButtons, { passive: true });
263
+ tabs.addEventListener("wheel", onWheel, { passive: false });
264
+ const ownerWindow = document.defaultView;
265
+ ownerWindow?.addEventListener("resize", updateButtons);
266
+ ownerWindow?.setTimeout(updateButtons, 0);
267
+ updateButtons();
268
+ return () => {
269
+ left.removeEventListener("click", onLeft);
270
+ right.removeEventListener("click", onRight);
271
+ tabs.removeEventListener("scroll", updateButtons);
272
+ tabs.removeEventListener("wheel", onWheel);
273
+ ownerWindow?.removeEventListener("resize", updateButtons);
274
+ };
275
+ }
276
+
277
+ function createConnectionIdentityIcon(
278
+ document: Document,
279
+ item: ConnectionListItem,
280
+ size: number,
281
+ ): HTMLElement {
282
+ const container = document.createElement("span");
283
+ container.className = item.agentSnapshot
284
+ ? "settings-connection-row__mark settings-connection-row__mark--logo"
285
+ : "settings-connection-row__mark";
286
+ container.setAttribute("aria-hidden", "true");
287
+ if (item.agentSnapshot) {
288
+ container.append(createRendererAgentIcon(item.agentSnapshot.agent, size, document));
289
+ } else {
290
+ container.textContent = "CH";
291
+ }
292
+ return container;
293
+ }
294
+
295
+ interface ConnectionRowGroupController {
296
+ readonly section: AgentGroupSection;
297
+ readonly moveLabel: string;
298
+ readonly dragHandleTitle: string;
299
+ toggleSection(): void;
300
+ onDragStart(event: DragEvent): void;
301
+ onDragOver(event: DragEvent): void;
302
+ onDragLeave(event: DragEvent): void;
303
+ onDrop(event: DragEvent): void;
304
+ onDragEnd(event: DragEvent): void;
305
+ }
306
+
307
+ function createConnectionRow(
308
+ document: Document,
309
+ item: ConnectionListItem,
310
+ messages: RendererSettingsMessages,
311
+ selected: boolean,
312
+ select: () => void,
313
+ group: ConnectionRowGroupController | null = null,
314
+ ): HTMLElement {
315
+ const row = document.createElement("div");
316
+ row.className = "settings-connection-row";
317
+ row.dataset.connectionItem = item.key;
318
+ row.dataset.connectionSelected = String(selected);
319
+ row.tabIndex = selected ? 0 : -1;
320
+ row.setAttribute("role", "row");
321
+
322
+ const identity = document.createElement("div");
323
+ identity.className = "settings-connection-row__identity";
324
+ identity.setAttribute("role", "cell");
325
+ if (group) {
326
+ const handle = document.createElement("span");
327
+ handle.className = "settings-connection-row__handle";
328
+ handle.setAttribute("aria-hidden", "true");
329
+ handle.title = group.dragHandleTitle;
330
+ handle.append(createRendererSettingsIcon("grip-vertical", 15));
331
+ identity.append(handle);
332
+ }
333
+ const label = document.createElement("strong");
334
+ label.textContent = item.name;
335
+ identity.append(createConnectionIdentityIcon(document, item, 19), label);
336
+
337
+ const status = document.createElement("span");
338
+ status.className = "settings-connection-row__status";
339
+ status.dataset.connectionTone = connectionStatusTone(item.availability, item.error !== null);
340
+ status.setAttribute("role", "cell");
341
+ status.textContent = connectionStatusLabel(item.availability, messages, item.error !== null);
342
+
343
+ const action = document.createElement("div");
344
+ action.className = "settings-connection-row__action";
345
+ action.setAttribute("role", "cell");
346
+ if (item.agentSnapshot?.availability === "notInstalled") {
347
+ const install = document.createElement("a");
348
+ install.className = "settings-connection-install-link";
349
+ install.href = HARNESS_INSTALL_URLS[item.agentSnapshot.agent];
350
+ install.target = "_blank";
351
+ install.rel = "noopener noreferrer";
352
+ install.setAttribute("aria-label", `${messages.connectionOpenInstallation}: ${item.name}`);
353
+ install.title = messages.connectionOpenInstallation;
354
+ install.append(createRendererSettingsIcon("download", 17));
355
+ action.append(install);
356
+ } else if (item.error) {
357
+ const viewError = document.createElement("button");
358
+ viewError.type = "button";
359
+ viewError.className = "settings-connection-view-error";
360
+ viewError.textContent = messages.connectionViewError;
361
+ viewError.addEventListener("click", (event) => {
362
+ event.stopPropagation();
363
+ select();
364
+ });
365
+ action.append(viewError);
366
+ }
367
+ if (group) {
368
+ const toggle = document.createElement("button");
369
+ toggle.type = "button";
370
+ toggle.className = "settings-connection-row__group-toggle";
371
+ toggle.title = group.moveLabel;
372
+ toggle.setAttribute("aria-label", group.moveLabel);
373
+ toggle.append(
374
+ createRendererSettingsIcon(group.section === "main" ? "chevron-down" : "chevron-up", 15),
375
+ );
376
+ toggle.addEventListener("click", (event) => {
377
+ event.stopPropagation();
378
+ group.toggleSection();
379
+ });
380
+ action.append(toggle);
381
+ }
382
+
383
+ row.addEventListener("click", (event) => {
384
+ const target = event.target as Element | null;
385
+ if (target?.closest?.("a")) return;
386
+ select();
387
+ });
388
+ row.addEventListener("keydown", (event) => {
389
+ if (event.key !== "Enter" && event.key !== " ") return;
390
+ event.preventDefault();
391
+ select();
392
+ });
393
+ if (group) {
394
+ row.draggable = true;
395
+ row.dataset.connectionGroupSection = group.section;
396
+ row.addEventListener("dragstart", group.onDragStart);
397
+ row.addEventListener("dragover", group.onDragOver);
398
+ row.addEventListener("dragleave", group.onDragLeave);
399
+ row.addEventListener("drop", group.onDrop);
400
+ row.addEventListener("dragend", group.onDragEnd);
401
+ }
402
+ row.append(identity, status, action);
403
+ return row;
404
+ }
405
+
406
+ function createInspectorHeader(
407
+ document: Document,
408
+ item: ConnectionListItem,
409
+ messages: RendererSettingsMessages,
410
+ ): HTMLElement {
411
+ const header = document.createElement("header");
412
+ header.className = "settings-connection-inspector__header";
413
+ const identity = document.createElement("div");
414
+ identity.className = "settings-connection-inspector__identity";
415
+ const title = document.createElement("strong");
416
+ title.textContent = item.name;
417
+ identity.append(createConnectionIdentityIcon(document, item, 20), title);
418
+ const status = document.createElement("span");
419
+ status.className = "settings-connection-row__status";
420
+ status.dataset.connectionTone = connectionStatusTone(item.availability, item.error !== null);
421
+ status.textContent = connectionStatusLabel(item.availability, messages, item.error !== null);
422
+ header.append(identity, status);
423
+ return header;
424
+ }
425
+
426
+ function renderOneClickInstallSection(
427
+ document: Document,
428
+ container: HTMLElement,
429
+ agent: ExternalRendererAgent,
430
+ name: string,
431
+ hostId: string,
432
+ messages: RendererSettingsMessages,
433
+ diagnostics: RendererConnectionDiagnostics | null,
434
+ ): void {
435
+ const section = document.createElement("div");
436
+ section.className = "settings-connection-install-callout";
437
+
438
+ const head = document.createElement("div");
439
+ head.className = "settings-connection-install-head";
440
+ const icon = document.createElement("span");
441
+ icon.className = "settings-connection-install-callout__icon";
442
+ icon.append(createRendererSettingsIcon("download", 18));
443
+ const copy = document.createElement("div");
444
+ const title = document.createElement("strong");
445
+ title.textContent = `${messages.connectionInstall} ${name}`;
446
+ const description = document.createElement("p");
447
+ description.textContent = messages.connectionInstallDescription;
448
+ copy.append(title, description);
449
+ head.append(icon, copy);
450
+
451
+ const commandInfo = HARNESS_INSTALL_COMMANDS[agent];
452
+ const commandBox = document.createElement("div");
453
+ commandBox.className = "settings-install-command-box";
454
+ const commandLabel = document.createElement("span");
455
+ commandLabel.className = "settings-install-command-label";
456
+ commandLabel.textContent = messages.installCommandLabel;
457
+ const commandRow = document.createElement("div");
458
+ commandRow.className = "settings-install-command-row";
459
+ const code = document.createElement("code");
460
+ code.textContent = commandInfo?.command ?? `npm install -g ${agent}`;
461
+ commandRow.append(code);
462
+ commandBox.append(commandLabel, commandRow);
463
+
464
+ const actions = document.createElement("div");
465
+ actions.className = "settings-install-actions";
466
+
467
+ const installBtn = document.createElement("button");
468
+ installBtn.type = "button";
469
+ installBtn.className = "settings-command-button";
470
+ installBtn.append(createRendererSettingsIcon("download", 15), messages.oneClickInstall);
471
+
472
+ const copyBtn = document.createElement("button");
473
+ copyBtn.type = "button";
474
+ copyBtn.className = "settings-command-button settings-command-button--secondary";
475
+ copyBtn.append(createRendererSettingsIcon("copy", 15), messages.copyInstallCommand);
476
+
477
+ const downloadLink = document.createElement("a");
478
+ downloadLink.className = "settings-command-button settings-command-button--secondary";
479
+ downloadLink.href = HARNESS_INSTALL_URLS[agent];
480
+ downloadLink.target = "_blank";
481
+ downloadLink.rel = "noopener noreferrer";
482
+ downloadLink.append(createRendererSettingsIcon("external-link", 15), messages.officialDownload);
483
+
484
+ const refreshBtn = document.createElement("button");
485
+ refreshBtn.type = "button";
486
+ refreshBtn.className = "settings-command-button settings-command-button--secondary";
487
+ refreshBtn.append(createRendererSettingsIcon("diagnose", 15), messages.refreshDetection);
488
+
489
+ const feedback = document.createElement("div");
490
+ feedback.className = "settings-install-feedback";
491
+
492
+ copyBtn.addEventListener("click", () => {
493
+ const text = commandInfo?.command ?? `npm install -g ${agent}`;
494
+ const clipboard = document.defaultView?.navigator?.clipboard;
495
+ if (clipboard) {
496
+ void clipboard.writeText(text).then(() => {
497
+ copyBtn.textContent = messages.installCommandCopied;
498
+ document.defaultView?.setTimeout(() => {
499
+ copyBtn.replaceChildren(createRendererSettingsIcon("copy", 15), messages.copyInstallCommand);
500
+ }, 2000);
501
+ });
502
+ }
503
+ });
504
+
505
+ refreshBtn.addEventListener("click", () => {
506
+ void diagnostics?.refresh();
507
+ });
508
+
509
+ installBtn.addEventListener("click", () => {
510
+ if (installBtn.disabled) return;
511
+ installBtn.disabled = true;
512
+ installBtn.replaceChildren(createRendererSettingsIcon("download", 15), messages.oneClickInstalling);
513
+ feedback.textContent = "";
514
+ feedback.className = "settings-install-feedback";
515
+
516
+ const run = async () => {
517
+ if (!diagnostics?.installHarness) {
518
+ const text = commandInfo?.command ?? `npm install -g ${agent}`;
519
+ await document.defaultView?.navigator?.clipboard?.writeText(text);
520
+ feedback.className = "settings-install-feedback settings-feedback-warning";
521
+ feedback.textContent = messages.oneClickInstallFailed;
522
+ installBtn.disabled = false;
523
+ installBtn.replaceChildren(createRendererSettingsIcon("download", 15), messages.oneClickInstall);
524
+ return;
525
+ }
526
+ try {
527
+ const result = await diagnostics.installHarness(hostId, agent);
528
+ if (result.success) {
529
+ feedback.className = "settings-install-feedback settings-feedback-success";
530
+ feedback.textContent = messages.oneClickInstallSuccess;
531
+ installBtn.replaceChildren(createRendererSettingsIcon("check", 15), messages.oneClickInstallSuccess);
532
+ document.defaultView?.setTimeout(() => {
533
+ void diagnostics.refresh();
534
+ }, 1000);
535
+ } else {
536
+ feedback.className = "settings-install-feedback settings-feedback-error";
537
+ feedback.textContent = `${messages.oneClickInstallFailed} ${result.error ?? ""}`;
538
+ installBtn.disabled = false;
539
+ installBtn.replaceChildren(createRendererSettingsIcon("download", 15), messages.oneClickInstall);
540
+ }
541
+ } catch (err: unknown) {
542
+ feedback.className = "settings-install-feedback settings-feedback-error";
543
+ feedback.textContent = `${messages.oneClickInstallFailed} ${err instanceof Error ? err.message : String(err)}`;
544
+ installBtn.disabled = false;
545
+ installBtn.replaceChildren(createRendererSettingsIcon("download", 15), messages.oneClickInstall);
546
+ }
547
+ };
548
+ void run();
549
+ });
550
+
551
+ actions.append(installBtn, copyBtn, downloadLink, refreshBtn);
552
+ section.append(head, commandBox, actions, feedback);
553
+ container.append(section);
554
+ }
555
+
556
+ function renderModelConfigurationSection(
557
+ document: Document,
558
+ container: HTMLElement,
559
+ agent: ExternalRendererAgent,
560
+ hostId: string,
561
+ messages: RendererSettingsMessages,
562
+ diagnostics: RendererConnectionDiagnostics | null,
563
+ ): void {
564
+ const card = document.createElement("div");
565
+ card.className = "settings-model-config-panel";
566
+
567
+ const cardHead = document.createElement("div");
568
+ cardHead.className = "settings-model-config-head";
569
+ const title = document.createElement("strong");
570
+ title.className = "settings-model-config-title";
571
+ title.textContent = messages.modelConfigurationTitle;
572
+ const description = document.createElement("p");
573
+ description.className = "settings-model-config-description";
574
+ description.textContent = messages.modelConfigurationDescription;
575
+ cardHead.append(title, description);
576
+ card.append(cardHead);
577
+
578
+ const loading = document.createElement("div");
579
+ loading.className = "settings-model-config-loading";
580
+ loading.textContent = messages.loadingModels;
581
+ card.append(loading);
582
+ container.append(card);
583
+
584
+ if (!diagnostics?.inspectHarness) {
585
+ loading.textContent = messages.notAvailable;
586
+ return;
587
+ }
588
+
589
+ void diagnostics.inspectHarness(hostId, agent).then(
590
+ (inspection) => {
591
+ loading.remove();
592
+ if (inspection.status !== "ready") {
593
+ const empty = document.createElement("div");
594
+ empty.className = "settings-model-config-empty";
595
+ empty.textContent = inspection.error?.message ?? messages.noModelsAvailable;
596
+ card.append(empty);
597
+ return;
598
+ }
599
+ const catalog = inspection.catalog;
600
+ if (!catalog || !catalog.models || catalog.models.length === 0) {
601
+ const empty = document.createElement("div");
602
+ empty.className = "settings-model-config-empty";
603
+ empty.textContent = messages.noModelsAvailable;
604
+ card.append(empty);
605
+ return;
606
+ }
607
+
608
+ const pref = readNewThreadExternalConfigurationPreference(
609
+ agent,
610
+ catalog,
611
+ inspection.permissionModes,
612
+ );
613
+
614
+ const form = document.createElement("div");
615
+ form.className = "settings-model-config-form";
616
+
617
+ // Model Select
618
+ const modelField = document.createElement("div");
619
+ modelField.className = "settings-model-config-field";
620
+ const modelLabel = document.createElement("label");
621
+ modelLabel.className = "settings-model-config-label";
622
+ modelLabel.textContent = messages.modelSelectLabel;
623
+ const modelSelect = document.createElement("select");
624
+ modelSelect.className = "settings-model-config-select";
625
+
626
+ const initialModelId = pref?.model.id ?? catalog.defaultModel?.id ?? catalog.models[0]?.ref.id;
627
+ for (const m of catalog.models) {
628
+ const option = document.createElement("option");
629
+ option.value = m.ref.id;
630
+ option.textContent = m.label || m.ref.id;
631
+ if (m.ref.id === initialModelId) option.selected = true;
632
+ modelSelect.append(option);
633
+ }
634
+ modelField.append(modelLabel, modelSelect);
635
+ form.append(modelField);
636
+
637
+ // Thinking Select (if supported)
638
+ const thinkingField = document.createElement("div");
639
+ thinkingField.className = "settings-model-config-field";
640
+ const thinkingLabel = document.createElement("label");
641
+ thinkingLabel.className = "settings-model-config-label";
642
+ thinkingLabel.textContent = messages.thinkingSelectLabel;
643
+ const thinkingSelect = document.createElement("select");
644
+ thinkingSelect.className = "settings-model-config-select";
645
+ thinkingField.append(thinkingLabel, thinkingSelect);
646
+
647
+ const updateThinkingOptions = () => {
648
+ const currentModel = catalog.models.find((m) => m.ref.id === modelSelect.value);
649
+ const supportedIds = currentModel?.supportedThinkingOptionIds ?? catalog.thinkingOptions?.map((o) => o.id) ?? [];
650
+ thinkingSelect.replaceChildren();
651
+
652
+ const defaultOption = document.createElement("option");
653
+ defaultOption.value = "";
654
+ defaultOption.textContent = messages.thinkingOptionDefault;
655
+ thinkingSelect.append(defaultOption);
656
+
657
+ const availableThinking = (catalog.thinkingOptions ?? []).filter((o) => supportedIds.includes(o.id));
658
+ if (availableThinking.length === 0) {
659
+ thinkingField.style.display = "none";
660
+ return;
661
+ }
662
+ thinkingField.style.display = "flex";
663
+ for (const opt of availableThinking) {
664
+ const option = document.createElement("option");
665
+ option.value = opt.id;
666
+ option.textContent = opt.label || opt.id;
667
+ if (opt.id === (pref?.thinkingOptionId ?? catalog.defaultThinkingOptionId)) {
668
+ option.selected = true;
669
+ }
670
+ thinkingSelect.append(option);
671
+ }
672
+ };
673
+
674
+ updateThinkingOptions();
675
+ modelSelect.addEventListener("change", updateThinkingOptions);
676
+ form.append(thinkingField);
677
+
678
+ // Buttons & Feedback
679
+ const actions = document.createElement("div");
680
+ actions.className = "settings-model-config-actions";
681
+
682
+ const saveBtn = document.createElement("button");
683
+ saveBtn.type = "button";
684
+ saveBtn.className = "settings-command-button";
685
+ saveBtn.append(createRendererSettingsIcon("check", 15), messages.saveModelPreference);
686
+
687
+ const resetBtn = document.createElement("button");
688
+ resetBtn.type = "button";
689
+ resetBtn.className = "settings-command-button settings-command-button--secondary";
690
+ resetBtn.append(createRendererSettingsIcon("undo", 15), messages.resetModelPreference);
691
+
692
+ const feedback = document.createElement("span");
693
+ feedback.className = "settings-model-config-feedback";
694
+
695
+ saveBtn.addEventListener("click", () => {
696
+ const targetModel = catalog.models.find((m) => m.ref.id === modelSelect.value);
697
+ if (!targetModel) return;
698
+ const thinkingOpt = catalog.thinkingOptions?.find((o) => o.id === thinkingSelect.value);
699
+ const thinkingVal = thinkingOpt?.id;
700
+ writeNewThreadExternalConfigurationPreference(agent, targetModel.ref, thinkingVal);
701
+ feedback.className = "settings-model-config-feedback settings-feedback-success";
702
+ feedback.textContent = messages.preferenceSaved;
703
+ document.defaultView?.setTimeout(() => {
704
+ feedback.textContent = "";
705
+ }, 3500);
706
+ });
707
+
708
+ resetBtn.addEventListener("click", () => {
709
+ const defaultRef = catalog.defaultModel ?? catalog.models[0]?.ref;
710
+ if (!defaultRef) return;
711
+ writeNewThreadExternalConfigurationPreference(agent, defaultRef, catalog.defaultThinkingOptionId);
712
+ modelSelect.value = defaultRef.id;
713
+ updateThinkingOptions();
714
+ if (catalog.defaultThinkingOptionId) thinkingSelect.value = catalog.defaultThinkingOptionId;
715
+ feedback.className = "settings-model-config-feedback settings-feedback-info";
716
+ feedback.textContent = messages.preferenceReset;
717
+ document.defaultView?.setTimeout(() => {
718
+ feedback.textContent = "";
719
+ }, 3500);
720
+ });
721
+
722
+ actions.append(saveBtn, resetBtn, feedback);
723
+ form.append(actions);
724
+ card.append(form);
725
+ },
726
+ (err: unknown) => {
727
+ loading.textContent = `${messages.connectionErrorTitle}: ${err instanceof Error ? err.message : String(err)}`;
728
+ },
729
+ );
730
+ }
731
+
732
+ function renderConnectionInspector(
733
+ document: Document,
734
+ inspector: HTMLElement,
735
+ item: ConnectionListItem,
736
+ hostId: string,
737
+ messages: RendererSettingsMessages,
738
+ diagnostics: RendererConnectionDiagnostics | null = null,
739
+ ): void {
740
+ inspector.replaceChildren(createInspectorHeader(document, item, messages));
741
+ const body = document.createElement("div");
742
+ body.className = "settings-connection-inspector__body";
743
+
744
+ if (item.agentSnapshot && (item.agentSnapshot.availability === "notInstalled" || item.agentSnapshot.availability === "unavailable")) {
745
+ renderOneClickInstallSection(
746
+ document,
747
+ body,
748
+ item.agentSnapshot.agent,
749
+ item.name,
750
+ hostId,
751
+ messages,
752
+ diagnostics,
753
+ );
754
+ } else if (item.error) {
755
+ const summary = document.createElement("div");
756
+ summary.className = "settings-connection-error-summary";
757
+ const title = document.createElement("strong");
758
+ title.textContent = messages.connectionErrorTitle;
759
+ const description = document.createElement("p");
760
+ description.textContent = item.error.message;
761
+ summary.append(title, description);
762
+
763
+ const metadata = document.createElement("div");
764
+ metadata.className = "settings-connection-error-metadata";
765
+ metadata.append(
766
+ detailLine(document, messages.connectionErrorCode, item.error.code),
767
+ detailLine(document, messages.connectionRetryable, String(item.error.retryable)),
768
+ );
769
+ if (item.error.stage) {
770
+ metadata.append(detailLine(document, messages.connectionFailureStage, item.error.stage));
771
+ }
772
+ if (item.error.durationMs !== undefined) {
773
+ metadata.append(
774
+ detailLine(document, messages.connectionDuration, `${item.error.durationMs} ms`),
775
+ );
776
+ }
777
+ if (item.error.diagnostic) {
778
+ metadata.append(detailLine(document, messages.connectionDiagnostic, item.error.diagnostic));
779
+ }
780
+
781
+ const logHeader = document.createElement("div");
782
+ logHeader.className = "settings-connection-error-log-header";
783
+ const logTitle = document.createElement("strong");
784
+ logTitle.textContent = messages.connectionErrorLog;
785
+ const copy = document.createElement("button");
786
+ copy.type = "button";
787
+ copy.className = "settings-command-button settings-command-button--secondary";
788
+ setCopyButtonLabel(copy, messages.connectionCopyDetails);
789
+ const report = diagnosticText(hostId, item);
790
+ copy.addEventListener("click", () => {
791
+ copyDiagnosticsToClipboard(document, copy, report, messages, messages.connectionCopyDetails);
792
+ });
793
+ logHeader.append(logTitle, copy);
794
+ const log = document.createElement("pre");
795
+ log.className = "settings-connection-stderr";
796
+ log.textContent = item.error.stderrTail ?? item.error.diagnostic ?? report;
797
+
798
+ const actions = document.createElement("div");
799
+ actions.className = "settings-connection-error-actions";
800
+ const issue = document.createElement("a");
801
+ issue.className = "settings-command-button settings-command-button--secondary";
802
+ issue.href = CODEXHOST_GITHUB_ISSUES_NEW_URL;
803
+ issue.target = "_blank";
804
+ issue.rel = "noopener noreferrer";
805
+ issue.append(messages.connectionOpenIssue, createRendererSettingsIcon("external-link", 14));
806
+ actions.append(issue);
807
+ const issueNote = document.createElement("p");
808
+ issueNote.className = "settings-connection-issue-note";
809
+ issueNote.textContent = messages.connectionIssueDescription;
810
+ body.append(summary, metadata, logHeader, log, actions, issueNote);
811
+ } else {
812
+ const status = document.createElement("div");
813
+ status.className = "settings-connection-state-summary";
814
+ const title = document.createElement("strong");
815
+ title.textContent = connectionStatusLabel(item.availability, messages);
816
+ const description = document.createElement("p");
817
+ description.textContent =
818
+ item.availability === "ready"
819
+ ? messages.connectionReadyDescription
820
+ : messages.connectionUnavailableDescription;
821
+ status.append(title, description);
822
+ body.append(status);
823
+
824
+ if (item.openWebUi) {
825
+ const open = document.createElement("button");
826
+ open.type = "button";
827
+ open.className = "settings-command-button settings-command-button--secondary";
828
+ open.dataset.connectionAction = "open-web-ui";
829
+ open.append(
830
+ messages.connectionOpenHarnessWeb,
831
+ createRendererSettingsIcon("external-link", 14),
832
+ );
833
+ open.addEventListener("click", () => {
834
+ if (open.disabled) return;
835
+ open.disabled = true;
836
+ void item
837
+ .openWebUi?.()
838
+ .catch(() => undefined)
839
+ .finally(() => {
840
+ open.disabled = false;
841
+ });
842
+ });
843
+ body.append(open);
844
+ }
845
+
846
+ if (item.agentSnapshot && item.availability === "ready") {
847
+ renderModelConfigurationSection(
848
+ document,
849
+ body,
850
+ item.agentSnapshot.agent,
851
+ hostId,
852
+ messages,
853
+ diagnostics,
854
+ );
855
+ }
856
+ }
857
+
858
+ inspector.append(body);
859
+ }
860
+
861
+ function connectionItems(
862
+ snapshot: RendererConnectionSnapshot,
863
+ host: RendererConnectionHostSnapshot,
864
+ messages: RendererSettingsMessages,
865
+ diagnostics: RendererConnectionDiagnostics | null,
866
+ ): ConnectionListItem[] {
867
+ return [
868
+ {
869
+ key: "renderer-adapter",
870
+ name: messages.connectionAdapter,
871
+ availability: snapshot.adapter.state,
872
+ error: null,
873
+ },
874
+ ...host.agents.map((agent): ConnectionListItem => ({
875
+ key: agent.agent,
876
+ name: RENDERER_AGENT_LABELS[agent.agent],
877
+ availability: agent.availability,
878
+ error: agent.availability === "notInstalled" ? null : agent.error,
879
+ agentSnapshot: agent,
880
+ ...(host.hostId === "local" && agent.webUiAvailable && diagnostics?.openWebUi
881
+ ? {
882
+ openWebUi: () => diagnostics.openWebUi?.(host.hostId, agent.agent) ?? Promise.resolve(),
883
+ }
884
+ : {}),
885
+ })),
886
+ ];
887
+ }
888
+
889
+ // Lets another surface (currently: the Agent picker's error indicator, see
890
+ // renderer-agent-picker.ts) ask the Connections page to focus a specific
891
+ // Agent's row the next time it mounts, instead of falling back to "the
892
+ // first Agent that needs attention". Consumed once, then cleared — if the
893
+ // requested Agent isn't present under whichever Host tab is selected by
894
+ // default, this silently falls through to the existing fallback below.
895
+ let pendingFocusAgent: string | null = null;
896
+
897
+ export function requestConnectionsPageFocus(agentKey: string): void {
898
+ pendingFocusAgent = agentKey;
899
+ }
900
+
901
+ function createGroupDivider(
902
+ document: Document,
903
+ messages: RendererSettingsMessages,
904
+ count: number,
905
+ ): HTMLElement {
906
+ const divider = document.createElement("div");
907
+ divider.className = "settings-connection-group-divider";
908
+ divider.setAttribute("role", "presentation");
909
+ divider.textContent = `${messages.connectionGroupMoreLabel} (${count})`;
910
+ return divider;
911
+ }
912
+
913
+ function createGroupMoreHint(document: Document, messages: RendererSettingsMessages): HTMLElement {
914
+ const hint = document.createElement("div");
915
+ hint.className = "settings-connection-group-hint";
916
+ hint.setAttribute("role", "presentation");
917
+ const title = document.createElement("strong");
918
+ title.textContent = messages.connectionGroupMoreHintTitle;
919
+ const body = document.createElement("span");
920
+ body.textContent = messages.connectionGroupMoreHintBody;
921
+ hint.append(title, body);
922
+ return hint;
923
+ }
924
+
925
+ function createGroupResetButton(
926
+ document: Document,
927
+ messages: RendererSettingsMessages,
928
+ onReset: () => void,
929
+ ): HTMLElement {
930
+ const button = document.createElement("button");
931
+ button.type = "button";
932
+ button.className = "settings-connection-group-reset";
933
+ button.append(createRendererSettingsIcon("undo", 14), messages.connectionGroupReset);
934
+ button.addEventListener("click", onReset);
935
+ return button;
936
+ }
937
+
938
+ export function createConnectionsSettingsPage(
939
+ messages: RendererSettingsMessages,
940
+ getDiagnostics: () => RendererConnectionDiagnostics | null,
941
+ groupPreference: AgentGroupPreferenceStore = getSharedAgentGroupPreferenceStore(),
942
+ ): RendererSettingsPageDefinition {
943
+ return Object.freeze({
944
+ id: "connections",
945
+ label: messages.pageLabels.connections,
946
+ icon: "connections",
947
+ mount(context: RendererSettingsPageMountContext) {
948
+ const document = context.content.ownerDocument;
949
+ const header = document.createElement("div");
950
+ header.className = "settings-connection-page-header";
951
+ const headingCopy = document.createElement("div");
952
+ const heading = document.createElement("div");
953
+ heading.className = "settings-section-label";
954
+ heading.textContent = messages.pageLabels.connections;
955
+ const description = document.createElement("p");
956
+ description.className = "settings-page-description";
957
+ description.textContent = messages.connectionsDescription;
958
+ headingCopy.append(heading, description);
959
+ const refresh = document.createElement("button");
960
+ refresh.type = "button";
961
+ refresh.className = "settings-command-button settings-command-button--secondary";
962
+ refresh.dataset.connectionAction = "refresh";
963
+ refresh.append(createRendererSettingsIcon("diagnose", 16), messages.connectionRefresh);
964
+ header.append(headingCopy, refresh);
965
+ const content = document.createElement("div");
966
+ content.className = "settings-connections-content";
967
+ context.content.append(header, content);
968
+
969
+ let pending = false;
970
+ let selectedHostId: string | null = null;
971
+ let selectedItemKey: string | null = null;
972
+ let latestSnapshot: RendererConnectionSnapshot | null = null;
973
+ let disposeHostScroller = (): void => undefined;
974
+
975
+ const diagnostics = getDiagnostics();
976
+ const runRefresh = (): void => {
977
+ if (pending || !diagnostics) return;
978
+ pending = true;
979
+ refresh.disabled = true;
980
+ refresh.replaceChildren(
981
+ createRendererSettingsIcon("diagnose", 16),
982
+ messages.connectionRefreshing,
983
+ );
984
+ void context.runLatest(() => diagnostics.refresh(), {
985
+ success() {
986
+ pending = false;
987
+ refresh.disabled = false;
988
+ refresh.replaceChildren(
989
+ createRendererSettingsIcon("diagnose", 16),
990
+ messages.connectionRefresh,
991
+ );
992
+ render(diagnostics.snapshot());
993
+ },
994
+ failure(error) {
995
+ pending = false;
996
+ refresh.disabled = false;
997
+ refresh.replaceChildren(
998
+ createRendererSettingsIcon("diagnose", 16),
999
+ messages.connectionRefresh,
1000
+ );
1001
+ const snapshot = diagnostics.snapshot();
1002
+ render({
1003
+ ...snapshot,
1004
+ hosts: snapshot.hosts.map((host) => ({
1005
+ ...host,
1006
+ agents: host.agents.map((agent) => ({
1007
+ ...agent,
1008
+ availability: "error",
1009
+ error: {
1010
+ code: "internalError",
1011
+ message: error instanceof Error ? error.message : String(error),
1012
+ retryable: true,
1013
+ stage: "request",
1014
+ },
1015
+ })),
1016
+ })),
1017
+ });
1018
+ },
1019
+ });
1020
+ };
1021
+
1022
+ const render = (snapshot: RendererConnectionSnapshot | null): void => {
1023
+ latestSnapshot = snapshot;
1024
+ disposeHostScroller();
1025
+ disposeHostScroller = () => undefined;
1026
+ content.replaceChildren();
1027
+ if (!snapshot) {
1028
+ const empty = document.createElement("div");
1029
+ empty.className = "settings-empty";
1030
+ empty.textContent = messages.connectionNoRuntime;
1031
+ content.append(empty);
1032
+ return;
1033
+ }
1034
+ const selectedHost =
1035
+ (selectedHostId
1036
+ ? snapshot.hosts.find((host) => host.hostId === selectedHostId)
1037
+ : undefined) ??
1038
+ snapshot.hosts.find((host) => host.active) ??
1039
+ snapshot.hosts.find((host) => host.hostId === "local") ??
1040
+ snapshot.hosts[0];
1041
+ if (!selectedHost) return;
1042
+ selectedHostId = selectedHost.hostId;
1043
+
1044
+ const layout = document.createElement("div");
1045
+ layout.className = "settings-connections-layout";
1046
+ const list = document.createElement("section");
1047
+ list.className = "settings-connection-list";
1048
+ const hostStrip = document.createElement("div");
1049
+ hostStrip.className = "settings-connection-host-strip";
1050
+ const scrollLeft = createHostScrollButton(document, "left", messages);
1051
+ const tabs = document.createElement("div");
1052
+ tabs.className = "settings-connection-host-tabs";
1053
+ tabs.setAttribute("role", "tablist");
1054
+ tabs.setAttribute("aria-label", messages.connectionHosts);
1055
+ const scrollRight = createHostScrollButton(document, "right", messages);
1056
+ const panelId = "codexhost-settings-connection-host-panel";
1057
+
1058
+ snapshot.hosts.forEach((host, index) => {
1059
+ const tab = document.createElement("button");
1060
+ tab.type = "button";
1061
+ tab.className = "settings-connection-host-tab";
1062
+ tab.dataset.connectionHostTab = host.hostId;
1063
+ tab.dataset.connectionHostActive = String(host.active);
1064
+ tab.setAttribute("role", "tab");
1065
+ tab.setAttribute("aria-controls", panelId);
1066
+ tab.setAttribute("aria-selected", String(host.hostId === selectedHost.hostId));
1067
+ tab.tabIndex = host.hostId === selectedHost.hostId ? 0 : -1;
1068
+ const hostName = connectionHostName(host.hostId, messages);
1069
+ tab.textContent = hostName;
1070
+ tab.title = host.active ? `${hostName} · ${messages.connectionActiveHost}` : hostName;
1071
+ tab.addEventListener("click", () => {
1072
+ selectedHostId = host.hostId;
1073
+ render(latestSnapshot);
1074
+ });
1075
+ tab.addEventListener("keydown", (event) => {
1076
+ if (event.key !== "ArrowLeft" && event.key !== "ArrowRight") return;
1077
+ event.preventDefault();
1078
+ const direction = event.key === "ArrowRight" ? 1 : -1;
1079
+ const next =
1080
+ snapshot.hosts[(index + direction + snapshot.hosts.length) % snapshot.hosts.length];
1081
+ if (!next) return;
1082
+ selectedHostId = next.hostId;
1083
+ render(latestSnapshot);
1084
+ const nextTab = [
1085
+ ...content.querySelectorAll<HTMLButtonElement>("[data-connection-host-tab]"),
1086
+ ].find((candidate) => candidate.dataset.connectionHostTab === next.hostId);
1087
+ nextTab?.focus();
1088
+ });
1089
+ tabs.append(tab);
1090
+ });
1091
+ hostStrip.append(scrollLeft, tabs, scrollRight);
1092
+
1093
+ const tableHeader = document.createElement("div");
1094
+ tableHeader.className = "settings-connection-table-header";
1095
+ tableHeader.setAttribute("role", "row");
1096
+ const componentHeading = document.createElement("span");
1097
+ componentHeading.textContent = messages.connectionComponent;
1098
+ componentHeading.setAttribute("role", "columnheader");
1099
+ const statusHeading = document.createElement("span");
1100
+ statusHeading.textContent = messages.connectionStatus;
1101
+ statusHeading.setAttribute("role", "columnheader");
1102
+ const actionHeading = document.createElement("span");
1103
+ actionHeading.setAttribute("aria-hidden", "true");
1104
+ tableHeader.append(componentHeading, statusHeading, actionHeading);
1105
+
1106
+ const rows = document.createElement("div");
1107
+ rows.className = "settings-connection-rows";
1108
+ rows.id = panelId;
1109
+ rows.dataset.connectionHost = selectedHost.hostId;
1110
+ rows.setAttribute("role", "rowgroup");
1111
+ const inspector = document.createElement("aside");
1112
+ inspector.className = "settings-connection-inspector";
1113
+ inspector.setAttribute("aria-live", "polite");
1114
+ const items = connectionItems(snapshot, selectedHost, messages, diagnostics);
1115
+ if (!items.some((item) => item.key === selectedItemKey)) {
1116
+ const requestedFocus = pendingFocusAgent;
1117
+ pendingFocusAgent = null;
1118
+ selectedItemKey =
1119
+ (requestedFocus && items.some((item) => item.key === requestedFocus)
1120
+ ? requestedFocus
1121
+ : undefined) ??
1122
+ items.find(
1123
+ (item) => item.agentSnapshot?.availability === "notInstalled" || item.error !== null,
1124
+ )?.key ??
1125
+ items[0]?.key ??
1126
+ null;
1127
+ }
1128
+ const rowElements = new Map<string, HTMLElement>();
1129
+ const selectItem = (item: ConnectionListItem): void => {
1130
+ selectedItemKey = item.key;
1131
+ for (const [key, row] of rowElements) {
1132
+ const selected = key === item.key;
1133
+ row.dataset.connectionSelected = String(selected);
1134
+ row.tabIndex = selected ? 0 : -1;
1135
+ }
1136
+ renderConnectionInspector(document, inspector, item, selectedHost.hostId, messages, diagnostics);
1137
+ };
1138
+
1139
+ const pinnedItem = items.find((item) => item.key === "renderer-adapter");
1140
+ if (pinnedItem) {
1141
+ const row = createConnectionRow(
1142
+ document,
1143
+ pinnedItem,
1144
+ messages,
1145
+ pinnedItem.key === selectedItemKey,
1146
+ () => selectItem(pinnedItem),
1147
+ );
1148
+ rowElements.set(pinnedItem.key, row);
1149
+ rows.append(row);
1150
+ }
1151
+
1152
+ // Only real, switchable external Agents participate in the
1153
+ // Main / More grouping — the Renderer adapter above stays pinned.
1154
+ const groupableItems = items.filter(
1155
+ (item): item is ConnectionListItem & { agentSnapshot: RendererConnectionAgentSnapshot } =>
1156
+ item.agentSnapshot !== undefined,
1157
+ );
1158
+ const agentByKey = new Map(groupableItems.map((item) => [item.key, item]));
1159
+ const preferenceOrder = groupPreference
1160
+ .list()
1161
+ .filter((entry) => agentByKey.has(entry.agent));
1162
+ for (const item of groupableItems) {
1163
+ if (!preferenceOrder.some((entry) => entry.agent === item.key)) {
1164
+ preferenceOrder.push({ agent: item.key as ExternalRendererAgent, section: "main" });
1165
+ }
1166
+ }
1167
+ const mainEntries = preferenceOrder.filter((entry) => entry.section === "main");
1168
+ const moreEntries = preferenceOrder.filter((entry) => entry.section === "more");
1169
+ const nextInSection = (
1170
+ section: AgentGroupSection,
1171
+ agent: ExternalRendererAgent,
1172
+ ): ExternalRendererAgent | null => {
1173
+ const list = section === "main" ? mainEntries : moreEntries;
1174
+ const index = list.findIndex((entry) => entry.agent === agent);
1175
+ return index >= 0 ? (list[index + 1]?.agent ?? null) : null;
1176
+ };
1177
+
1178
+ let draggingAgent: ExternalRendererAgent | null = null;
1179
+ // Assigned below only when there is at least one groupable Agent to
1180
+ // show a More zone for; guarded everywhere it's read.
1181
+ let moreZone: HTMLElement | null = null;
1182
+ const clearDropIndicators = (): void => {
1183
+ for (const row of rowElements.values()) row.dataset.connectionDropIndicator = "";
1184
+ if (moreZone) moreZone.dataset.connectionDragOver = "false";
1185
+ };
1186
+ const dropTargetSection = (
1187
+ agent: ExternalRendererAgent,
1188
+ event: DragEvent,
1189
+ ): { before: boolean; beforeAgent: ExternalRendererAgent | null } => {
1190
+ const row = rowElements.get(agent);
1191
+ const rect =
1192
+ row && typeof row.getBoundingClientRect === "function"
1193
+ ? row.getBoundingClientRect()
1194
+ : null;
1195
+ const before = rect ? event.clientY - rect.top < rect.height / 2 : true;
1196
+ const section = (row?.dataset.connectionGroupSection ?? "main") as AgentGroupSection;
1197
+ return { before, beforeAgent: before ? agent : nextInSection(section, agent) };
1198
+ };
1199
+ const createGroupController = (
1200
+ agent: ExternalRendererAgent,
1201
+ section: AgentGroupSection,
1202
+ ): ConnectionRowGroupController => ({
1203
+ section,
1204
+ moveLabel:
1205
+ section === "main"
1206
+ ? messages.connectionGroupMoveToMore
1207
+ : messages.connectionGroupMoveToMain,
1208
+ dragHandleTitle: messages.connectionGroupDragHandle,
1209
+ toggleSection() {
1210
+ groupPreference.moveAgent(agent, section === "main" ? "more" : "main", null);
1211
+ },
1212
+ onDragStart(event) {
1213
+ draggingAgent = agent;
1214
+ event.dataTransfer?.setData("text/plain", agent);
1215
+ if (event.dataTransfer) event.dataTransfer.effectAllowed = "move";
1216
+ const row = rowElements.get(agent);
1217
+ if (row) row.dataset.connectionDragging = "true";
1218
+ },
1219
+ onDragOver(event) {
1220
+ if (!draggingAgent || draggingAgent === agent) return;
1221
+ event.preventDefault();
1222
+ const row = rowElements.get(agent);
1223
+ if (!row) return;
1224
+ const { before } = dropTargetSection(agent, event);
1225
+ clearDropIndicators();
1226
+ row.dataset.connectionDropIndicator = before ? "before" : "after";
1227
+ },
1228
+ onDragLeave() {
1229
+ const row = rowElements.get(agent);
1230
+ if (row) row.dataset.connectionDropIndicator = "";
1231
+ },
1232
+ onDrop(event) {
1233
+ event.preventDefault();
1234
+ if (!draggingAgent) return;
1235
+ const { beforeAgent } = dropTargetSection(agent, event);
1236
+ groupPreference.moveAgent(draggingAgent, section, beforeAgent);
1237
+ draggingAgent = null;
1238
+ clearDropIndicators();
1239
+ },
1240
+ onDragEnd() {
1241
+ draggingAgent = null;
1242
+ const row = rowElements.get(agent);
1243
+ if (row) row.dataset.connectionDragging = "false";
1244
+ clearDropIndicators();
1245
+ },
1246
+ });
1247
+
1248
+ const appendGroupRow = (agent: ExternalRendererAgent, section: AgentGroupSection): void => {
1249
+ const item = agentByKey.get(agent);
1250
+ if (!item) return;
1251
+ const row = createConnectionRow(
1252
+ document,
1253
+ item,
1254
+ messages,
1255
+ item.key === selectedItemKey,
1256
+ () => selectItem(item),
1257
+ createGroupController(agent, section),
1258
+ );
1259
+ rowElements.set(item.key, row);
1260
+ rows.append(row);
1261
+ };
1262
+
1263
+ for (const entry of mainEntries) appendGroupRow(entry.agent, "main");
1264
+
1265
+ if (groupableItems.length > 0) {
1266
+ rows.append(createGroupDivider(document, messages, moreEntries.length));
1267
+ const zone = document.createElement("div");
1268
+ moreZone = zone;
1269
+ zone.className = "settings-connection-group-more";
1270
+ zone.setAttribute("role", "presentation");
1271
+ zone.addEventListener("dragover", (event) => {
1272
+ if (!draggingAgent) return;
1273
+ event.preventDefault();
1274
+ zone.dataset.connectionDragOver = "true";
1275
+ });
1276
+ zone.addEventListener("dragleave", () => {
1277
+ zone.dataset.connectionDragOver = "false";
1278
+ });
1279
+ zone.addEventListener("drop", (event) => {
1280
+ event.preventDefault();
1281
+ zone.dataset.connectionDragOver = "false";
1282
+ if (!draggingAgent) return;
1283
+ groupPreference.moveAgent(draggingAgent, "more", null);
1284
+ draggingAgent = null;
1285
+ clearDropIndicators();
1286
+ });
1287
+ if (moreEntries.length === 0) {
1288
+ zone.append(createGroupMoreHint(document, messages));
1289
+ } else {
1290
+ for (const entry of moreEntries) {
1291
+ const item = agentByKey.get(entry.agent);
1292
+ if (!item) continue;
1293
+ const row = createConnectionRow(
1294
+ document,
1295
+ item,
1296
+ messages,
1297
+ item.key === selectedItemKey,
1298
+ () => selectItem(item),
1299
+ createGroupController(entry.agent, "more"),
1300
+ );
1301
+ rowElements.set(item.key, row);
1302
+ zone.append(row);
1303
+ }
1304
+ }
1305
+ rows.append(zone);
1306
+
1307
+ rows.append(
1308
+ createGroupResetButton(document, messages, () => {
1309
+ groupPreference.resetToDefault();
1310
+ }),
1311
+ );
1312
+ }
1313
+
1314
+ const selectedItem = items.find((item) => item.key === selectedItemKey) ?? items[0];
1315
+ if (selectedItem) selectItem(selectedItem);
1316
+ list.append(hostStrip, tableHeader, rows);
1317
+ layout.append(list, inspector);
1318
+ content.append(layout);
1319
+ disposeHostScroller = configureHostScroller(
1320
+ document,
1321
+ hostStrip,
1322
+ tabs,
1323
+ scrollLeft,
1324
+ scrollRight,
1325
+ );
1326
+ const selectedTab = [...tabs.children].find(
1327
+ (child) => child.getAttribute("aria-selected") === "true",
1328
+ ) as HTMLElement | undefined;
1329
+ selectedTab?.scrollIntoView?.({ block: "nearest", inline: "nearest" });
1330
+ };
1331
+
1332
+ render(diagnostics?.snapshot() ?? null);
1333
+ // Keep the Main / More grouping in sync with any other open picker or
1334
+ // settings instance (e.g. the Agent picker's "Manage" shortcut).
1335
+ const unsubscribeGroup = groupPreference.subscribe(() =>
1336
+ render(diagnostics?.snapshot() ?? latestSnapshot),
1337
+ );
1338
+ if (!diagnostics) {
1339
+ refresh.disabled = true;
1340
+ return () => {
1341
+ disposeHostScroller();
1342
+ unsubscribeGroup();
1343
+ };
1344
+ }
1345
+ refresh.addEventListener("click", runRefresh);
1346
+ const unsubscribe = diagnostics.subscribe(() => render(diagnostics.snapshot()));
1347
+ return () => {
1348
+ disposeHostScroller();
1349
+ unsubscribe();
1350
+ unsubscribeGroup();
1351
+ };
1352
+ },
1353
+ });
1354
+ }