@harness-mix/cli 0.1.3

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 (655) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/LICENSE +202 -0
  3. package/NOTICE +14 -0
  4. package/README.md +262 -0
  5. package/Start-Codex.cmd +5 -0
  6. package/config/codex-desktop-compatibility.json +29 -0
  7. package/docs/chatgpt-web-sidebar.md +27 -0
  8. package/docs/cross-platform.md +73 -0
  9. package/docs/harness-management.md +44 -0
  10. package/docs/images/codex-desktop-home.png +0 -0
  11. package/docs/images/codex-desktop-session.png +0 -0
  12. package/docs/kiro-cursor-integration.md +3 -0
  13. package/docs/multi-agent-collaboration.md +89 -0
  14. package/docs/native-acp.md +122 -0
  15. package/docs/native-codex.md +95 -0
  16. package/docs/superpowers/specs/2026-09-13-native-hardening-design.md +326 -0
  17. package/licenses/codex-host-MIT.txt +21 -0
  18. package/output/native-build/desktop-controller.mjs +1466 -0
  19. package/output/native-build/harness-mix-appx.exe +0 -0
  20. package/output/native-build/harness-mix-secret.exe +0 -0
  21. package/output/native-build/harness-mix-shim.exe +0 -0
  22. package/output/native-build/renderer-extension.js +29380 -0
  23. package/package.json +168 -0
  24. package/scripts/acp-capabilities-probe.cjs +100 -0
  25. package/scripts/adapters-test.cjs +17 -0
  26. package/scripts/antigravity-adapter-test.cjs +529 -0
  27. package/scripts/architecture-test.cjs +62 -0
  28. package/scripts/build-native.cjs +56 -0
  29. package/scripts/catalog-test.cjs +25 -0
  30. package/scripts/cdp-eval.cjs +40 -0
  31. package/scripts/cdp-watch.cjs +36 -0
  32. package/scripts/check.cjs +23 -0
  33. package/scripts/codebuddy-migration-test.cjs +47 -0
  34. package/scripts/codex-adapter-test.cjs +83 -0
  35. package/scripts/collaboration-recovery-test.cjs +111 -0
  36. package/scripts/collaboration-test.cjs +108 -0
  37. package/scripts/collaboration-ui-smoke.cjs +57 -0
  38. package/scripts/concurrency-layers-test.cjs +181 -0
  39. package/scripts/contracts-test.cjs +105 -0
  40. package/scripts/core-concurrency-test.cjs +103 -0
  41. package/scripts/core-replay-test.cjs +179 -0
  42. package/scripts/core-runtime-test.cjs +104 -0
  43. package/scripts/core-services-test.cjs +50 -0
  44. package/scripts/determinism-test.cjs +36 -0
  45. package/scripts/diagnostics.cjs +63 -0
  46. package/scripts/docs-command-test.cjs +49 -0
  47. package/scripts/dsh-adapter-test.cjs +90 -0
  48. package/scripts/dsh-collaboration-acp-test.cjs +19 -0
  49. package/scripts/dsh-native.cjs +9 -0
  50. package/scripts/dsh-native.cmd +2 -0
  51. package/scripts/e2e-codex.cjs +82 -0
  52. package/scripts/e2e-collaboration.cjs +60 -0
  53. package/scripts/e2e-core-files.cjs +58 -0
  54. package/scripts/e2e-core-fork.cjs +49 -0
  55. package/scripts/e2e-core-resume.cjs +49 -0
  56. package/scripts/e2e-delegate.cjs +38 -0
  57. package/scripts/e2e-dsh.cjs +23 -0
  58. package/scripts/e2e-native-acp.cjs +42 -0
  59. package/scripts/e2e-native-commands.cjs +54 -0
  60. package/scripts/e2e-native-host.cjs +144 -0
  61. package/scripts/e2e-openclaw-image.cjs +59 -0
  62. package/scripts/e2e-openclaw.cjs +21 -0
  63. package/scripts/e2e-pi.cjs +23 -0
  64. package/scripts/e2e-shadow.cjs +52 -0
  65. package/scripts/fixture-capture.cjs +103 -0
  66. package/scripts/harness-health-check.cjs +72 -0
  67. package/scripts/kiro-cursor-adapters-test.cjs +82 -0
  68. package/scripts/launch-codex.cjs +5 -0
  69. package/scripts/native-acp-depth-test.cjs +189 -0
  70. package/scripts/native-compatibility-test.cjs +42 -0
  71. package/scripts/native-config-test.cjs +25 -0
  72. package/scripts/native-file-change-test.cjs +94 -0
  73. package/scripts/native-host.cjs +8 -0
  74. package/scripts/native-images-test.cjs +56 -0
  75. package/scripts/native-job-object-test.cjs +83 -0
  76. package/scripts/native-protocol-test.cjs +258 -0
  77. package/scripts/native-rollback-test.cjs +46 -0
  78. package/scripts/native-secret-test.cjs +57 -0
  79. package/scripts/native-shim-test.cjs +41 -0
  80. package/scripts/native-sidebar-test.cjs +88 -0
  81. package/scripts/native-ui-smoke.cjs +94 -0
  82. package/scripts/native-update-apply-test.cjs +215 -0
  83. package/scripts/native-updater-test.cjs +109 -0
  84. package/scripts/native-vendor-adapters-test.cjs +88 -0
  85. package/scripts/openclaw-acp-probe.cjs +39 -0
  86. package/scripts/openclaw-adapter-test.cjs +180 -0
  87. package/scripts/openclaw-models-probe.cjs +13 -0
  88. package/scripts/platform-test.cjs +62 -0
  89. package/scripts/projector-test.cjs +144 -0
  90. package/scripts/sequence-test.cjs +57 -0
  91. package/scripts/shadow-test.cjs +154 -0
  92. package/scripts/support/legacy-projection.cjs +95 -0
  93. package/scripts/support/legacy-transcript.cjs +48 -0
  94. package/scripts/support/parity-observer.cjs +27 -0
  95. package/scripts/support/shadow-comparator.cjs +62 -0
  96. package/scripts/support/shadow.cjs +114 -0
  97. package/scripts/switch-harness-test.cjs +145 -0
  98. package/scripts/thread-title-test.cjs +98 -0
  99. package/scripts/tool-concurrency-regression-test.cjs +119 -0
  100. package/scripts/transcript-test.cjs +24 -0
  101. package/scripts/turn-manager-test.cjs +91 -0
  102. package/scripts/workspace-test.cjs +86 -0
  103. package/src/assets/brand-harness-mix.png +0 -0
  104. package/src/assets/icons/antigravity-color.svg +1 -0
  105. package/src/assets/icons/claude-color.svg +1 -0
  106. package/src/assets/icons/codebuddy-color.svg +1 -0
  107. package/src/assets/icons/codex-color.svg +1 -0
  108. package/src/assets/icons/codex-harness.svg +1 -0
  109. package/src/assets/icons/cursor-cli-color.svg +1 -0
  110. package/src/assets/icons/cursor.svg +1 -0
  111. package/src/assets/icons/deepseek-color.svg +1 -0
  112. package/src/assets/icons/grok-color.svg +1 -0
  113. package/src/assets/icons/hermes-color.svg +1 -0
  114. package/src/assets/icons/kiro-cli-color.svg +11 -0
  115. package/src/assets/icons/model-astra.svg +1 -0
  116. package/src/assets/icons/model-claude.svg +1 -0
  117. package/src/assets/icons/model-deepseek.svg +1 -0
  118. package/src/assets/icons/model-gemini.svg +1 -0
  119. package/src/assets/icons/model-grok.svg +1 -0
  120. package/src/assets/icons/model-hunyuan.svg +1 -0
  121. package/src/assets/icons/model-kimi.svg +1 -0
  122. package/src/assets/icons/model-minimax.svg +1 -0
  123. package/src/assets/icons/model-openai.svg +1 -0
  124. package/src/assets/icons/model-qwen-color.svg +1 -0
  125. package/src/assets/icons/model-xiaomimimo.svg +1 -0
  126. package/src/assets/icons/model-zai.svg +1 -0
  127. package/src/assets/icons/omp-color.svg +1 -0
  128. package/src/assets/icons/openclaw-color.svg +1 -0
  129. package/src/assets/icons/opencode-color.svg +1 -0
  130. package/src/assets/icons/pi.svg +1 -0
  131. package/src/assets/icons/pinumber1_80899.svg +48 -0
  132. package/src/assets/icons/qoder-color.svg +1 -0
  133. package/src/assets/icons/trae-color.svg +1 -0
  134. package/src/assets/icons/workbuddy-color.svg +1 -0
  135. package/src/assets/icons/zcode-color.svg +1 -0
  136. package/src/main/adapters/acp-interactions.js +132 -0
  137. package/src/main/adapters/acp.js +191 -0
  138. package/src/main/adapters/antigravity.js +1368 -0
  139. package/src/main/adapters/claude.js +520 -0
  140. package/src/main/adapters/codebuddy-history.js +90 -0
  141. package/src/main/adapters/codebuddy.js +2 -0
  142. package/src/main/adapters/codex-app-server.js +119 -0
  143. package/src/main/adapters/codex.js +559 -0
  144. package/src/main/adapters/cursor.js +2 -0
  145. package/src/main/adapters/dsh-web-host.js +202 -0
  146. package/src/main/adapters/dsh.js +446 -0
  147. package/src/main/adapters/grok.js +277 -0
  148. package/src/main/adapters/hermes.js +24 -0
  149. package/src/main/adapters/index.js +32 -0
  150. package/src/main/adapters/kiro-history.js +43 -0
  151. package/src/main/adapters/kiro.js +2 -0
  152. package/src/main/adapters/native-acp-command.js +47 -0
  153. package/src/main/adapters/native-acp.js +435 -0
  154. package/src/main/adapters/omp.js +12 -0
  155. package/src/main/adapters/openclaw-gateway.js +211 -0
  156. package/src/main/adapters/openclaw.js +337 -0
  157. package/src/main/adapters/opencode-server.js +73 -0
  158. package/src/main/adapters/opencode.js +178 -0
  159. package/src/main/adapters/pi-family.js +342 -0
  160. package/src/main/adapters/pi-usage.js +24 -0
  161. package/src/main/adapters/pi.js +10 -0
  162. package/src/main/adapters/qoder.js +7 -0
  163. package/src/main/adapters/trae.js +7 -0
  164. package/src/main/adapters/workbuddy.js +2 -0
  165. package/src/main/adapters/zcode.js +7 -0
  166. package/src/main/harness-adapter/contract-test.js +53 -0
  167. package/src/main/harness-adapter/contract.js +34 -0
  168. package/src/main/harness-adapter/event-normalizer.js +252 -0
  169. package/src/main/harness-adapter/fixture-recorder.js +56 -0
  170. package/src/main/harness-adapter/index.js +6 -0
  171. package/src/main/harness-adapter/manifest.js +44 -0
  172. package/src/main/host/collaboration-mcp.cjs +35 -0
  173. package/src/main/host/collaboration-pi.mjs +17 -0
  174. package/src/main/host/collaboration-tools.js +16 -0
  175. package/src/main/host/collaboration-worktree.js +151 -0
  176. package/src/main/host/collaboration.js +264 -0
  177. package/src/main/host/core-session.js +81 -0
  178. package/src/main/host/handoff.js +46 -0
  179. package/src/main/host/history-import.js +55 -0
  180. package/src/main/host/jsonl.js +116 -0
  181. package/src/main/host/native-history.js +79 -0
  182. package/src/main/host/runtime.js +1050 -0
  183. package/src/main/host/session-history.js +63 -0
  184. package/src/main/host/store.js +75 -0
  185. package/src/main/native/compatibility.js +56 -0
  186. package/src/main/native/config.js +55 -0
  187. package/src/main/native/host.js +153 -0
  188. package/src/main/native/icons.js +105 -0
  189. package/src/main/native/input.js +43 -0
  190. package/src/main/native/launcher.js +188 -0
  191. package/src/main/native/platform.js +64 -0
  192. package/src/main/native/process-utils.js +57 -0
  193. package/src/main/native/protocol.js +836 -0
  194. package/src/main/native/redact.js +35 -0
  195. package/src/main/native/rs/Cargo.lock +15 -0
  196. package/src/main/native/rs/Cargo.toml +9 -0
  197. package/src/main/native/rs/crates/appx/Cargo.toml +13 -0
  198. package/src/main/native/rs/crates/appx/src/main.rs +309 -0
  199. package/src/main/native/rs/crates/secret/Cargo.toml +10 -0
  200. package/src/main/native/rs/crates/secret/src/main.rs +262 -0
  201. package/src/main/native/rs/crates/shim/Cargo.toml +10 -0
  202. package/src/main/native/rs/crates/shim/src/job.rs +83 -0
  203. package/src/main/native/rs/crates/shim/src/main.rs +257 -0
  204. package/src/main/native/secure-store.js +59 -0
  205. package/src/main/native/thread-list.js +38 -0
  206. package/src/main/native/update-state.js +110 -0
  207. package/src/main/native/updater.js +394 -0
  208. package/src/main/native/usage.js +105 -0
  209. package/src/main/protocol-core/capability-manager.js +16 -0
  210. package/src/main/protocol-core/event-router.js +32 -0
  211. package/src/main/protocol-core/file-change-projector.js +45 -0
  212. package/src/main/protocol-core/index.js +8 -0
  213. package/src/main/protocol-core/interaction-router.js +30 -0
  214. package/src/main/protocol-core/projector.js +238 -0
  215. package/src/main/protocol-core/protocol-core.js +132 -0
  216. package/src/main/protocol-core/sequence-validator.js +44 -0
  217. package/src/main/protocol-core/thread-manager.js +50 -0
  218. package/src/main/protocol-core/turn-manager.js +63 -0
  219. package/src/main/shared-contracts/capability.js +35 -0
  220. package/src/main/shared-contracts/event.js +55 -0
  221. package/src/main/shared-contracts/ids.js +12 -0
  222. package/src/main/shared-contracts/index.js +11 -0
  223. package/src/main/shared-contracts/interaction.js +37 -0
  224. package/src/main/shared-contracts/item.js +51 -0
  225. package/src/main/shared-contracts/native-ref.js +24 -0
  226. package/src/main/shared-contracts/thread.js +36 -0
  227. package/src/main/shared-contracts/turn.js +54 -0
  228. package/src/main/workspace/core-review.js +53 -0
  229. package/src/main/workspace/diff.js +27 -0
  230. package/src/main/workspace/file-changes.js +21 -0
  231. package/src/main/workspace/files.js +76 -0
  232. package/src/main/workspace/review-controller.js +102 -0
  233. package/src/main/workspace/review.js +88 -0
  234. package/src/native-ui/LICENSE +21 -0
  235. package/src/native-ui/README.md +16 -0
  236. package/src/native-ui/desktop-control/dist/cdp-client.d.ts +53 -0
  237. package/src/native-ui/desktop-control/dist/cdp-client.d.ts.map +1 -0
  238. package/src/native-ui/desktop-control/dist/cdp-client.js +258 -0
  239. package/src/native-ui/desktop-control/dist/cdp-client.js.map +1 -0
  240. package/src/native-ui/desktop-control/dist/contract-audit.d.ts +73 -0
  241. package/src/native-ui/desktop-control/dist/contract-audit.d.ts.map +1 -0
  242. package/src/native-ui/desktop-control/dist/contract-audit.js +152 -0
  243. package/src/native-ui/desktop-control/dist/contract-audit.js.map +1 -0
  244. package/src/native-ui/desktop-control/dist/controller-attachment-server.d.ts +10 -0
  245. package/src/native-ui/desktop-control/dist/controller-attachment-server.d.ts.map +1 -0
  246. package/src/native-ui/desktop-control/dist/controller-attachment-server.js +77 -0
  247. package/src/native-ui/desktop-control/dist/controller-attachment-server.js.map +1 -0
  248. package/src/native-ui/desktop-control/dist/index.d.ts +21 -0
  249. package/src/native-ui/desktop-control/dist/index.d.ts.map +1 -0
  250. package/src/native-ui/desktop-control/dist/index.js +14 -0
  251. package/src/native-ui/desktop-control/dist/index.js.map +1 -0
  252. package/src/native-ui/desktop-control/dist/main-process-title-policy.d.ts +24 -0
  253. package/src/native-ui/desktop-control/dist/main-process-title-policy.d.ts.map +1 -0
  254. package/src/native-ui/desktop-control/dist/main-process-title-policy.js +284 -0
  255. package/src/native-ui/desktop-control/dist/main-process-title-policy.js.map +1 -0
  256. package/src/native-ui/desktop-control/dist/production-controller.d.ts +32 -0
  257. package/src/native-ui/desktop-control/dist/production-controller.d.ts.map +1 -0
  258. package/src/native-ui/desktop-control/dist/production-controller.js +294 -0
  259. package/src/native-ui/desktop-control/dist/production-controller.js.map +1 -0
  260. package/src/native-ui/desktop-control/dist/release-main.d.ts +2 -0
  261. package/src/native-ui/desktop-control/dist/release-main.d.ts.map +1 -0
  262. package/src/native-ui/desktop-control/dist/release-main.js +17 -0
  263. package/src/native-ui/desktop-control/dist/release-main.js.map +1 -0
  264. package/src/native-ui/desktop-control/dist/renderer-cdp-control-session.d.ts +49 -0
  265. package/src/native-ui/desktop-control/dist/renderer-cdp-control-session.d.ts.map +1 -0
  266. package/src/native-ui/desktop-control/dist/renderer-cdp-control-session.js +214 -0
  267. package/src/native-ui/desktop-control/dist/renderer-cdp-control-session.js.map +1 -0
  268. package/src/native-ui/desktop-control/dist/renderer-control-session.d.ts +79 -0
  269. package/src/native-ui/desktop-control/dist/renderer-control-session.d.ts.map +1 -0
  270. package/src/native-ui/desktop-control/dist/renderer-control-session.js +366 -0
  271. package/src/native-ui/desktop-control/dist/renderer-control-session.js.map +1 -0
  272. package/src/native-ui/desktop-control/dist/renderer-dom.d.ts +24 -0
  273. package/src/native-ui/desktop-control/dist/renderer-dom.d.ts.map +1 -0
  274. package/src/native-ui/desktop-control/dist/renderer-dom.js +110 -0
  275. package/src/native-ui/desktop-control/dist/renderer-dom.js.map +1 -0
  276. package/src/native-ui/desktop-control/dist/renderer-draft-prewarm-policy.d.ts +20 -0
  277. package/src/native-ui/desktop-control/dist/renderer-draft-prewarm-policy.d.ts.map +1 -0
  278. package/src/native-ui/desktop-control/dist/renderer-draft-prewarm-policy.js +173 -0
  279. package/src/native-ui/desktop-control/dist/renderer-draft-prewarm-policy.js.map +1 -0
  280. package/src/native-ui/desktop-control/dist/renderer-draft-prewarm-runtime.d.ts +38 -0
  281. package/src/native-ui/desktop-control/dist/renderer-draft-prewarm-runtime.d.ts.map +1 -0
  282. package/src/native-ui/desktop-control/dist/renderer-draft-prewarm-runtime.js +637 -0
  283. package/src/native-ui/desktop-control/dist/renderer-draft-prewarm-runtime.js.map +1 -0
  284. package/src/native-ui/desktop-control/dist/tsconfig.tsbuildinfo +1 -0
  285. package/src/native-ui/desktop-control/package.json +22 -0
  286. package/src/native-ui/desktop-control/scripts/build-release.mjs +94 -0
  287. package/src/native-ui/desktop-control/src/cdp-client.ts +347 -0
  288. package/src/native-ui/desktop-control/src/contract-audit.ts +291 -0
  289. package/src/native-ui/desktop-control/src/controller-attachment-server.ts +93 -0
  290. package/src/native-ui/desktop-control/src/index.ts +91 -0
  291. package/src/native-ui/desktop-control/src/main-process-title-policy.ts +372 -0
  292. package/src/native-ui/desktop-control/src/production-controller.ts +347 -0
  293. package/src/native-ui/desktop-control/src/release-main.ts +18 -0
  294. package/src/native-ui/desktop-control/src/renderer-cdp-control-session.ts +358 -0
  295. package/src/native-ui/desktop-control/src/renderer-control-session.ts +595 -0
  296. package/src/native-ui/desktop-control/src/renderer-dom.ts +144 -0
  297. package/src/native-ui/desktop-control/src/renderer-draft-prewarm-policy.ts +217 -0
  298. package/src/native-ui/desktop-control/src/renderer-draft-prewarm-runtime.ts +749 -0
  299. package/src/native-ui/desktop-control/test/cdp-client.test.ts +157 -0
  300. package/src/native-ui/desktop-control/test/contract-audit.test.ts +56 -0
  301. package/src/native-ui/desktop-control/test/controller-attachment-server.test.ts +98 -0
  302. package/src/native-ui/desktop-control/test/index.test.ts +11 -0
  303. package/src/native-ui/desktop-control/test/main-process-title-policy.test.ts +168 -0
  304. package/src/native-ui/desktop-control/test/production-controller.test.ts +392 -0
  305. package/src/native-ui/desktop-control/test/renderer-cdp-control-session.test.ts +205 -0
  306. package/src/native-ui/desktop-control/test/renderer-control-session.test.ts +451 -0
  307. package/src/native-ui/desktop-control/test/renderer-dom.test.ts +62 -0
  308. package/src/native-ui/desktop-control/test/renderer-draft-prewarm-policy.test.ts +1029 -0
  309. package/src/native-ui/desktop-control/tsconfig.json +12 -0
  310. package/src/native-ui/renderer-extension/dist/types/agent-group-preference.d.ts +39 -0
  311. package/src/native-ui/renderer-extension/dist/types/agent-group-preference.d.ts.map +1 -0
  312. package/src/native-ui/renderer-extension/dist/types/agent-selection-state.d.ts +85 -0
  313. package/src/native-ui/renderer-extension/dist/types/agent-selection-state.d.ts.map +1 -0
  314. package/src/native-ui/renderer-extension/dist/types/audit-entry.d.ts +2 -0
  315. package/src/native-ui/renderer-extension/dist/types/audit-entry.d.ts.map +1 -0
  316. package/src/native-ui/renderer-extension/dist/types/codex-locale-adapter.d.ts +23 -0
  317. package/src/native-ui/renderer-extension/dist/types/codex-locale-adapter.d.ts.map +1 -0
  318. package/src/native-ui/renderer-extension/dist/types/collaboration-icon.d.ts +2 -0
  319. package/src/native-ui/renderer-extension/dist/types/collaboration-icon.d.ts.map +1 -0
  320. package/src/native-ui/renderer-extension/dist/types/contract-audit.d.ts +37 -0
  321. package/src/native-ui/renderer-extension/dist/types/contract-audit.d.ts.map +1 -0
  322. package/src/native-ui/renderer-extension/dist/types/harness-mix-icons.d.ts +3 -0
  323. package/src/native-ui/renderer-extension/dist/types/harness-mix-icons.d.ts.map +1 -0
  324. package/src/native-ui/renderer-extension/dist/types/harness-mix-settings.d.ts +3 -0
  325. package/src/native-ui/renderer-extension/dist/types/harness-mix-settings.d.ts.map +1 -0
  326. package/src/native-ui/renderer-extension/dist/types/index.d.ts +51 -0
  327. package/src/native-ui/renderer-extension/dist/types/index.d.ts.map +1 -0
  328. package/src/native-ui/renderer-extension/dist/types/install-renderer-binding.d.ts +4 -0
  329. package/src/native-ui/renderer-extension/dist/types/install-renderer-binding.d.ts.map +1 -0
  330. package/src/native-ui/renderer-extension/dist/types/probe-entry.d.ts +2 -0
  331. package/src/native-ui/renderer-extension/dist/types/probe-entry.d.ts.map +1 -0
  332. package/src/native-ui/renderer-extension/dist/types/production-entry.d.ts +9 -0
  333. package/src/native-ui/renderer-extension/dist/types/production-entry.d.ts.map +1 -0
  334. package/src/native-ui/renderer-extension/dist/types/renderer-agent-icon.d.ts +4 -0
  335. package/src/native-ui/renderer-extension/dist/types/renderer-agent-icon.d.ts.map +1 -0
  336. package/src/native-ui/renderer-extension/dist/types/renderer-agent-picker.d.ts +62 -0
  337. package/src/native-ui/renderer-extension/dist/types/renderer-agent-picker.d.ts.map +1 -0
  338. package/src/native-ui/renderer-extension/dist/types/renderer-binding-probe.d.ts +70 -0
  339. package/src/native-ui/renderer-extension/dist/types/renderer-binding-probe.d.ts.map +1 -0
  340. package/src/native-ui/renderer-extension/dist/types/renderer-codex-account-options.d.ts +34 -0
  341. package/src/native-ui/renderer-extension/dist/types/renderer-codex-account-options.d.ts.map +1 -0
  342. package/src/native-ui/renderer-extension/dist/types/renderer-codex-account-state.d.ts +19 -0
  343. package/src/native-ui/renderer-extension/dist/types/renderer-codex-account-state.d.ts.map +1 -0
  344. package/src/native-ui/renderer-extension/dist/types/renderer-collab-cards.d.ts +40 -0
  345. package/src/native-ui/renderer-extension/dist/types/renderer-collab-cards.d.ts.map +1 -0
  346. package/src/native-ui/renderer-extension/dist/types/renderer-composer-dom.d.ts +82 -0
  347. package/src/native-ui/renderer-extension/dist/types/renderer-composer-dom.d.ts.map +1 -0
  348. package/src/native-ui/renderer-extension/dist/types/renderer-credits-control.d.ts +21 -0
  349. package/src/native-ui/renderer-extension/dist/types/renderer-credits-control.d.ts.map +1 -0
  350. package/src/native-ui/renderer-extension/dist/types/renderer-external-steering.d.ts +7 -0
  351. package/src/native-ui/renderer-extension/dist/types/renderer-external-steering.d.ts.map +1 -0
  352. package/src/native-ui/renderer-extension/dist/types/renderer-fork-control.d.ts +34 -0
  353. package/src/native-ui/renderer-extension/dist/types/renderer-fork-control.d.ts.map +1 -0
  354. package/src/native-ui/renderer-extension/dist/types/renderer-harness-command-claim.d.ts +4 -0
  355. package/src/native-ui/renderer-extension/dist/types/renderer-harness-command-claim.d.ts.map +1 -0
  356. package/src/native-ui/renderer-extension/dist/types/renderer-harness-command-control.d.ts +15 -0
  357. package/src/native-ui/renderer-extension/dist/types/renderer-harness-command-control.d.ts.map +1 -0
  358. package/src/native-ui/renderer-extension/dist/types/renderer-harness-localization.d.ts +25 -0
  359. package/src/native-ui/renderer-extension/dist/types/renderer-harness-localization.d.ts.map +1 -0
  360. package/src/native-ui/renderer-extension/dist/types/renderer-harness-mentions.d.ts +23 -0
  361. package/src/native-ui/renderer-extension/dist/types/renderer-harness-mentions.d.ts.map +1 -0
  362. package/src/native-ui/renderer-extension/dist/types/renderer-model-client.d.ts +102 -0
  363. package/src/native-ui/renderer-extension/dist/types/renderer-model-client.d.ts.map +1 -0
  364. package/src/native-ui/renderer-extension/dist/types/renderer-model-picker-positioning.d.ts +22 -0
  365. package/src/native-ui/renderer-extension/dist/types/renderer-model-picker-positioning.d.ts.map +1 -0
  366. package/src/native-ui/renderer-extension/dist/types/renderer-model-picker.d.ts +54 -0
  367. package/src/native-ui/renderer-extension/dist/types/renderer-model-picker.d.ts.map +1 -0
  368. package/src/native-ui/renderer-extension/dist/types/renderer-new-thread-preference.d.ts +18 -0
  369. package/src/native-ui/renderer-extension/dist/types/renderer-new-thread-preference.d.ts.map +1 -0
  370. package/src/native-ui/renderer-extension/dist/types/renderer-permission-mode-picker.d.ts +42 -0
  371. package/src/native-ui/renderer-extension/dist/types/renderer-permission-mode-picker.d.ts.map +1 -0
  372. package/src/native-ui/renderer-extension/dist/types/renderer-permission-mode-preference.d.ts +9 -0
  373. package/src/native-ui/renderer-extension/dist/types/renderer-permission-mode-preference.d.ts.map +1 -0
  374. package/src/native-ui/renderer-extension/dist/types/renderer-request-sender.d.ts +9 -0
  375. package/src/native-ui/renderer-extension/dist/types/renderer-request-sender.d.ts.map +1 -0
  376. package/src/native-ui/renderer-extension/dist/types/renderer-session-import-client.d.ts +12 -0
  377. package/src/native-ui/renderer-extension/dist/types/renderer-session-import-client.d.ts.map +1 -0
  378. package/src/native-ui/renderer-extension/dist/types/renderer-settings-lifecycle.d.ts +18 -0
  379. package/src/native-ui/renderer-extension/dist/types/renderer-settings-lifecycle.d.ts.map +1 -0
  380. package/src/native-ui/renderer-extension/dist/types/renderer-sidebar-agent-icons.d.ts +45 -0
  381. package/src/native-ui/renderer-extension/dist/types/renderer-sidebar-agent-icons.d.ts.map +1 -0
  382. package/src/native-ui/renderer-extension/dist/types/renderer-transcript-dom.d.ts +23 -0
  383. package/src/native-ui/renderer-extension/dist/types/renderer-transcript-dom.d.ts.map +1 -0
  384. package/src/native-ui/renderer-extension/dist/types/renderer-trigger-chip-style.d.ts +3 -0
  385. package/src/native-ui/renderer-extension/dist/types/renderer-trigger-chip-style.d.ts.map +1 -0
  386. package/src/native-ui/renderer-extension/dist/types/renderer-usage-control.d.ts +72 -0
  387. package/src/native-ui/renderer-extension/dist/types/renderer-usage-control.d.ts.map +1 -0
  388. package/src/native-ui/renderer-extension/dist/types/settings/accounts-list.d.ts +24 -0
  389. package/src/native-ui/renderer-extension/dist/types/settings/accounts-list.d.ts.map +1 -0
  390. package/src/native-ui/renderer-extension/dist/types/settings/accounts-page.d.ts +18 -0
  391. package/src/native-ui/renderer-extension/dist/types/settings/accounts-page.d.ts.map +1 -0
  392. package/src/native-ui/renderer-extension/dist/types/settings/accounts-usage.d.ts +27 -0
  393. package/src/native-ui/renderer-extension/dist/types/settings/accounts-usage.d.ts.map +1 -0
  394. package/src/native-ui/renderer-extension/dist/types/settings/connections-page.d.ts +44 -0
  395. package/src/native-ui/renderer-extension/dist/types/settings/connections-page.d.ts.map +1 -0
  396. package/src/native-ui/renderer-extension/dist/types/settings/core.d.ts +38 -0
  397. package/src/native-ui/renderer-extension/dist/types/settings/core.d.ts.map +1 -0
  398. package/src/native-ui/renderer-extension/dist/types/settings/harness-accounts.d.ts +21 -0
  399. package/src/native-ui/renderer-extension/dist/types/settings/harness-accounts.d.ts.map +1 -0
  400. package/src/native-ui/renderer-extension/dist/types/settings/icons.d.ts +6 -0
  401. package/src/native-ui/renderer-extension/dist/types/settings/icons.d.ts.map +1 -0
  402. package/src/native-ui/renderer-extension/dist/types/settings/localization.d.ts +247 -0
  403. package/src/native-ui/renderer-extension/dist/types/settings/localization.d.ts.map +1 -0
  404. package/src/native-ui/renderer-extension/dist/types/settings/pages.d.ts +23 -0
  405. package/src/native-ui/renderer-extension/dist/types/settings/pages.d.ts.map +1 -0
  406. package/src/native-ui/renderer-extension/dist/types/settings/release-notes.d.ts +4 -0
  407. package/src/native-ui/renderer-extension/dist/types/settings/release-notes.d.ts.map +1 -0
  408. package/src/native-ui/renderer-extension/dist/types/settings/session-import-list-controls.d.ts +12 -0
  409. package/src/native-ui/renderer-extension/dist/types/settings/session-import-list-controls.d.ts.map +1 -0
  410. package/src/native-ui/renderer-extension/dist/types/settings/session-import-page.d.ts +8 -0
  411. package/src/native-ui/renderer-extension/dist/types/settings/session-import-page.d.ts.map +1 -0
  412. package/src/native-ui/renderer-extension/dist/types/settings/shell.d.ts +24 -0
  413. package/src/native-ui/renderer-extension/dist/types/settings/shell.d.ts.map +1 -0
  414. package/src/native-ui/renderer-extension/dist/types/settings/trigger.d.ts +45 -0
  415. package/src/native-ui/renderer-extension/dist/types/settings/trigger.d.ts.map +1 -0
  416. package/src/native-ui/renderer-extension/dist/types/settings/update-request.d.ts +6 -0
  417. package/src/native-ui/renderer-extension/dist/types/settings/update-request.d.ts.map +1 -0
  418. package/src/native-ui/renderer-extension/dist/types/tsconfig.tsbuildinfo +1 -0
  419. package/src/native-ui/renderer-extension/dist/types/versioned-renderer-adapter.d.ts +143 -0
  420. package/src/native-ui/renderer-extension/dist/types/versioned-renderer-adapter.d.ts.map +1 -0
  421. package/src/native-ui/renderer-extension/package.json +22 -0
  422. package/src/native-ui/renderer-extension/src/agent-group-preference.ts +174 -0
  423. package/src/native-ui/renderer-extension/src/agent-selection-state.ts +627 -0
  424. package/src/native-ui/renderer-extension/src/assets/README.md +13 -0
  425. package/src/native-ui/renderer-extension/src/assets/antigravity-agent.svg +1 -0
  426. package/src/native-ui/renderer-extension/src/assets/codex-agent.png +0 -0
  427. package/src/native-ui/renderer-extension/src/assets/grok-agent.png +0 -0
  428. package/src/native-ui/renderer-extension/src/assets/kiro-agent.svg +11 -0
  429. package/src/native-ui/renderer-extension/src/assets/omp-agent.svg +14 -0
  430. package/src/native-ui/renderer-extension/src/assets/opencode-agent.png +0 -0
  431. package/src/native-ui/renderer-extension/src/assets.d.ts +26 -0
  432. package/src/native-ui/renderer-extension/src/audit-entry.ts +5 -0
  433. package/src/native-ui/renderer-extension/src/codex-locale-adapter.ts +321 -0
  434. package/src/native-ui/renderer-extension/src/collaboration-icon.ts +13 -0
  435. package/src/native-ui/renderer-extension/src/contract-audit.ts +102 -0
  436. package/src/native-ui/renderer-extension/src/harness-mix-icons.ts +31 -0
  437. package/src/native-ui/renderer-extension/src/harness-mix-settings.ts +88 -0
  438. package/src/native-ui/renderer-extension/src/index.ts +275 -0
  439. package/src/native-ui/renderer-extension/src/install-renderer-binding.ts +30 -0
  440. package/src/native-ui/renderer-extension/src/probe-entry.ts +4 -0
  441. package/src/native-ui/renderer-extension/src/production-entry.ts +23 -0
  442. package/src/native-ui/renderer-extension/src/renderer-agent-icon.ts +146 -0
  443. package/src/native-ui/renderer-extension/src/renderer-agent-picker.ts +814 -0
  444. package/src/native-ui/renderer-extension/src/renderer-binding-probe.ts +3002 -0
  445. package/src/native-ui/renderer-extension/src/renderer-codex-account-options.ts +281 -0
  446. package/src/native-ui/renderer-extension/src/renderer-codex-account-state.ts +53 -0
  447. package/src/native-ui/renderer-extension/src/renderer-collab-cards.ts +198 -0
  448. package/src/native-ui/renderer-extension/src/renderer-composer-dom.ts +782 -0
  449. package/src/native-ui/renderer-extension/src/renderer-credits-control.ts +520 -0
  450. package/src/native-ui/renderer-extension/src/renderer-external-steering.ts +339 -0
  451. package/src/native-ui/renderer-extension/src/renderer-fork-control.ts +273 -0
  452. package/src/native-ui/renderer-extension/src/renderer-harness-command-claim.ts +64 -0
  453. package/src/native-ui/renderer-extension/src/renderer-harness-command-control.ts +417 -0
  454. package/src/native-ui/renderer-extension/src/renderer-harness-localization.ts +144 -0
  455. package/src/native-ui/renderer-extension/src/renderer-harness-mentions.ts +306 -0
  456. package/src/native-ui/renderer-extension/src/renderer-model-client.ts +572 -0
  457. package/src/native-ui/renderer-extension/src/renderer-model-picker-positioning.ts +65 -0
  458. package/src/native-ui/renderer-extension/src/renderer-model-picker.ts +640 -0
  459. package/src/native-ui/renderer-extension/src/renderer-new-thread-preference.ts +177 -0
  460. package/src/native-ui/renderer-extension/src/renderer-permission-mode-picker.ts +413 -0
  461. package/src/native-ui/renderer-extension/src/renderer-permission-mode-preference.ts +49 -0
  462. package/src/native-ui/renderer-extension/src/renderer-request-sender.ts +43 -0
  463. package/src/native-ui/renderer-extension/src/renderer-session-import-client.ts +68 -0
  464. package/src/native-ui/renderer-extension/src/renderer-settings-lifecycle.ts +239 -0
  465. package/src/native-ui/renderer-extension/src/renderer-sidebar-agent-icons.ts +457 -0
  466. package/src/native-ui/renderer-extension/src/renderer-transcript-dom.ts +47 -0
  467. package/src/native-ui/renderer-extension/src/renderer-trigger-chip-style.ts +52 -0
  468. package/src/native-ui/renderer-extension/src/renderer-usage-control.ts +633 -0
  469. package/src/native-ui/renderer-extension/src/settings/accounts-list.ts +236 -0
  470. package/src/native-ui/renderer-extension/src/settings/accounts-page.ts +585 -0
  471. package/src/native-ui/renderer-extension/src/settings/accounts-usage.ts +221 -0
  472. package/src/native-ui/renderer-extension/src/settings/accounts.css +683 -0
  473. package/src/native-ui/renderer-extension/src/settings/connections-page.ts +1394 -0
  474. package/src/native-ui/renderer-extension/src/settings/core.ts +158 -0
  475. package/src/native-ui/renderer-extension/src/settings/harness-accounts.ts +195 -0
  476. package/src/native-ui/renderer-extension/src/settings/icons.ts +141 -0
  477. package/src/native-ui/renderer-extension/src/settings/localization.ts +800 -0
  478. package/src/native-ui/renderer-extension/src/settings/pages.ts +632 -0
  479. package/src/native-ui/renderer-extension/src/settings/release-notes.ts +222 -0
  480. package/src/native-ui/renderer-extension/src/settings/session-import-list-controls.ts +128 -0
  481. package/src/native-ui/renderer-extension/src/settings/session-import-page.ts +461 -0
  482. package/src/native-ui/renderer-extension/src/settings/shell.css +2238 -0
  483. package/src/native-ui/renderer-extension/src/settings/shell.ts +329 -0
  484. package/src/native-ui/renderer-extension/src/settings/trigger.ts +323 -0
  485. package/src/native-ui/renderer-extension/src/settings/update-request.ts +49 -0
  486. package/src/native-ui/renderer-extension/src/versioned-renderer-adapter.ts +1289 -0
  487. package/src/native-ui/renderer-extension/test/agent-selection-state.test.ts +611 -0
  488. package/src/native-ui/renderer-extension/test/codebuddy-migration.test.ts +22 -0
  489. package/src/native-ui/renderer-extension/test/codex-locale-adapter.test.ts +152 -0
  490. package/src/native-ui/renderer-extension/test/contract-audit.test.ts +71 -0
  491. package/src/native-ui/renderer-extension/test/harness-mix-icons.test.ts +58 -0
  492. package/src/native-ui/renderer-extension/test/index.test.ts +9 -0
  493. package/src/native-ui/renderer-extension/test/renderer-agent-icon.test.ts +98 -0
  494. package/src/native-ui/renderer-extension/test/renderer-agent-picker.test.ts +226 -0
  495. package/src/native-ui/renderer-extension/test/renderer-binding-probe-host-catalog.test.ts +728 -0
  496. package/src/native-ui/renderer-extension/test/renderer-binding-probe.test.ts +1290 -0
  497. package/src/native-ui/renderer-extension/test/renderer-codex-account-state.test.ts +65 -0
  498. package/src/native-ui/renderer-extension/test/renderer-collab-cards.test.ts +45 -0
  499. package/src/native-ui/renderer-extension/test/renderer-composer-permissions.test.ts +75 -0
  500. package/src/native-ui/renderer-extension/test/renderer-credits-control.test.ts +70 -0
  501. package/src/native-ui/renderer-extension/test/renderer-external-steering-rpc.test.ts +184 -0
  502. package/src/native-ui/renderer-extension/test/renderer-external-steering.test.ts +279 -0
  503. package/src/native-ui/renderer-extension/test/renderer-fork-control.test.ts +363 -0
  504. package/src/native-ui/renderer-extension/test/renderer-harness-command-claim.test.ts +167 -0
  505. package/src/native-ui/renderer-extension/test/renderer-harness-command-control.test.ts +54 -0
  506. package/src/native-ui/renderer-extension/test/renderer-model-client.test.ts +709 -0
  507. package/src/native-ui/renderer-extension/test/renderer-model-picker.test.ts +302 -0
  508. package/src/native-ui/renderer-extension/test/renderer-native-thread-ownership.test.ts +84 -0
  509. package/src/native-ui/renderer-extension/test/renderer-new-thread-preference.test.ts +81 -0
  510. package/src/native-ui/renderer-extension/test/renderer-permission-mode-picker.test.ts +269 -0
  511. package/src/native-ui/renderer-extension/test/renderer-permission-mode-preference.test.ts +48 -0
  512. package/src/native-ui/renderer-extension/test/renderer-settings-lifecycle.test.ts +156 -0
  513. package/src/native-ui/renderer-extension/test/renderer-sidebar-agent-icons.test.ts +575 -0
  514. package/src/native-ui/renderer-extension/test/renderer-unsupported-methods.test.ts +167 -0
  515. package/src/native-ui/renderer-extension/test/renderer-usage-control.test.ts +96 -0
  516. package/src/native-ui/renderer-extension/test/settings/accounts-usage.test.ts +208 -0
  517. package/src/native-ui/renderer-extension/test/settings/core.test.ts +145 -0
  518. package/src/native-ui/renderer-extension/test/settings/harness-settings.test.ts +92 -0
  519. package/src/native-ui/renderer-extension/test/settings/localization.test.ts +80 -0
  520. package/src/native-ui/renderer-extension/test/settings/pages.test.ts +2000 -0
  521. package/src/native-ui/renderer-extension/test/settings/release-notes.test.ts +163 -0
  522. package/src/native-ui/renderer-extension/test/settings/shell.test.ts +74 -0
  523. package/src/native-ui/renderer-extension/test/settings/trigger.test.ts +270 -0
  524. package/src/native-ui/renderer-extension/test/settings/update-request.test.ts +48 -0
  525. package/src/native-ui/renderer-extension/test/versioned-renderer-adapter.test.ts +695 -0
  526. package/src/native-ui/renderer-extension/tsconfig.json +15 -0
  527. package/src/native-ui/shared-contracts/dist/codex-accounts.d.ts +246 -0
  528. package/src/native-ui/shared-contracts/dist/codex-accounts.d.ts.map +1 -0
  529. package/src/native-ui/shared-contracts/dist/codex-accounts.js +99 -0
  530. package/src/native-ui/shared-contracts/dist/codex-accounts.js.map +1 -0
  531. package/src/native-ui/shared-contracts/dist/deepseek-modern-sessions.d.ts +37 -0
  532. package/src/native-ui/shared-contracts/dist/deepseek-modern-sessions.d.ts.map +1 -0
  533. package/src/native-ui/shared-contracts/dist/deepseek-modern-sessions.js +36 -0
  534. package/src/native-ui/shared-contracts/dist/deepseek-modern-sessions.js.map +1 -0
  535. package/src/native-ui/shared-contracts/dist/errors.d.ts +17 -0
  536. package/src/native-ui/shared-contracts/dist/errors.d.ts.map +1 -0
  537. package/src/native-ui/shared-contracts/dist/errors.js +14 -0
  538. package/src/native-ui/shared-contracts/dist/errors.js.map +1 -0
  539. package/src/native-ui/shared-contracts/dist/external-thread-fork.d.ts +11 -0
  540. package/src/native-ui/shared-contracts/dist/external-thread-fork.d.ts.map +1 -0
  541. package/src/native-ui/shared-contracts/dist/external-thread-fork.js +14 -0
  542. package/src/native-ui/shared-contracts/dist/external-thread-fork.js.map +1 -0
  543. package/src/native-ui/shared-contracts/dist/harness-accounts.d.ts +78 -0
  544. package/src/native-ui/shared-contracts/dist/harness-accounts.d.ts.map +1 -0
  545. package/src/native-ui/shared-contracts/dist/harness-accounts.js +27 -0
  546. package/src/native-ui/shared-contracts/dist/harness-accounts.js.map +1 -0
  547. package/src/native-ui/shared-contracts/dist/harness-commands.d.ts +46 -0
  548. package/src/native-ui/shared-contracts/dist/harness-commands.d.ts.map +1 -0
  549. package/src/native-ui/shared-contracts/dist/harness-commands.js +61 -0
  550. package/src/native-ui/shared-contracts/dist/harness-commands.js.map +1 -0
  551. package/src/native-ui/shared-contracts/dist/harness-models.d.ts +300 -0
  552. package/src/native-ui/shared-contracts/dist/harness-models.d.ts.map +1 -0
  553. package/src/native-ui/shared-contracts/dist/harness-models.js +318 -0
  554. package/src/native-ui/shared-contracts/dist/harness-models.js.map +1 -0
  555. package/src/native-ui/shared-contracts/dist/harness-permission-modes.d.ts +30 -0
  556. package/src/native-ui/shared-contracts/dist/harness-permission-modes.d.ts.map +1 -0
  557. package/src/native-ui/shared-contracts/dist/harness-permission-modes.js +57 -0
  558. package/src/native-ui/shared-contracts/dist/harness-permission-modes.js.map +1 -0
  559. package/src/native-ui/shared-contracts/dist/harness-plugins.d.ts +56 -0
  560. package/src/native-ui/shared-contracts/dist/harness-plugins.d.ts.map +1 -0
  561. package/src/native-ui/shared-contracts/dist/harness-plugins.js +75 -0
  562. package/src/native-ui/shared-contracts/dist/harness-plugins.js.map +1 -0
  563. package/src/native-ui/shared-contracts/dist/harness-route.d.ts +16 -0
  564. package/src/native-ui/shared-contracts/dist/harness-route.d.ts.map +1 -0
  565. package/src/native-ui/shared-contracts/dist/harness-route.js +42 -0
  566. package/src/native-ui/shared-contracts/dist/harness-route.js.map +1 -0
  567. package/src/native-ui/shared-contracts/dist/harness-session-import.d.ts +54 -0
  568. package/src/native-ui/shared-contracts/dist/harness-session-import.d.ts.map +1 -0
  569. package/src/native-ui/shared-contracts/dist/harness-session-import.js +72 -0
  570. package/src/native-ui/shared-contracts/dist/harness-session-import.js.map +1 -0
  571. package/src/native-ui/shared-contracts/dist/ids.d.ts +12 -0
  572. package/src/native-ui/shared-contracts/dist/ids.d.ts.map +1 -0
  573. package/src/native-ui/shared-contracts/dist/ids.js +10 -0
  574. package/src/native-ui/shared-contracts/dist/ids.js.map +1 -0
  575. package/src/native-ui/shared-contracts/dist/index.d.ts +47 -0
  576. package/src/native-ui/shared-contracts/dist/index.d.ts.map +1 -0
  577. package/src/native-ui/shared-contracts/dist/index.js +29 -0
  578. package/src/native-ui/shared-contracts/dist/index.js.map +1 -0
  579. package/src/native-ui/shared-contracts/dist/json-rpc.d.ts +84 -0
  580. package/src/native-ui/shared-contracts/dist/json-rpc.d.ts.map +1 -0
  581. package/src/native-ui/shared-contracts/dist/json-rpc.js +65 -0
  582. package/src/native-ui/shared-contracts/dist/json-rpc.js.map +1 -0
  583. package/src/native-ui/shared-contracts/dist/json-value.d.ts +13 -0
  584. package/src/native-ui/shared-contracts/dist/json-value.d.ts.map +1 -0
  585. package/src/native-ui/shared-contracts/dist/json-value.js +60 -0
  586. package/src/native-ui/shared-contracts/dist/json-value.js.map +1 -0
  587. package/src/native-ui/shared-contracts/dist/native-refs.d.ts +43 -0
  588. package/src/native-ui/shared-contracts/dist/native-refs.d.ts.map +1 -0
  589. package/src/native-ui/shared-contracts/dist/native-refs.js +35 -0
  590. package/src/native-ui/shared-contracts/dist/native-refs.js.map +1 -0
  591. package/src/native-ui/shared-contracts/dist/reasoning-transcript.d.ts +7 -0
  592. package/src/native-ui/shared-contracts/dist/reasoning-transcript.d.ts.map +1 -0
  593. package/src/native-ui/shared-contracts/dist/reasoning-transcript.js +7 -0
  594. package/src/native-ui/shared-contracts/dist/reasoning-transcript.js.map +1 -0
  595. package/src/native-ui/shared-contracts/dist/thread-delegate.d.ts +22 -0
  596. package/src/native-ui/shared-contracts/dist/thread-delegate.d.ts.map +1 -0
  597. package/src/native-ui/shared-contracts/dist/thread-delegate.js +30 -0
  598. package/src/native-ui/shared-contracts/dist/thread-delegate.js.map +1 -0
  599. package/src/native-ui/shared-contracts/dist/thread-harness-switch.d.ts +16 -0
  600. package/src/native-ui/shared-contracts/dist/thread-harness-switch.d.ts.map +1 -0
  601. package/src/native-ui/shared-contracts/dist/thread-harness-switch.js +19 -0
  602. package/src/native-ui/shared-contracts/dist/thread-harness-switch.js.map +1 -0
  603. package/src/native-ui/shared-contracts/dist/thread-usage.d.ts +106 -0
  604. package/src/native-ui/shared-contracts/dist/thread-usage.d.ts.map +1 -0
  605. package/src/native-ui/shared-contracts/dist/thread-usage.js +103 -0
  606. package/src/native-ui/shared-contracts/dist/thread-usage.js.map +1 -0
  607. package/src/native-ui/shared-contracts/dist/tsconfig.tsbuildinfo +1 -0
  608. package/src/native-ui/shared-contracts/dist/updates.d.ts +128 -0
  609. package/src/native-ui/shared-contracts/dist/updates.d.ts.map +1 -0
  610. package/src/native-ui/shared-contracts/dist/updates.js +58 -0
  611. package/src/native-ui/shared-contracts/dist/updates.js.map +1 -0
  612. package/src/native-ui/shared-contracts/dist/version.d.ts +2 -0
  613. package/src/native-ui/shared-contracts/dist/version.d.ts.map +1 -0
  614. package/src/native-ui/shared-contracts/dist/version.js +2 -0
  615. package/src/native-ui/shared-contracts/dist/version.js.map +1 -0
  616. package/src/native-ui/shared-contracts/package.json +25 -0
  617. package/src/native-ui/shared-contracts/src/codex-accounts.ts +140 -0
  618. package/src/native-ui/shared-contracts/src/deepseek-modern-sessions.ts +67 -0
  619. package/src/native-ui/shared-contracts/src/errors.ts +25 -0
  620. package/src/native-ui/shared-contracts/src/external-thread-fork.ts +20 -0
  621. package/src/native-ui/shared-contracts/src/harness-accounts.ts +32 -0
  622. package/src/native-ui/shared-contracts/src/harness-commands.ts +81 -0
  623. package/src/native-ui/shared-contracts/src/harness-models.ts +406 -0
  624. package/src/native-ui/shared-contracts/src/harness-permission-modes.ts +73 -0
  625. package/src/native-ui/shared-contracts/src/harness-plugins.ts +96 -0
  626. package/src/native-ui/shared-contracts/src/harness-route.ts +47 -0
  627. package/src/native-ui/shared-contracts/src/harness-session-import.ts +90 -0
  628. package/src/native-ui/shared-contracts/src/ids.ts +20 -0
  629. package/src/native-ui/shared-contracts/src/index.ts +320 -0
  630. package/src/native-ui/shared-contracts/src/json-rpc.ts +80 -0
  631. package/src/native-ui/shared-contracts/src/json-value.ts +78 -0
  632. package/src/native-ui/shared-contracts/src/native-refs.ts +58 -0
  633. package/src/native-ui/shared-contracts/src/reasoning-transcript.ts +6 -0
  634. package/src/native-ui/shared-contracts/src/thread-delegate.ts +40 -0
  635. package/src/native-ui/shared-contracts/src/thread-harness-switch.ts +25 -0
  636. package/src/native-ui/shared-contracts/src/thread-usage.ts +126 -0
  637. package/src/native-ui/shared-contracts/src/updates.ts +78 -0
  638. package/src/native-ui/shared-contracts/src/version.ts +1 -0
  639. package/src/native-ui/shared-contracts/test/browser-bundle.test.ts +36 -0
  640. package/src/native-ui/shared-contracts/test/deepseek-modern-sessions.test.ts +120 -0
  641. package/src/native-ui/shared-contracts/test/errors.test.ts +72 -0
  642. package/src/native-ui/shared-contracts/test/harness-commands.test.ts +64 -0
  643. package/src/native-ui/shared-contracts/test/harness-models.test.ts +390 -0
  644. package/src/native-ui/shared-contracts/test/harness-permission-modes.test.ts +134 -0
  645. package/src/native-ui/shared-contracts/test/harness-plugins.test.ts +113 -0
  646. package/src/native-ui/shared-contracts/test/harness-session-import.test.ts +117 -0
  647. package/src/native-ui/shared-contracts/test/ids.test.ts +69 -0
  648. package/src/native-ui/shared-contracts/test/index.test.ts +80 -0
  649. package/src/native-ui/shared-contracts/test/json-rpc.test.ts +177 -0
  650. package/src/native-ui/shared-contracts/test/json-value.test.ts +62 -0
  651. package/src/native-ui/shared-contracts/test/native-refs.test.ts +95 -0
  652. package/src/native-ui/shared-contracts/test/thread-usage.test.ts +115 -0
  653. package/src/native-ui/shared-contracts/test/updates.test.ts +120 -0
  654. package/src/native-ui/shared-contracts/tsconfig.json +10 -0
  655. package/src/tsconfig.base.json +19 -0
@@ -0,0 +1,836 @@
1
+ // Projection boundary only. Execution, persistence and native approvals belong
2
+ // to Harness Mix HostRuntime / ProtocolCore and their existing adapters.
3
+ const { getHarnessSvg } = require('./icons');
4
+ const { prepareInput } = require('./input');
5
+ const { projectUsage, projectAccountCredits } = require('./usage');
6
+ const { exec } = require('node:child_process');
7
+ const os = require('node:os');
8
+ const fs = require('node:fs');
9
+ const path = require('node:path');
10
+ const { randomUUID } = require('node:crypto');
11
+ const { diff } = require('../workspace/diff');
12
+ const {
13
+ fetchLatestVersion,
14
+ remoteState,
15
+ runUpdateFlow,
16
+ resolveRegistry,
17
+ } = require('./updater');
18
+ const {
19
+ detectChannel,
20
+ compareVersions,
21
+ readState,
22
+ } = require('./update-state');
23
+ const { nativeEnvironment } = require('./config');
24
+
25
+ const REPO_ROOT = path.resolve(__dirname, '../../..');
26
+ const PACKAGE_JSON_PATH = path.join(REPO_ROOT, 'package.json');
27
+
28
+ const ALIASES = { workbuddy: 'codebuddy', 'claude-code': 'claude', 'deepseek-harness': 'dsh', 'codex-harness': 'codex' };
29
+ const externalId = id => ({ workbuddy: 'codebuddy', claude: 'claude-code', dsh: 'deepseek-harness', codex: 'codex-harness' }[id] || id);
30
+ const modelRef = model => ({ id: Buffer.from(JSON.stringify({ id: model.id, provider: model.provider })).toString('base64url') });
31
+ const routeModel = harnessId => ['pi', 'claude-code', 'deepseek-harness', 'antigravity', 'omp', 'opencode', 'grok'].includes(harnessId)
32
+ ? `codexhost/${harnessId}-native`
33
+ : `codexhost/plugin-v1@${Buffer.from(JSON.stringify({ harnessId })).toString('hex')}`;
34
+ const terminal = status => ['completed', 'cancelled', 'error', 'failed'].includes(status);
35
+ const turnStatus = status => ({ cancelled: 'interrupted', error: 'failed', failed: 'failed', completed: 'completed' }[status] || 'inProgress');
36
+
37
+ const HARNESS_INSTALL_COMMANDS = {
38
+ qoder: { win32: 'npm install -g @qoder-ai/qodercli', default: 'npm install -g @qoder-ai/qodercli' },
39
+ codex: { win32: 'npm install -g @openai/codex', default: 'npm install -g @openai/codex' },
40
+ 'codex-harness': { win32: 'npm install -g @openai/codex', default: 'npm install -g @openai/codex' },
41
+ pi: { win32: 'npm install -g @mariozechner/pi-coding-agent', default: 'npm install -g @mariozechner/pi-coding-agent' },
42
+ 'claude-code': { win32: 'npm install -g @anthropic-ai/claude-code', default: 'npm install -g @anthropic-ai/claude-code' },
43
+ 'deepseek-harness': { win32: 'pip install deepseek-harness', default: 'pip3 install deepseek-harness' },
44
+ opencode: { win32: 'npm install -g opencode-ai', default: 'npm install -g opencode-ai' },
45
+ grok: { win32: 'npm install -g @xai/grok-cli', default: 'npm install -g @xai/grok-cli' },
46
+ omp: { win32: 'npm install -g @oh-my-pi/pi-coding-agent', default: 'npm install -g @oh-my-pi/pi-coding-agent' },
47
+ antigravity: { win32: 'npm install -g @google/antigravity-cli', default: 'npm install -g @google/antigravity-cli' },
48
+ openclaw: { win32: 'npm install -g openclaw', default: 'npm install -g openclaw' },
49
+ hermes: { win32: 'pip install hermes-agent', default: 'pip3 install hermes-agent' },
50
+ };
51
+
52
+ const HARNESS_AUTH_INFO = {
53
+ codex: { name: 'Codex', plan: 'OpenAI / Codex Desktop', label: 'Codex Desktop 内置登录', loginCommand: 'codex login', configHint: 'Codex 官方桌面客户端内置登录状态' },
54
+ 'claude-code': { name: 'Claude Code', plan: 'Anthropic Claude', label: 'Claude Code 授权', loginCommand: 'claude login', configHint: '~/.claude.json 或环境变量 ANTHROPIC_API_KEY' },
55
+ 'deepseek-harness': { name: 'DeepSeek Harness', plan: 'DeepSeek API', label: 'DeepSeek API Key', loginCommand: null, configHint: '环境变量 DEEPSEEK_API_KEY' },
56
+ antigravity: { name: 'Antigravity CLI', plan: 'Google Gemini', label: 'Google Cloud ADC 认证', loginCommand: 'gcloud auth application-default login', configHint: 'Google Application Default Credentials (ADC) 或 gcloud 认证' },
57
+ pi: { name: 'Pi', plan: 'Pi Multi-Provider', label: 'Pi 模型凭据配置', loginCommand: null, configHint: '~/.pi/agent/settings.json 或各模型提供商 API Key' },
58
+ omp: { name: 'Oh My Pi', plan: 'Oh My Pi', label: 'OMP 模型凭据配置', loginCommand: null, configHint: '~/.omp/ 配置文件或各 Provider API 密钥' },
59
+ grok: { name: 'Grok', plan: 'xAI Grok', label: 'xAI API Key', loginCommand: null, configHint: '环境变量 XAI_API_KEY' },
60
+ opencode: { name: 'OpenCode', plan: 'OpenCode Providers', label: 'OpenCode Provider 配置', loginCommand: null, configHint: '~/.opencode/ 配置文件' },
61
+ openclaw: { name: 'OpenClaw', plan: 'OpenClaw Gateway', label: 'OpenClaw Token 认证', loginCommand: null, configHint: '环境变量 OPENCLAW_TOKEN 或 gateway.auth 配置' },
62
+ 'kiro-cli': { name: 'Kiro', plan: 'AWS / Kiro CLI', label: 'Kiro CLI 授权', loginCommand: 'kiro auth login', configHint: '命令行 kiro auth login 或 ~/.kiro/ 目录' },
63
+ 'cursor-cli': { name: 'Cursor', plan: 'Cursor Account', label: 'Cursor 账号认证', loginCommand: 'cursor-cli auth login', configHint: 'Cursor 客户端或 cursor-cli auth 登录' },
64
+ qoder: { name: 'Qoder', plan: 'Qoder AI', label: 'Qoder CLI 认证', loginCommand: 'qoder auth login', configHint: '命令行 qoder auth login 或 ~/.qoder/ 配置' },
65
+ codebuddy: { name: 'CodeBuddy', plan: 'CodeBuddy AI', label: 'CodeBuddy 凭据', loginCommand: null, configHint: 'CodeBuddy 客户端或环境变量配置' },
66
+ hermes: { name: 'Hermes', plan: 'Nous Hermes', label: 'Hermes Agent 配置', loginCommand: null, configHint: '~/.hermes/ 配置文件或各模型 API Key' },
67
+ zcode: { name: 'ZCode', plan: 'ZCode AI', label: 'ZCode 账号与配置', loginCommand: null, configHint: 'ZCode 客户端或配置文件' },
68
+ trae: { name: 'Trae', plan: 'Trae AI', label: 'Trae 账号与配置', loginCommand: null, configHint: 'Trae 客户端登录状态' },
69
+ };
70
+
71
+ const MODEL_REF_ID = /^[A-Za-z0-9._~-]{1,512}$/;
72
+ // Positional suffix contract of the versioned Renderer adapter transport ids.
73
+ // Mirrors transportModelId()/decode*TransportModelId() in
74
+ // src/native-ui/renderer-extension/src/versioned-renderer-adapter.ts exactly.
75
+ const LEGACY_SUFFIX_FIELDS = {
76
+ pi: ['model', 'thinkingOptionId'],
77
+ 'claude-code': ['model', 'permissionModeId', 'thinkingOptionId'],
78
+ 'deepseek-harness': ['model', 'permissionModeId'],
79
+ antigravity: ['model', 'permissionModeId', 'thinkingOptionId'],
80
+ opencode: ['model', 'permissionModeId', 'thinkingOptionId'],
81
+ grok: ['model', 'permissionModeId', 'thinkingOptionId'],
82
+ // OMP(Pi 家族):两段式是 model@thinking,三段式才是 model@permission@thinking
83
+ omp: ['model', 'thinkingOptionId'],
84
+ };
85
+
86
+ function decodeLegacySuffix(harnessId, suffix) {
87
+ const fields = LEGACY_SUFFIX_FIELDS[harnessId];
88
+ const parts = suffix.split('@');
89
+ if (parts.length > 3) throw new Error('Invalid native Harness route');
90
+ // OMP 特例:三段式 model@permission@thinking(中间槽可为空),两段式 model@thinking
91
+ if (harnessId === 'omp' && parts.length === 3) return decodePositional(harnessId, ['model', 'permissionModeId', 'thinkingOptionId'], parts);
92
+ if (parts.length > fields.length) throw new Error('Invalid native Harness route');
93
+ return decodePositional(harnessId, fields, parts);
94
+ }
95
+
96
+ function decodePositional(harnessId, fields, parts) {
97
+ const route = { harnessId };
98
+ parts.forEach((part, index) => {
99
+ // Optional middle slots may be empty (e.g. model@@thinkingOption).
100
+ if (!part) return;
101
+ const field = fields[index];
102
+ if (field === 'model') {
103
+ if (!MODEL_REF_ID.test(part)) throw new Error('Invalid native Harness route');
104
+ route.model = { id: part };
105
+ } else {
106
+ route[field] = part;
107
+ }
108
+ });
109
+ return route;
110
+ }
111
+
112
+ function decodeRoute(model) {
113
+ if (typeof model !== 'string') return null;
114
+ if (model.startsWith('codexhost/plugin-v1@')) {
115
+ const hex = model.slice('codexhost/plugin-v1@'.length);
116
+ if (model.length > 4096 || !/^(?:[a-f0-9]{2})+$/.test(hex)) throw new Error('Invalid native Harness route');
117
+ const route = JSON.parse(Buffer.from(hex, 'hex').toString());
118
+ if (!route.harnessId || route.harnessId === 'codex') throw new Error('Invalid external Harness');
119
+ return route;
120
+ }
121
+ const legacy = /^codexhost\/(pi|claude-code|deepseek-harness|antigravity|omp|opencode|grok)-native(?:@(.+))?$/.exec(model);
122
+ if (!legacy) return null;
123
+ return legacy[2] === undefined ? { harnessId: legacy[1] } : decodeLegacySuffix(legacy[1], legacy[2]);
124
+ }
125
+
126
+ // file_change 的 diff 载体有三种形态:字符串 unified diff(codex 原生)、
127
+ // workspace/diff 的结果对象 {rows}(canonicalChanges/审查快照)、或裸 before/after。
128
+ // 统一规范化为完整 git 风格 unified diff:Desktop 以 `diff --git a/x b/x` 头切分文件并
129
+ // 提取干净路径,且只在 `@@` hunk 头之后才开始计数增删行——两者缺失都会显示 +0 -0。
130
+ function unifiedBody(change) {
131
+ if (typeof change.diff === 'string' && change.diff.trim()) return change.diff;
132
+ if (typeof change.patch === 'string' && change.patch.trim()) return change.patch;
133
+ const rows = Array.isArray(change.patch?.rows) ? change.patch.rows
134
+ : (typeof change.before === 'string' || typeof change.after === 'string') ? diff(change.before || '', change.after || '').rows
135
+ : null;
136
+ if (!rows?.length) return '';
137
+ const removed = rows.filter(row => row.kind !== 'add').length;
138
+ const added = rows.filter(row => row.kind !== 'remove').length;
139
+ const hunk = `@@ -${removed ? `1,${removed}` : '0,0'} +${added ? `1,${added}` : '0,0'} @@`;
140
+ return [hunk, ...rows.map(row => (row.kind === 'add' ? '+' : row.kind === 'remove' ? '-' : ' ') + row.text)].join('\n');
141
+ }
142
+
143
+ function unifiedDiff(change, kindType) {
144
+ const body = unifiedBody(change);
145
+ if (/^diff --git /m.test(body)) return body; // 已是完整 unified diff,原样透传
146
+ const file = change.path || change.file || '';
147
+ const headers = kindType === 'add' ? ['--- /dev/null', `+++ b/${file}`]
148
+ : kindType === 'delete' ? [`--- a/${file}`, '+++ /dev/null']
149
+ : [`--- a/${file}`, `+++ b/${file}`];
150
+ return [`diff --git a/${file} b/${file}`, ...(/^---\s/m.test(body) ? [] : headers), body].filter(Boolean).join('\n');
151
+ }
152
+
153
+ function projectItem(item) {
154
+ const base = { id: item.id };
155
+ if (item.type === 'user_message') return { ...base, type: 'userMessage', content: [
156
+ { type: 'text', text: item.content || '', text_elements: [] },
157
+ ...(item.attachments || []).filter(a => a.kind === 'image').map(a => a.data
158
+ ? { type: 'image', url: `data:${a.mime || 'image/png'};base64,${a.data}` }
159
+ : a.path ? { type: 'localImage', path: a.path } : { type: 'text', text: `[图片:${a.name}]`, text_elements: [] }),
160
+ ] };
161
+ if (item.type === 'agent_message' || item.type === 'notice') return { ...base, type: 'agentMessage', text: item.content || '', phase: item.phase || 'final' };
162
+ if (item.type === 'reasoning') return { ...base, type: 'reasoning', summary: [item.content || ''], content: [] };
163
+ if (item.type === 'tool_call' && item.collaboration) {
164
+ const job = item.collaboration;
165
+ const status = ({ completed: 'completed', failed: 'errored', cancelled: 'interrupted', interrupted: 'interrupted' })[job.status] || 'running';
166
+ return { ...base, type: 'collabAgentToolCall', tool: job.operation || 'spawnAgent',
167
+ status: terminal(item.status) ? (item.state === 'error' ? 'failed' : 'completed') : 'inProgress',
168
+ senderThreadId: job.parent_thread_id, receiverThreadIds: job.child_thread_id ? [job.child_thread_id] : [],
169
+ prompt: job.task || null, model: null, reasoningEffort: null,
170
+ childThreadId: job.child_thread_id || null, agentType: job.agent_type || null,
171
+ diff: job.diff || null, digest: job.digest || null,
172
+ branch: job.branch || job.workspace?.branch || null,
173
+ workspaceMode: job.workspace?.mode || 'shared',
174
+ applied: !!job.appliedDigest || !!job.applied,
175
+ agentsStates: job.child_thread_id ? { [job.child_thread_id]: { status,
176
+ message: job.attention?.message || job.attention?.title || job.result || job.error || null } } : {} };
177
+ }
178
+ if (item.type === 'tool_call') return { ...base, type: 'mcpToolCall', server: 'harness-mix', tool: item.title || 'tool',
179
+ arguments: item.input || {}, status: terminal(item.status) ? (item.state === 'error' ? 'failed' : 'completed') : 'inProgress',
180
+ result: item.output ? { content: [{ type: 'text', text: String(item.output) }], structuredContent: null } : null,
181
+ error: item.state === 'error' ? { message: String(item.output || item.detail || 'Tool failed') } : null, durationMs: null };
182
+ if (item.type === 'file_change') return { ...base, type: 'fileChange', status: terminal(item.status) ? 'completed' : 'inProgress',
183
+ changes: (item.changes || [item]).map(change => {
184
+ const kind = change.changeType === 'deleted' ? { type: 'delete' } : change.changeType === 'added' ? { type: 'add' } : { type: 'update', move_path: null };
185
+ return { path: change.path || change.file || '', kind, diff: unifiedDiff(change, kind.type) };
186
+ }) };
187
+ if (item.type === 'context_compaction' || item.type === 'contextCompaction') return { ...base, type: 'contextCompaction' };
188
+ return null;
189
+ }
190
+
191
+ class NativeProtocol {
192
+ constructor(runtime, emit, requestOfficial = null) {
193
+ this.runtime = runtime;
194
+ this.emit = emit;
195
+ this.requestOfficial = requestOfficial;
196
+ this.approvals = new Map();
197
+ this.published = new Map();
198
+ this.steering = new Map(); // threadId -> in-flight steer promise
199
+ this.steerReceipts = new Map(); // `${threadId}\0${clientUserMessageId}` -> bounded delivery receipt
200
+ this.unsubscribe = runtime.core.subscribe(({ event, projected }) => this.onCore(event, projected));
201
+ // Host 侧新建的线程(协作子任务等)也要通知 Desktop 侧栏,与 thread/start 同一契约
202
+ this.unsubscribeRuntime = runtime.subscribe(event => {
203
+ if (event?.type === 'thread-created' && event.thread) this.emit({ method: 'thread/started', params: { thread: this.projectThread(event.thread) } });
204
+ if (event?.type === 'thread-updated' && event.thread) {
205
+ this.emit({ method: 'thread/name/updated', params: { threadId: event.thread.id, threadName: event.thread.title } });
206
+ }
207
+ });
208
+ }
209
+ thread(id) { return this.runtime.threads.find(t => t.id === id); }
210
+ owns(id) { return Boolean(this.thread(id)); }
211
+ turn(turn) { return { id: turn.id, status: turnStatus(turn.status), error: turn.error ? { message: String(turn.error), codexErrorInfo: null, additionalDetails: null } : null,
212
+ items: this.runtime.core.getItemsForTurn(turn.id).map(projectItem).filter(Boolean) }; }
213
+ projectThread(thread, includeTurns = true) {
214
+ // Projection shape mirrors the upstream codexhost external-thread contract: every
215
+ // field the Desktop sidebar/composer reads must be present with the same defaults.
216
+ const updatedAt = Math.floor((thread.updatedAt || thread.createdAt) / 1000);
217
+ return { id: thread.id, preview: thread.messages.find(m => m.role === 'user')?.text || thread.title,
218
+ ephemeral: thread.ephemeral === true, modelProvider: 'codexhost', model: routeModel(externalId(thread.harnessId)), reasoningEffort: null,
219
+ section: thread.section ?? null, sectionEnteredAt: thread.sectionEnteredAt ?? null, projectId: thread.projectId ?? null,
220
+ createdAt: Math.floor(thread.createdAt / 1000),
221
+ updatedAt, recencyAt: updatedAt,
222
+ status: { type: thread.status === 'working' ? 'active' : 'idle', ...(thread.status === 'working' ? { activeFlags: [] } : {}) },
223
+ path: null, cwd: thread.cwd, cliVersion: 'codexhost', source: 'vscode', threadSource: null,
224
+ name: thread.title || null, agentNickname: thread.parentThreadId ? this.runtime.adapters.get(thread.harnessId)?.manifest.name || thread.harnessId : null,
225
+ agentRole: thread.parentThreadId ? 'worker' : null, gitInfo: thread.gitInfo || null,
226
+ sessionId: thread.id, forkedFromId: thread.forkedFrom ?? null, parentThreadId: thread.parentThreadId ?? null,
227
+ // 跨 Harness 原地切换血缘:链上每条是某 Harness 曾用的原生会话引用(切回可 resume)
228
+ harnessChain: (thread.harnessChain ?? []).map(e => ({ harnessId: externalId(e.harnessId), at: e.at })),
229
+ pendingHarnessSwitch: thread.pendingHandoff ? { fromHarnessId: externalId(thread.pendingHandoff.fromHarnessId), note: thread.pendingHandoff.note ?? null } : null,
230
+ canAcceptDirectInput: true, historyMode: 'legacy', isPinned: false, extra: null,
231
+ isolation: thread.isolation ?? 'shared',
232
+ workspace: thread.workspace ? { mode: thread.workspace.mode, branch: thread.workspace.branch, root: thread.workspace.root } : null,
233
+ turns: includeTurns ? this.runtime.core.turns.turnsForThread(thread.id).map(t => this.turn(t)) : [] };
234
+ }
235
+ capabilities(id, catalog) {
236
+ const cap = this.runtime.getCapabilities(id);
237
+ return { configuration: { selectModel: Boolean(cap.model?.selection), selectThinkingOption: Boolean(cap.model?.thinkingLevel),
238
+ selectPermissionMode: Boolean(catalog.permissionModes?.length), permissionModeScope: 'live' },
239
+ history: { fork: Boolean(cap.session?.fork), forkAcrossCwd: false, rollbackLastTurn: Boolean(cap.session?.forkFromMessage) } };
240
+ }
241
+ async inspect(id) {
242
+ const local = ALIASES[id] || id;
243
+ if (!this.runtime.adapters.has(local)) return { status: 'notInstalled', error: { code: 'UNSUPPORTED', message: `Harness Mix has no adapter for ${id}`, retryable: false } };
244
+ if (!this.runtime.status[local]?.available) return { status: 'unavailable', error: { code: 'UNAVAILABLE', message: this.runtime.status[local]?.detail || 'Harness unavailable', retryable: true } };
245
+ try {
246
+ let catalog = await this.runtime.describe(local);
247
+ if (catalog.models === null) {
248
+ const adapter = this.runtime.adapters.get(local);
249
+ const probe = await adapter.open({ thread: { cwd: os.tmpdir(), nativeSessionId: randomUUID(), options: {} }, emit: () => {}, diagnostic: () => {} });
250
+ try { catalog = await adapter.describeFor(probe); this.runtime.catalogs.set(local, catalog); }
251
+ finally { await adapter.close(probe); }
252
+ }
253
+ const thinkingOptions = (catalog.thinkingLevels || []).map(x => ({ id: x.id, label: x.label || x.id }));
254
+ const levelId = entry => (typeof entry === 'string' ? entry : entry?.id);
255
+ // 模型级 efforts(Claude/DSH/OpenCode 按模型声明)并入全局档位表(共享契约要求 supported ⊆ thinkingOptions)
256
+ for (const sourceModel of catalog.models || []) {
257
+ for (const entry of sourceModel.efforts || []) {
258
+ const id = levelId(entry);
259
+ if (id && !thinkingOptions.some(o => o.id === id)) {
260
+ thinkingOptions.push({ id, label: (typeof entry === 'object' && entry?.label) || id });
261
+ }
262
+ }
263
+ }
264
+ // adapter 可在 thinkingLevels 某一项上声明 default: true(如 Antigravity 的 high),
265
+ // 作为该 Harness 的安全预选档;未声明则不预选,由原生会话自身默认档生效。
266
+ const defaultThinking = (catalog.thinkingLevels || []).find(x => x.default === true)?.id;
267
+ const thinkingIds = thinkingOptions.map(o => o.id);
268
+ const sourceModels = catalog.models || [];
269
+ const models = sourceModels.map(m => {
270
+ // 模型显式声明了 efforts(含空数组)以模型为准;未声明则适用全部全局档位
271
+ const supported = Array.isArray(m.efforts)
272
+ ? m.efforts.map(levelId).filter(id => id && thinkingIds.includes(id))
273
+ : thinkingIds;
274
+ return { ref: modelRef(m), label: m.name || m.id,
275
+ ...(supported.length ? { supportedThinkingOptionIds: supported } : {}) };
276
+ });
277
+ // The renderer draft flow requires a default model for its initial selection.
278
+ const defaultSource = sourceModels.find(m => m && m.isDefault === true) || sourceModels[0];
279
+ const result = { status: 'ready', catalog: { models, ...(defaultSource ? { defaultModel: modelRef(defaultSource) } : {}), thinkingOptions,
280
+ ...(defaultThinking ? { defaultThinkingOptionId: defaultThinking } : {}) }, capabilities: this.capabilities(local, catalog) };
281
+ if (catalog.permissionModes?.length) result.permissionModes = { modes: catalog.permissionModes.map(m => ({ id: m.id, label: m.label || m.name || m.id, ...((m.description || m.hint) ? { description: m.description || m.hint } : {}) })), defaultModeId: catalog.permissionModes.find(m => m.default)?.id || catalog.permissionModes[0].id };
282
+ return result;
283
+ } catch (error) { return { status: 'error', error: { code: 'INSPECTION_FAILED', message: error.message, retryable: true } }; }
284
+ }
285
+ configuration(thread) {
286
+ const catalogEntry = this.runtime.catalogs?.get(thread.harnessId);
287
+ const models = catalogEntry?.models || thread.models || [];
288
+ const configured = thread.options?.model;
289
+ const actual = thread.model;
290
+ const exact = candidate => candidate && models.find(model => modelRef(model).id === modelRef(candidate).id);
291
+ // Native runtime names can be resolved aliases, and older Pi records omitted
292
+ // their provider. Prefer the explicitly selected catalog identity, then a
293
+ // unique native match; never guess between providers with the same model id.
294
+ const matches = actual ? models.filter(model => model.id === actual.id && (!actual.provider || model.provider === actual.provider)) : [];
295
+ const selected = exact(configured) || exact(actual) || (matches.length === 1 ? matches[0] : null) || actual || configured;
296
+ // 当前模型适用的思考档位:模型声明了 efforts 以模型为准,否则适用全局目录
297
+ const levelId = entry => (typeof entry === 'string' ? entry : entry?.id);
298
+ const globalLevels = (catalogEntry?.thinkingLevels || []).map(l => ({ id: l.id, label: l.label || l.id }));
299
+ const selectedEntry = selected ? models.find(m => m.id === selected.id && (!selected.provider || !m.provider || m.provider === selected.provider)) : null;
300
+ const thinkingOptions = Array.isArray(selectedEntry?.efforts)
301
+ ? selectedEntry.efforts.map(entry => {
302
+ const id = levelId(entry);
303
+ return id ? { id, label: (typeof entry === 'object' && entry?.label) || id } : null;
304
+ }).filter(Boolean)
305
+ : globalLevels;
306
+ const thinking = thread.options?.thinking;
307
+ return { ...(selected ? { effectiveModel: modelRef(selected) } : {}),
308
+ // 可选集合存在时,生效档位必须属于其中(共享契约校验);目录未加载时保留原样
309
+ ...(thinking && (!thinkingOptions.length || thinkingOptions.some(o => o.id === thinking)) ? { effectiveThinkingOptionId: thinking } : {}),
310
+ ...(thinkingOptions.length ? { availableThinkingOptions: thinkingOptions } : {}),
311
+ ...(thread.options?.permissionMode ? { effectivePermissionModeId: thread.options.permissionMode } : {}) };
312
+ }
313
+ async resolveModel(harnessId, ref) {
314
+ if (!ref) return undefined;
315
+ const catalog = await this.runtime.describe(harnessId);
316
+ const model = catalog.models.find(m => modelRef(m).id === ref.id);
317
+ if (!model) throw new Error('Selected model is no longer in the native catalog');
318
+ return model;
319
+ }
320
+ async request(method, params = {}) {
321
+ if (method === 'codexhost/harness/session-import/sources') return this.runtime.history.sources();
322
+ if (method === 'codexhost/harness/session-import/list') return this.runtime.history.list(params);
323
+ if (method === 'codexhost/harness/session-import/import') return this.runtime.history.import(params);
324
+ if (method === 'codexhost/collaboration/agents') return [...this.runtime.adapters.values()].map(a => ({ id: externalId(a.manifest.id), name: a.manifest.name, available: !!this.runtime.status[a.manifest.id]?.available, lead: a.manifest.capabilities?.collaborationTools === true }));
325
+ const thread = this.thread(params.threadId);
326
+ if (method === 'harness-mix/runtime/inspect') return { owner: 'harness-mix', runtime: 'src/main/host/runtime.js', core: 'src/main/protocol-core/protocol-core.js', threads: this.runtime.threads.length };
327
+ // Updates
328
+ if (method === 'codexhost/update/check') {
329
+ const dataDir = nativeEnvironment().CODEXHOST_DATA_DIR;
330
+ let currentVersion = '0.1.2';
331
+ try {
332
+ currentVersion = JSON.parse(fs.readFileSync(PACKAGE_JSON_PATH, 'utf8')).version || '0.1.2';
333
+ } catch { /* fallback */ }
334
+ const channel = detectChannel(REPO_ROOT);
335
+ let latestVersion = currentVersion;
336
+ let updateAvailable = false;
337
+ let checkError = null;
338
+
339
+ if (channel === 'git') {
340
+ try {
341
+ const remote = remoteState(REPO_ROOT);
342
+ if (remote.state === 'available') {
343
+ updateAvailable = true;
344
+ latestVersion = `${currentVersion}+git.${remote.remote.slice(0, 7)}`;
345
+ } else {
346
+ latestVersion = currentVersion;
347
+ }
348
+ } catch (err) {
349
+ checkError = err.message;
350
+ }
351
+ } else {
352
+ try {
353
+ const fetched = await fetchLatestVersion({
354
+ registry: resolveRegistry(),
355
+ dataDir,
356
+ timeoutMs: 6000,
357
+ });
358
+ if (fetched) {
359
+ latestVersion = fetched;
360
+ updateAvailable = compareVersions(latestVersion, currentVersion) > 0;
361
+ }
362
+ } catch (err) {
363
+ checkError = err.message;
364
+ }
365
+ }
366
+
367
+ return {
368
+ currentVersion,
369
+ installation: channel === 'npm' ? 'npm' : 'windows-installer',
370
+ latestVersion,
371
+ updateAvailable,
372
+ installationAvailable: true,
373
+ releaseNotes: updateAvailable ? `发现新版本 ${latestVersion},支持自动快进更新与安全回滚。` : null,
374
+ releaseNotesUrl: `https://github.com/emo-xiaoyu/harness-mix/releases/tag/v${currentVersion}`,
375
+ status: null,
376
+ error: checkError ? `更新检查失败: ${checkError.slice(0, 450)}` : null,
377
+ };
378
+ }
379
+ if (method === 'codexhost/update/start') {
380
+ const dataDir = nativeEnvironment().CODEXHOST_DATA_DIR;
381
+ const channel = detectChannel(REPO_ROOT);
382
+ let currentVersion = '0.1.2';
383
+ try { currentVersion = JSON.parse(fs.readFileSync(PACKAGE_JSON_PATH, 'utf8')).version || '0.1.2'; } catch {}
384
+ try {
385
+ const outcome = await runUpdateFlow({
386
+ root: REPO_ROOT,
387
+ dataDir,
388
+ mode: 'apply',
389
+ log: (msg) => console.log(msg),
390
+ });
391
+ return {
392
+ status: {
393
+ version: outcome.to || currentVersion,
394
+ installation: channel === 'npm' ? 'npm' : 'windows-installer',
395
+ phase: outcome.updated || outcome.repaired ? 'succeeded' : 'failed',
396
+ updatedAt: Date.now(),
397
+ error: outcome.failed ? (outcome.reason || '更新失败并已回退') : null,
398
+ },
399
+ };
400
+ } catch (err) {
401
+ return {
402
+ status: {
403
+ version: currentVersion,
404
+ installation: channel === 'npm' ? 'npm' : 'windows-installer',
405
+ phase: 'failed',
406
+ updatedAt: Date.now(),
407
+ error: err.message.slice(0, 450),
408
+ },
409
+ };
410
+ }
411
+ }
412
+ if (method === 'codexhost/update/status') {
413
+ const dataDir = nativeEnvironment().CODEXHOST_DATA_DIR;
414
+ const state = readState(dataDir);
415
+ const channel = detectChannel(REPO_ROOT);
416
+ let currentVersion = '0.1.2';
417
+ try { currentVersion = JSON.parse(fs.readFileSync(PACKAGE_JSON_PATH, 'utf8')).version || '0.1.2'; } catch {}
418
+ if (state.phase && state.phase !== 'idle') {
419
+ return {
420
+ status: {
421
+ version: state.pendingVersion || state.appliedVersion || currentVersion,
422
+ installation: channel === 'npm' ? 'npm' : 'windows-installer',
423
+ phase: state.phase === 'applying' ? 'installing' : 'succeeded',
424
+ updatedAt: state.appliedAt || Date.now(),
425
+ error: null,
426
+ },
427
+ };
428
+ }
429
+ return { status: null };
430
+ }
431
+
432
+ // No additional managed accounts: native Codex keeps its own signed-in account.
433
+ if (method === 'codexhost/account/list' || method === 'codexhost/account/refresh') return { accounts: [] };
434
+ if (method === 'codexhost/harness/account/login') {
435
+ const extId = params.harnessId;
436
+ const meta = HARNESS_AUTH_INFO[extId] || HARNESS_AUTH_INFO[ALIASES[extId]];
437
+ const cmd = meta?.loginCommand;
438
+ if (!cmd) throw new Error(`Harness ${extId} 暂不支持命令行直接登录,请参考凭据配置指引进行配置`);
439
+ const title = `登录 ${meta.name || extId}`;
440
+ const execCmd = `cmd.exe /c start "${title}" cmd.exe /k "echo 正在为 ${meta.name} 启动登录认证... && echo 执行命令: ${cmd} && echo. && ${cmd} && echo. && echo [Harness Mix] 登录操作已完成,请关闭此窗口并返回 Harness Mix 刷新状态"`;
441
+ exec(execCmd, { windowsHide: false });
442
+ return { success: true, command: cmd };
443
+ }
444
+ if (method === 'codexhost/harness/accounts/list') {
445
+ const accounts = [];
446
+ for (const adapter of this.runtime.adapters.values()) {
447
+ const id = adapter.manifest.id;
448
+ const extId = externalId(id);
449
+ const meta = HARNESS_AUTH_INFO[extId] || HARNESS_AUTH_INFO[id] || { name: adapter.manifest.name };
450
+ const isAvailable = !!this.runtime.status[id]?.available;
451
+
452
+ let email = undefined;
453
+ let label = meta.label;
454
+ let plan = meta.plan;
455
+ let credits = undefined;
456
+ let status = isAvailable ? 'ready' : 'not_installed';
457
+
458
+ if (typeof adapter.inspectAccount === 'function') {
459
+ try {
460
+ const raw = await Promise.race([
461
+ Promise.resolve().then(() => adapter.inspectAccount()),
462
+ new Promise((resolve) => setTimeout(() => resolve(null), 5_000)),
463
+ ]);
464
+ if (raw && typeof raw === 'object') {
465
+ if (raw.email && typeof raw.email === 'string') email = raw.email.trim();
466
+ if (raw.label && typeof raw.label === 'string') label = raw.label.trim();
467
+ if (raw.plan && typeof raw.plan === 'string') plan = raw.plan.trim();
468
+ if (raw.credits) credits = projectAccountCredits(raw.credits) || undefined;
469
+ status = 'ready';
470
+ }
471
+ } catch {
472
+ // keep default
473
+ }
474
+ }
475
+
476
+ if (!email) {
477
+ if (id === 'codex') {
478
+ status = 'ready';
479
+ email = 'Codex Desktop 会话已就绪';
480
+ } else if (id === 'dsh') {
481
+ if (process.env.DEEPSEEK_API_KEY) {
482
+ status = 'ready';
483
+ email = 'API Key (已设置)';
484
+ } else {
485
+ status = isAvailable ? 'unconfigured' : 'not_installed';
486
+ }
487
+ } else if (id === 'grok') {
488
+ if (process.env.XAI_API_KEY) {
489
+ status = 'ready';
490
+ email = 'xAI API Key (已设置)';
491
+ } else {
492
+ status = isAvailable ? 'unconfigured' : 'not_installed';
493
+ }
494
+ } else if (id === 'openclaw') {
495
+ if (process.env.OPENCLAW_TOKEN) {
496
+ status = 'ready';
497
+ email = 'Gateway Token (已配置)';
498
+ } else {
499
+ status = isAvailable ? 'unconfigured' : 'not_installed';
500
+ }
501
+ } else if (!isAvailable) {
502
+ status = 'not_installed';
503
+ }
504
+ }
505
+
506
+ accounts.push({
507
+ harnessId: extId,
508
+ harnessName: meta.name || adapter.manifest.name,
509
+ status,
510
+ ...(email ? { email } : {}),
511
+ ...(label ? { label } : {}),
512
+ ...(plan ? { plan } : {}),
513
+ ...(meta.configHint ? { configHint: meta.configHint } : {}),
514
+ ...(meta.loginCommand ? { loginCommand: meta.loginCommand } : {}),
515
+ ...(credits ? { credits } : {}),
516
+ });
517
+ }
518
+ return { accounts };
519
+ }
520
+ if (method === 'codexhost/harness/plugins/list') return { plugins: this.runtime.snapshot().adapters.map(a => ({ id: externalId(a.id), name: a.id === 'codex' ? 'Codex(协作)' : a.name, version: '0.1.0', icon: `data:image/svg+xml;base64,${Buffer.from(getHarnessSvg(a.id)).toString('base64')}` })) };
521
+ if (method === 'codexhost/harness/inspect') return this.inspect(params.harnessId);
522
+ if (method === 'codexhost/harness/install') {
523
+ const local = ALIASES[params.harnessId] || params.harnessId;
524
+ const entry = HARNESS_INSTALL_COMMANDS[params.harnessId] || HARNESS_INSTALL_COMMANDS[local];
525
+ if (!entry) throw new Error(`No installation command available for harness: ${params.harnessId}`);
526
+ const command = (process.platform === 'win32' ? entry.win32 : entry.default) || entry.default;
527
+
528
+ if (params.terminal) {
529
+ const title = `安装 ${params.harnessId}`;
530
+ const cmd = `cmd.exe /c start "${title}" cmd.exe /k "echo 正在安装 ${params.harnessId} (${command})... && ${command} && echo. && echo [Harness Mix] 安装执行完毕,请关闭此窗口并返回 Harness Mix 点击【刷新检测】"`;
531
+ exec(cmd, { windowsHide: false });
532
+ return { success: true, command, stdout: '已在独立终端窗口中启动安装' };
533
+ }
534
+
535
+ return new Promise((resolve) => {
536
+ exec(command, { timeout: 180000, shell: true }, async (err, stdout, stderr) => {
537
+ const adapter = this.runtime.adapters.get(local);
538
+ if (adapter) {
539
+ try {
540
+ const inspection = await adapter.inspect();
541
+ this.runtime.status[local] = inspection;
542
+ if (inspection.available) this.runtime.catalogs.delete(local);
543
+ } catch (e) {
544
+ this.runtime.status[local] = { available: false, detail: e.message };
545
+ }
546
+ }
547
+ if (err) {
548
+ resolve({ success: false, command, error: err.message, stdout: stdout?.toString() || '', stderr: stderr?.toString() || '' });
549
+ } else {
550
+ resolve({ success: true, command, stdout: stdout?.toString() || '', stderr: stderr?.toString() || '' });
551
+ }
552
+ });
553
+ });
554
+ }
555
+ if (method === 'codexhost/harness/commands/inspect' || method === 'codexhost/thread/commands/inspect') {
556
+ const commands = await this.runtime.listCommands({ threadId: params.threadId, harnessId: ALIASES[params.harnessId] || params.harnessId });
557
+ return { commands: commands.map(c => ({ id: c.id, invocation: '/' + c.id, label: c.label || c.id, ...(c.description ? { description: c.description.slice(0, 512) } : {}), argumentMode: c.action === 'insert' ? 'text' : 'none' })) };
558
+ }
559
+ if (method === 'codexhost/thread/ownership/list') return { threads: params.threadIds.map(id => ({ threadId: id, owner: this.owns(id) ? 'external' : 'codex', ...(this.owns(id) ? { harnessId: externalId(this.thread(id).harnessId) } : {}) })) };
560
+ if (method === 'codexhost/thread/inspect') {
561
+ if (!thread) return { owner: 'codex', locked: true };
562
+ const catalog = await this.runtime.describe(thread.harnessId);
563
+ const usage = typeof this.runtime.core?.getThread === 'function' ? this.runtime.core.getThread(thread.id)?.usage : undefined;
564
+ const adapter = this.runtime.adapters && typeof this.runtime.adapters.get === 'function' ? this.runtime.adapters.get(thread.harnessId) : null;
565
+ const rawCredits = adapter && typeof adapter.credits === 'function' ? adapter.credits() : null;
566
+ const credits = projectAccountCredits(rawCredits);
567
+ return { owner: 'external', harnessId: externalId(thread.harnessId), transportModelId: routeModel(externalId(thread.harnessId)), locked: true,
568
+ ...this.configuration(thread), history: this.capabilities(thread.harnessId, catalog).history,
569
+ ...(usage ? { usage: projectUsage(usage) } : {}),
570
+ ...(credits ? { accountCredits: credits } : {}) };
571
+ }
572
+ if (method === 'thread/start') {
573
+ const route = decodeRoute(params.model);
574
+ if (!route) return undefined;
575
+ const id = ALIASES[route.harnessId] || route.harnessId;
576
+ if (!this.runtime.adapters.has(id)) throw new Error(`Unsupported Harness: ${id}`);
577
+ if (params.ephemeral && params.threadSource) throw new Error('Ephemeral background thread is not supported');
578
+ const isWorktree = params.worktree === true || params.options?.worktree === true;
579
+ const created = await this.runtime.createThread({ harnessId: id, cwd: params.cwd, ephemeral: params.ephemeral === true,
580
+ worktree: isWorktree,
581
+ options: {
582
+ model: await this.resolveModel(id, route.model), thinking: route.thinkingOptionId, permissionMode: route.permissionModeId,
583
+ ...(isWorktree ? { worktree: true } : {}),
584
+ } });
585
+ if (created.error) throw new Error(created.error);
586
+ const result = { thread: this.projectThread(created), model: params.model, modelProvider: 'harness-mix', cwd: created.cwd,
587
+ approvalPolicy: params.approvalPolicy || 'on-request', sandbox: params.sandbox || { type: 'workspaceWrite', writableRoots: [created.cwd], networkAccess: false, excludeTmpdirEnvVar: false, excludeSlashTmp: false }, reasoningEffort: null };
588
+ // thread/started 已由 runtime 的 thread-created 监听统一发出(含协作子任务路径)
589
+ return result;
590
+ }
591
+ if (method === 'codexhost/thread/workspace/review') return this.runtime.reviewThreadWorkspace(params.threadId);
592
+ if (method === 'codexhost/thread/workspace/apply') return this.runtime.applyThreadWorkspace(params.threadId, params.digest);
593
+ if (method === 'codexhost/thread/workspace/discard') return this.runtime.discardThreadWorkspace(params.threadId);
594
+ if (method === 'codexhost/thread/workspace/push') return this.runtime.pushThreadWorkspace(params.threadId, params);
595
+ if (!thread) {
596
+ if (method.startsWith('codexhost/')) throw new Error(`Harness Mix does not implement ${method}`);
597
+ return undefined;
598
+ }
599
+ if (method === 'thread/read') return { thread: this.projectThread(thread, params.includeTurns !== false) };
600
+ // External sessions currently accept immediate turns only, so their Desktop
601
+ // submission queue is empty. Do not forward their IDs to the stock server.
602
+ if (method === 'thread/queue/list') return { data: [], nextCursor: null };
603
+ if (method === 'thread/metadata/update') return { thread: this.projectThread(await this.runtime.updateThreadMetadata(thread.id, params.gitInfo)) };
604
+ if (method === 'thread/section/move') {
605
+ if (params.sectionId !== null && (typeof params.sectionId !== 'string' || !params.sectionId)) throw new Error('Invalid sectionId');
606
+ let section = null;
607
+ if (params.sectionId !== null) {
608
+ if (!this.requestOfficial) throw new Error('Official section catalog unavailable');
609
+ let cursor = null;
610
+ do {
611
+ const page = await this.requestOfficial('threadSection/list', { cursor, limit: 100 });
612
+ section = page.data.find(entry => entry.id === params.sectionId) || null;
613
+ cursor = page.nextCursor;
614
+ } while (!section && cursor);
615
+ if (!section) throw new Error('Unknown thread section');
616
+ }
617
+ await this.runtime.setThreadSection(thread.id, section, params.beforeThreadId);
618
+ return {};
619
+ }
620
+ if (method === 'thread/resume') return { thread: this.projectThread(thread), model: routeModel(externalId(thread.harnessId)), modelProvider: 'harness-mix', cwd: thread.cwd, approvalPolicy: 'on-request', sandbox: { type: 'workspaceWrite', writableRoots: [thread.cwd], networkAccess: false, excludeTmpdirEnvVar: false, excludeSlashTmp: false }, reasoningEffort: null };
621
+ if (method === 'turn/start') {
622
+ const { text, attachments } = await prepareInput(params.input, thread.cwd);
623
+ return { turn: this.turn(await this.startNativeTurn(thread, text, attachments)) };
624
+ }
625
+ // External steering: cancel the active Turn, wait for it to fully settle, then start
626
+ // the new input as a real new Turn. Never guess a stale target, never auto-start on
627
+ // failure, and never let a concurrent start race the replacement.
628
+ if (method === 'turn/steer') {
629
+ const input = Array.isArray(params.input) ? params.input : [];
630
+ // Reject before touching the active Turn; nothing is silently dropped mid-flight.
631
+ if (!input.length) {
632
+ throw new Error('Native steering currently accepts non-empty text input only');
633
+ }
634
+ const { text, attachments } = await prepareInput(input, thread.cwd);
635
+ if (!text.trim() && !attachments.length) throw new Error('Native steering requires non-empty text or images');
636
+ if (attachments.length && !this.runtime.getCapabilities(thread.harnessId).conversation.attachments) throw new Error('当前 Harness 不支持图片附件');
637
+ const expectedTurnId = params.expectedTurnId;
638
+ if (typeof expectedTurnId !== 'string' || !expectedTurnId) throw new Error('Native steering requires the active Turn identity');
639
+ return this.steerThread(thread, {
640
+ expectedTurnId,
641
+ text,
642
+ attachments,
643
+ messageKey: typeof params.clientUserMessageId === 'string' && params.clientUserMessageId
644
+ ? `${thread.id}\0${params.clientUserMessageId}` : null,
645
+ fingerprint: JSON.stringify({ expectedTurnId, input }),
646
+ });
647
+ }
648
+ if (method === 'turn/interrupt') { await this.runtime.cancel(thread.id); return {}; }
649
+ // 跨 Harness 任务协作:委派新子任务 / 跟进既有子任务,等待链由父线程协作 Turn 承载
650
+ if (method === 'codexhost/thread/delegate' || method === 'codexhost/thread/message') {
651
+ const task = params.task ?? params.text;
652
+ if (typeof task !== 'string' || !task.trim()) throw new Error('Delegation requires a non-empty task');
653
+ const { child, turn } = await this.runtime.delegateTask({
654
+ fromThreadId: thread.id,
655
+ harnessId: method === 'codexhost/thread/delegate' ? (ALIASES[params.harnessId] || params.harnessId) : undefined,
656
+ childThreadId: method === 'codexhost/thread/message' ? params.childThreadId : undefined,
657
+ task,
658
+ });
659
+ return { turn: this.turn(turn), childThreadId: child.id };
660
+ }
661
+ if (method === 'thread/rollback') return { thread: this.projectThread(await this.runtime.rollbackThread(thread.id, params.numTurns)) };
662
+ if (method === 'thread/name/set') { await this.runtime.renameThread(thread.id, params.name); return {}; }
663
+ if (method === 'thread/archive' || method === 'thread/unarchive') { await this.runtime.setThreadArchived(thread.id, method === 'thread/archive'); return method === 'thread/archive' ? {} : { thread: this.projectThread(thread) }; }
664
+ if (method === 'thread/loaded/list') return { data: [...this.runtime.sessions.keys()] };
665
+ if (method === 'codexhost/thread/usage/inspect') {
666
+ const usage = params.refresh === 'exact' ? await this.runtime.refreshUsage(thread.id) : this.runtime.core.getThread(thread.id)?.usage;
667
+ const adapter = this.runtime.adapters.get(thread.harnessId);
668
+ let rawCredits = adapter && typeof adapter.credits === 'function' ? adapter.credits() : null;
669
+ if (!rawCredits && adapter && typeof adapter.refreshCredits === 'function') {
670
+ try { rawCredits = await adapter.refreshCredits(); } catch {}
671
+ } else if (adapter && params.refresh === 'exact' && typeof adapter.refreshCredits === 'function') {
672
+ try { await adapter.refreshCredits(); } catch {}
673
+ rawCredits = adapter && typeof adapter.credits === 'function' ? adapter.credits() : null;
674
+ }
675
+ const credits = projectAccountCredits(rawCredits);
676
+ return {
677
+ threadId: thread.id,
678
+ usage: projectUsage(usage),
679
+ ...(credits ? { accountCredits: credits } : {}),
680
+ };
681
+ }
682
+ if (method === 'codexhost/thread/command/execute') {
683
+ if (params.arguments && Object.keys(params.arguments).length) throw new Error('This command does not accept arguments');
684
+ const turn = await this.startNativeTurn(thread, '', undefined, params.commandId);
685
+ return { accepted: true, turnId: turn.id };
686
+ }
687
+ if (method === 'codexhost/thread/model/select') { await this.runtime.setModel(thread.id, await this.resolveModel(thread.harnessId, params.model)); return this.configuration(thread); }
688
+ if (method === 'codexhost/thread/thinking/select') { await this.runtime.setThinking(thread.id, params.thinkingOptionId); return this.configuration(thread); }
689
+ if (method === 'codexhost/thread/permission-mode/select') {
690
+ await this.runtime.setOptions(thread.id, { permissionMode: params.permissionModeId });
691
+ const session = this.runtime.sessions.get(thread.id);
692
+ const adapter = this.runtime.adapters.get(thread.harnessId);
693
+ if (session && adapter && typeof adapter.setPermissionMode === 'function') {
694
+ try { await adapter.setPermissionMode(session, params.permissionModeId); } catch {}
695
+ }
696
+ return this.configuration(thread);
697
+ }
698
+ // 原地切换 Harness:会话历史保留,下条消息携带一次性上下文信封(/switch 指令的 RPC 等价物)
699
+ if (method === 'codexhost/thread/harness/switch') {
700
+ await this.runtime.switchHarness(thread.id, ALIASES[params.harnessId] || params.harnessId, { note: typeof params.note === 'string' ? params.note : undefined });
701
+ return { threadId: thread.id };
702
+ }
703
+ if (method === 'thread/fork' || method === 'codexhost/thread/fork') {
704
+ if (params.ephemeral || params.threadSource || params.excludeTurns) {
705
+ throw new Error('Ephemeral fork is not supported');
706
+ }
707
+ const messageId = params.lastTurnId ? thread.messages.find(m => m.coreTurnId === params.lastTurnId)?.id : params.messageId;
708
+ if (params.lastTurnId && !messageId) throw new Error('Unknown fork turn');
709
+ const fork = await this.runtime.forkThread(thread.id, messageId);
710
+ return method === 'codexhost/thread/fork' ? { threadId: fork.id } : { thread: this.projectThread(fork) };
711
+ }
712
+ throw new Error(`Harness Mix native bridge does not support ${method} for this thread`);
713
+ }
714
+ onCore(event, projected) {
715
+ const { threadId, turnId } = event;
716
+ const item = projected.item;
717
+ const notify = (method, extra) => this.emit({ method, params: { threadId, turnId, ...extra } });
718
+ if (event.type === 'usage.updated') this.emit({ method: 'codexhost/thread/usage/updated', params: { threadId, usage: projectUsage(projected.thread?.usage) } });
719
+ if (projected.items) {
720
+ for (const file of projected.items) this.onCore({ ...event, type: 'item.updated' }, { item: file });
721
+ notify('turn/diff/updated', { diff: projected.items.map(i => projectItem(i)?.changes?.map(c => c.diff).filter(Boolean).join('\n')).filter(Boolean).join('\n') });
722
+ }
723
+ if (event.type === 'plan.updated' && item) notify('turn/plan/updated', { explanation: null, plan: (item.entries || []).map(e => ({ step: e.text || e.title || e.step, status: e.status === 'done' || e.status === 'completed' ? 'completed' : e.status === 'in_progress' ? 'inProgress' : 'pending' })) });
724
+ if (event.type === 'turn.started') {
725
+ notify('turn/started', { turn: this.turn(projected.turn) });
726
+ // The Desktop sidebar spinner is driven by thread/status/changed, not by
727
+ // turn lifecycle events alone — mirror the official app-server contract.
728
+ notify('thread/status/changed', { status: { type: 'active', activeFlags: [] } });
729
+ }
730
+ if (item) {
731
+ const converted = projectItem(item);
732
+ if (converted) {
733
+ const previous = this.published.get(item.id);
734
+ if (!previous) notify('item/started', { item: converted });
735
+ if (item.type === 'agent_message' && item.content?.length > (previous?.content?.length || 0)) notify('item/agentMessage/delta', { itemId: item.id, delta: item.content.slice(previous?.content?.length || 0) });
736
+ if (item.type === 'reasoning' && item.content?.length > (previous?.content?.length || 0)) notify('item/reasoning/summaryTextDelta', { itemId: item.id, summaryIndex: 0, delta: item.content.slice(previous?.content?.length || 0) });
737
+ if (terminal(item.status) && (!terminal(previous?.status) || ['file_change', 'tool_call'].includes(item.type) && JSON.stringify(converted) !== JSON.stringify(projectItem(previous)))) notify('item/completed', { item: converted });
738
+ this.published.set(item.id, structuredClone(item));
739
+ if (this.published.size > 200) {
740
+ const oldest = this.published.keys().next().value;
741
+ if (oldest) this.published.delete(oldest);
742
+ }
743
+ }
744
+ if (['approval', 'question'].includes(item.type) && event.type === 'item.started') {
745
+ const id = `harness-mix:approval:${item.id}`;
746
+ this.approvals.set(id, { threadId, requestId: item.requestId, item });
747
+ const question = item.type === 'question' || item.method === 'select';
748
+ this.emit({ id, method: question ? 'item/tool/requestUserInput' : 'item/commandExecution/requestApproval', params: {
749
+ threadId, turnId, itemId: item.id,
750
+ ...(question ? { questions: [{ id: item.requestId, header: 'Harness', question: item.message || item.title || 'Native Harness input', isOther: true, isSecret: false,
751
+ options: item.options?.map(o => ({ label: typeof o === 'string' ? o : o.label || o.id, description: typeof o === 'string' ? o : o.description || o.label || o.id })) || null }] }
752
+ : { reason: item.message || item.title, command: null, cwd: this.thread(threadId)?.cwd, availableDecisions: ['accept', 'decline'] }) } });
753
+ }
754
+ }
755
+ if (event.type === 'turn.waiting') notify('thread/status/changed', { status: { type: 'active', activeFlags: [] } });
756
+ if (event.type === 'turn.resumed') notify('thread/status/changed', { status: { type: 'active', activeFlags: [] } });
757
+ if (event.type.startsWith('turn.') && projected.turn && terminal(projected.turn.status)) {
758
+ notify('turn/completed', { turn: this.turn(projected.turn) });
759
+ notify('thread/status/changed', { status: { type: 'idle' } });
760
+ if (Array.isArray(projected.turn.itemIds)) {
761
+ for (const id of projected.turn.itemIds) this.published.delete(id);
762
+ }
763
+ }
764
+ }
765
+ async startNativeTurn(thread, text, attachments, commandId) {
766
+ const before = thread.currentTurn?.id;
767
+ for (let i = 0; i < 100 && this.runtime.sending?.has(thread.id) && !this.runtime.execution.isRunning(thread.id); i++) {
768
+ await new Promise(resolve => setTimeout(resolve, 20));
769
+ }
770
+ let failure;
771
+ const running = (commandId ? this.runtime.executeCommand(thread.id, commandId) : this.runtime.send(thread.id, text, { attachments })).catch(error => { failure = error; });
772
+ for (let attempt = 0; attempt < 600 && thread.currentTurn?.id === before && !failure; attempt++) await new Promise(resolve => setTimeout(resolve, 50));
773
+ if (failure) throw failure;
774
+ if (!thread.currentTurn || thread.currentTurn.id === before) throw new Error('Native turn did not start');
775
+ void running;
776
+ return thread.currentTurn;
777
+ }
778
+ async steerThread(thread, { expectedTurnId, text, attachments, messageKey, fingerprint }) {
779
+ if (messageKey) {
780
+ const receipt = this.steerReceipts.get(messageKey);
781
+ // Outcome-unknown retry: identical payload returns the original receipt; a
782
+ // conflicting payload under the same message identity is rejected.
783
+ if (receipt) {
784
+ if (receipt.fingerprint !== fingerprint) throw new Error('Conflicting steering payload for the same message');
785
+ return { turnId: await receipt.promise };
786
+ }
787
+ }
788
+ if (this.steering.has(thread.id)) throw new Error('This Thread is already changing direction');
789
+ const work = this.steerExclusive(thread, expectedTurnId, text, attachments);
790
+ this.steering.set(thread.id, work);
791
+ if (messageKey) {
792
+ if (this.steerReceipts.size >= 200) this.steerReceipts.delete(this.steerReceipts.keys().next().value);
793
+ this.steerReceipts.set(messageKey, { fingerprint, promise: work });
794
+ }
795
+ try {
796
+ return { turnId: await work };
797
+ } finally {
798
+ this.steering.delete(thread.id);
799
+ }
800
+ }
801
+ async steerExclusive(thread, expectedTurnId, text, attachments) {
802
+ const active = this.runtime.execution.isRunning(thread.id) ? thread.currentTurn : null;
803
+ if (active) {
804
+ if (active.id !== expectedTurnId) throw new Error('The active Turn no longer matches the steering target');
805
+ await this.runtime.cancel(thread.id);
806
+ // Cancel settles synchronously in Core, but the acknowledgement is not completion:
807
+ // the replacement waits until the old Turn is fully terminal and the file-review
808
+ // snapshot has settled (≤20s, shorter than the Desktop submission timeout).
809
+ const settled = () => !this.runtime.execution.isRunning(thread.id) && !thread.reviewPending && !this.runtime.sending?.has(thread.id);
810
+ const deadline = Date.now() + 20_000;
811
+ while (!settled() && Date.now() < deadline) await new Promise(resolve => setTimeout(resolve, 50));
812
+ if (!settled()) throw new Error('Timed out waiting for the previous Turn to settle');
813
+ } else {
814
+ const last = thread.currentTurn;
815
+ // A later Turn already exists, or the target was never this Thread's last Turn: stale.
816
+ if (last && last.id !== expectedTurnId) throw new Error('The active Turn no longer matches the steering target');
817
+ }
818
+ // If a native Turn started on its own in the meantime, send() refuses and the new
819
+ // Turn is left running; a failed replacement never cancels unexpected work.
820
+ const started = await this.startNativeTurn(thread, text, attachments);
821
+ return started.id;
822
+ }
823
+ async respond(message) {
824
+ const pending = this.approvals.get(message.id);
825
+ if (!pending) return false;
826
+ if (message.error) throw new Error(message.error.message || 'Approval UI error');
827
+ const answer = message.result?.answers?.[pending.requestId]?.answers?.[0];
828
+ const decision = message.result?.decision;
829
+ const response = pending.item.type === 'question' ? { value: answer || '' } : pending.item.method === 'select' ? { value: answer || '' } : { confirmed: decision === 'accept' || decision === 'acceptForSession' };
830
+ await this.runtime.respondApproval(pending.threadId, pending.requestId, response);
831
+ this.approvals.delete(message.id);
832
+ return true;
833
+ }
834
+ close() { this.unsubscribe(); this.unsubscribeRuntime(); }
835
+ }
836
+ module.exports = { NativeProtocol, decodeRoute, projectItem, externalId, routeModel };