synabun 2.0.10 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (517) hide show
  1. package/CHANGELOG.md +86 -0
  2. package/README.md +25 -2
  3. package/THIRD-PARTY-LICENSES.md +22 -0
  4. package/bin/synabun.js +71 -24
  5. package/docs/whatsapp.md +2 -2
  6. package/hooks/claude-code/pre-websearch.mjs +12 -1
  7. package/hooks/claude-code/shared.mjs +5 -0
  8. package/hooks/claude-code/stop.mjs +1 -1
  9. package/lib/claude-hooks.js +172 -18
  10. package/lib/client-config-repair.js +17 -8
  11. package/lib/desktop-app.js +7 -1
  12. package/lib/external-tools.js +1 -1
  13. package/lib/first-launch-protection.js +57 -12
  14. package/lib/mcp-dist.js +176 -0
  15. package/lib/release-npm-ci.mjs +138 -0
  16. package/lib/release-publish.mjs +91 -0
  17. package/lib/release-scan.mjs +50 -0
  18. package/lib/server-crash-record.js +123 -0
  19. package/lib/server-exit.js +318 -0
  20. package/lib/server-supervisor.js +508 -0
  21. package/lib/start-launcher.js +37 -4
  22. package/lib/tools-cli.js +45 -0
  23. package/lib/update-snapshot.js +228 -0
  24. package/lib/virustotal.mjs +192 -0
  25. package/lib/windows-crash-event.js +269 -0
  26. package/mcp-server/dist/http.d.ts +20 -1
  27. package/mcp-server/dist/http.d.ts.map +1 -1
  28. package/mcp-server/dist/http.js +59 -12
  29. package/mcp-server/dist/http.js.map +1 -1
  30. package/mcp-server/dist/index.d.ts +33 -27
  31. package/mcp-server/dist/index.d.ts.map +1 -1
  32. package/mcp-server/dist/index.js +128 -143
  33. package/mcp-server/dist/index.js.map +1 -1
  34. package/mcp-server/dist/preload.js +1 -1
  35. package/mcp-server/dist/preload.js.map +1 -1
  36. package/mcp-server/dist/services/codex-config-heal.d.ts +6 -2
  37. package/mcp-server/dist/services/codex-config-heal.d.ts.map +1 -1
  38. package/mcp-server/dist/services/codex-config-heal.js +81 -28
  39. package/mcp-server/dist/services/codex-config-heal.js.map +1 -1
  40. package/mcp-server/dist/services/memory-judge-backfill.d.ts +6 -0
  41. package/mcp-server/dist/services/memory-judge-backfill.d.ts.map +1 -1
  42. package/mcp-server/dist/services/memory-judge-backfill.js +7 -1
  43. package/mcp-server/dist/services/memory-judge-backfill.js.map +1 -1
  44. package/mcp-server/dist/services/neural-interface.d.ts +16 -10
  45. package/mcp-server/dist/services/neural-interface.d.ts.map +1 -1
  46. package/mcp-server/dist/services/neural-interface.js +67 -11
  47. package/mcp-server/dist/services/neural-interface.js.map +1 -1
  48. package/mcp-server/dist/services/server-instructions.d.ts +7 -2
  49. package/mcp-server/dist/services/server-instructions.d.ts.map +1 -1
  50. package/mcp-server/dist/services/server-instructions.js +20 -62
  51. package/mcp-server/dist/services/server-instructions.js.map +1 -1
  52. package/mcp-server/dist/services/tool-catalog.d.ts +120 -0
  53. package/mcp-server/dist/services/tool-catalog.d.ts.map +1 -0
  54. package/mcp-server/dist/services/tool-catalog.js +339 -0
  55. package/mcp-server/dist/services/tool-catalog.js.map +1 -0
  56. package/mcp-server/dist/services/tool-list-refresh-barrier.d.ts +12 -0
  57. package/mcp-server/dist/services/tool-list-refresh-barrier.d.ts.map +1 -0
  58. package/mcp-server/dist/services/tool-list-refresh-barrier.js +40 -0
  59. package/mcp-server/dist/services/tool-list-refresh-barrier.js.map +1 -0
  60. package/mcp-server/dist/services/tool-list.d.ts +108 -0
  61. package/mcp-server/dist/services/tool-list.d.ts.map +1 -0
  62. package/mcp-server/dist/services/tool-list.js +334 -0
  63. package/mcp-server/dist/services/tool-list.js.map +1 -0
  64. package/mcp-server/dist/services/tool-runtime.d.ts +161 -0
  65. package/mcp-server/dist/services/tool-runtime.d.ts.map +1 -0
  66. package/mcp-server/dist/services/tool-runtime.js +400 -0
  67. package/mcp-server/dist/services/tool-runtime.js.map +1 -0
  68. package/mcp-server/dist/services/whiteboard-geometry.d.ts +26 -2
  69. package/mcp-server/dist/services/whiteboard-geometry.d.ts.map +1 -1
  70. package/mcp-server/dist/services/whiteboard-geometry.js +91 -8
  71. package/mcp-server/dist/services/whiteboard-geometry.js.map +1 -1
  72. package/mcp-server/dist/tools/agents.d.ts +10 -10
  73. package/mcp-server/dist/tools/agents.d.ts.map +1 -1
  74. package/mcp-server/dist/tools/agents.js +22 -13
  75. package/mcp-server/dist/tools/agents.js.map +1 -1
  76. package/mcp-server/dist/tools/browser-batch.d.ts +3 -3
  77. package/mcp-server/dist/tools/image-tools.d.ts +1 -1
  78. package/mcp-server/dist/tools/image-tools.js +1 -1
  79. package/mcp-server/dist/tools/skill-tools.d.ts +505 -0
  80. package/mcp-server/dist/tools/skill-tools.d.ts.map +1 -0
  81. package/mcp-server/dist/tools/skill-tools.js +639 -0
  82. package/mcp-server/dist/tools/skill-tools.js.map +1 -0
  83. package/mcp-server/dist/tools/skill.d.ts +7 -0
  84. package/mcp-server/dist/tools/skill.d.ts.map +1 -0
  85. package/mcp-server/dist/tools/skill.js +11 -0
  86. package/mcp-server/dist/tools/skill.js.map +1 -0
  87. package/mcp-server/dist/tools/tool-groups.d.ts +68 -0
  88. package/mcp-server/dist/tools/tool-groups.d.ts.map +1 -0
  89. package/mcp-server/dist/tools/tool-groups.js +147 -0
  90. package/mcp-server/dist/tools/tool-groups.js.map +1 -0
  91. package/mcp-server/dist/tools/whiteboard-format.d.ts.map +1 -1
  92. package/mcp-server/dist/tools/whiteboard-format.js +7 -4
  93. package/mcp-server/dist/tools/whiteboard-format.js.map +1 -1
  94. package/mcp-server/dist/tools/whiteboard-tools.d.ts +64 -13
  95. package/mcp-server/dist/tools/whiteboard-tools.d.ts.map +1 -1
  96. package/mcp-server/dist/tools/whiteboard-tools.js +30 -5
  97. package/mcp-server/dist/tools/whiteboard-tools.js.map +1 -1
  98. package/mcp-server/package-lock.json +2 -2
  99. package/mcp-server/package.json +1 -1
  100. package/mcp-server/src/http.ts +75 -12
  101. package/mcp-server/src/index.ts +147 -154
  102. package/mcp-server/src/preload.ts +12 -12
  103. package/mcp-server/src/services/codex-config-heal.ts +80 -29
  104. package/mcp-server/src/services/memory-judge-backfill.ts +7 -1
  105. package/mcp-server/src/services/neural-interface.ts +79 -20
  106. package/mcp-server/src/services/server-instructions.ts +27 -63
  107. package/mcp-server/src/services/tool-catalog.ts +403 -0
  108. package/mcp-server/src/services/tool-list-refresh-barrier.ts +33 -0
  109. package/mcp-server/src/services/tool-list.ts +410 -0
  110. package/mcp-server/src/services/tool-runtime.ts +457 -0
  111. package/mcp-server/src/services/whiteboard-geometry.ts +94 -9
  112. package/mcp-server/src/tools/agents.ts +22 -14
  113. package/mcp-server/src/tools/image-tools.ts +1 -1
  114. package/mcp-server/src/tools/skill-tools.ts +589 -0
  115. package/mcp-server/src/tools/skill.ts +13 -0
  116. package/mcp-server/src/tools/tool-groups.ts +164 -0
  117. package/mcp-server/src/tools/whiteboard-format.ts +9 -3
  118. package/mcp-server/src/tools/whiteboard-tools.ts +39 -5
  119. package/neural-interface/i18n/en.json +3463 -200
  120. package/neural-interface/i18n/pt-BR.json +3411 -151
  121. package/neural-interface/lib/assistant-api.js +127 -28
  122. package/neural-interface/lib/assistant-brains/claude.js +4 -3
  123. package/neural-interface/lib/assistant-brains/codex-browser-policy-hook.mjs +12 -2
  124. package/neural-interface/lib/assistant-brains/codex-route-gate-hook.mjs +32 -9
  125. package/neural-interface/lib/assistant-brains/codex.js +9 -5
  126. package/neural-interface/lib/assistant-brains/opencode.js +120 -54
  127. package/neural-interface/lib/assistant-brains/opencode2-browser-policy/index.js +28 -13
  128. package/neural-interface/lib/assistant-brains/opencode2-route-gate/index.js +59 -19
  129. package/neural-interface/lib/assistant-catalog.js +6 -7
  130. package/neural-interface/lib/assistant-dispatch.js +871 -156
  131. package/neural-interface/lib/assistant-envelope.js +3 -1
  132. package/neural-interface/lib/assistant-persona.js +80 -11
  133. package/neural-interface/lib/assistant-plan-permissions.js +10 -9
  134. package/neural-interface/lib/assistant-route-gate-codex.js +3 -0
  135. package/neural-interface/lib/assistant-route-gate.js +6 -4
  136. package/neural-interface/lib/assistant-router.js +13 -8
  137. package/neural-interface/lib/assistant-runtime.js +56 -18
  138. package/neural-interface/lib/assistant-task-prompt.js +78 -14
  139. package/neural-interface/lib/assistant-tools.js +51 -0
  140. package/neural-interface/lib/backup-service.js +620 -3
  141. package/neural-interface/lib/backup-zip-reader.js +10 -5
  142. package/neural-interface/lib/backup-zip-writer.js +257 -0
  143. package/neural-interface/lib/browser-execution.js +10 -2
  144. package/neural-interface/lib/browser-guard-cdp.js +83 -0
  145. package/neural-interface/lib/browser-network-guard.js +284 -0
  146. package/neural-interface/lib/browser-policy-roots.js +64 -0
  147. package/neural-interface/lib/browser-tool-policy.js +186 -31
  148. package/neural-interface/lib/claude-agent-bridge.js +4 -2
  149. package/neural-interface/lib/claude-hooks-status.js +103 -0
  150. package/neural-interface/lib/claude-temporary.js +5 -11
  151. package/neural-interface/lib/cli-install.js +18 -138
  152. package/neural-interface/lib/cli-resolver.js +4 -1
  153. package/neural-interface/lib/cli-update-planner.js +32 -31
  154. package/neural-interface/lib/cloudflared/tunnel.js +42 -2
  155. package/neural-interface/lib/codex-mcp-approvals.js +11 -0
  156. package/neural-interface/lib/codex-worker-app-server.js +172 -0
  157. package/neural-interface/lib/confined-fs.js +30 -3
  158. package/neural-interface/lib/crash-notice-api.js +98 -0
  159. package/neural-interface/lib/editor-completion-opencode.js +68 -68
  160. package/neural-interface/lib/exec-loop-command.js +4 -8
  161. package/neural-interface/lib/http-guards.js +8 -2
  162. package/neural-interface/lib/install-details.js +4 -1
  163. package/neural-interface/lib/mcp-agent-servers.js +67 -0
  164. package/neural-interface/lib/mcp-client-config.js +0 -29
  165. package/neural-interface/lib/mcp-external-servers.js +323 -0
  166. package/neural-interface/lib/{mcp-profile-refresh-coordinator.js → mcp-tools-refresh-coordinator.js} +4 -4
  167. package/neural-interface/lib/morelogin.js +30 -0
  168. package/neural-interface/lib/native-loop-providers.js +547 -47
  169. package/neural-interface/lib/native-loop-runtime.js +268 -41
  170. package/neural-interface/lib/opencode-config.js +557 -0
  171. package/neural-interface/lib/opencode-db-schema.js +17 -34
  172. package/neural-interface/lib/opencode-history.js +48 -218
  173. package/neural-interface/lib/opencode-mcp-ready.js +108 -0
  174. package/neural-interface/lib/opencode-native-boundary.js +44 -0
  175. package/neural-interface/lib/opencode-protocol.js +249 -112
  176. package/neural-interface/lib/opencode-runtime-config.js +32 -22
  177. package/neural-interface/lib/opencode-serve-records.js +39 -21
  178. package/neural-interface/lib/opencode-v2-client.js +48 -153
  179. package/neural-interface/lib/opencode-v2-ws-requests.js +36 -210
  180. package/neural-interface/lib/opencode-worker-data.js +27 -0
  181. package/neural-interface/lib/opencode2-client.js +73 -37
  182. package/neural-interface/lib/opencode2-proxy.js +23 -63
  183. package/neural-interface/lib/opencode2-translate.js +51 -2
  184. package/neural-interface/lib/owner-authority.js +249 -0
  185. package/neural-interface/lib/page-session.js +275 -0
  186. package/neural-interface/lib/peer-identity.js +763 -0
  187. package/neural-interface/lib/request-gate.js +17 -2
  188. package/neural-interface/lib/rulesets/api.js +1 -1
  189. package/neural-interface/lib/rulesets/fs-safe.js +1 -1
  190. package/neural-interface/lib/rulesets/installer.js +92 -27
  191. package/neural-interface/lib/rulesets/json-edit.js +1 -1
  192. package/neural-interface/lib/session-cache-builder.js +17 -30
  193. package/neural-interface/lib/session-title-generator.js +58 -36
  194. package/neural-interface/lib/skills/api-v2.js +495 -0
  195. package/neural-interface/lib/skills/bundle.js +418 -0
  196. package/neural-interface/lib/skills/catalog.js +294 -0
  197. package/neural-interface/lib/skills/creation-api.js +191 -0
  198. package/neural-interface/lib/skills/creation-brief.js +247 -0
  199. package/neural-interface/lib/skills/creation-sources.js +267 -0
  200. package/neural-interface/lib/skills/creation.js +843 -0
  201. package/neural-interface/lib/skills/deploy.js +564 -0
  202. package/neural-interface/lib/skills/digest.js +119 -0
  203. package/neural-interface/lib/skills/discover.js +111 -0
  204. package/neural-interface/lib/skills/draft-confinement.js +214 -0
  205. package/neural-interface/lib/skills/eval-confinement.js +397 -0
  206. package/neural-interface/lib/skills/eval-sandbox.js +280 -0
  207. package/neural-interface/lib/skills/eval-trace.js +119 -0
  208. package/neural-interface/lib/skills/evals-api.js +212 -0
  209. package/neural-interface/lib/skills/evals.js +1573 -0
  210. package/neural-interface/lib/skills/export.js +200 -0
  211. package/neural-interface/lib/skills/frontmatter.js +64 -0
  212. package/neural-interface/lib/skills/health.js +75 -0
  213. package/neural-interface/lib/skills/json-edit.js +165 -0
  214. package/neural-interface/lib/skills/known-bridge-digests.json +387 -0
  215. package/neural-interface/lib/skills/known-bridges.js +96 -0
  216. package/neural-interface/lib/skills/library.js +823 -0
  217. package/neural-interface/lib/skills/local-store.js +21 -0
  218. package/neural-interface/lib/skills/migration.js +433 -0
  219. package/neural-interface/lib/skills/operations.js +45 -0
  220. package/neural-interface/lib/skills/ownership.js +427 -0
  221. package/neural-interface/lib/skills/packages.js +88 -0
  222. package/neural-interface/lib/skills/reviews.js +212 -0
  223. package/neural-interface/lib/skills/revision.js +80 -0
  224. package/neural-interface/lib/skills/roots.js +262 -0
  225. package/neural-interface/lib/skills/runtime-checks.js +355 -0
  226. package/neural-interface/lib/skills/scan-assets.js +252 -0
  227. package/neural-interface/lib/skills/scan-context.js +26 -0
  228. package/neural-interface/lib/skills/scan-shell.js +324 -0
  229. package/neural-interface/lib/skills/scan.js +364 -0
  230. package/neural-interface/lib/skills/scanners.js +54 -0
  231. package/neural-interface/lib/skills/service.js +522 -0
  232. package/neural-interface/lib/skills/telemetry.js +113 -0
  233. package/neural-interface/lib/sqlite-integrity-worker.js +22 -0
  234. package/neural-interface/lib/tool-lists.js +124 -0
  235. package/neural-interface/lib/whatsapp/bridge.js +6 -3
  236. package/neural-interface/lib/worker-confinement.js +1192 -0
  237. package/neural-interface/lib/worker-guard-setting.js +56 -0
  238. package/neural-interface/lib/worker-mcp-channel.js +175 -0
  239. package/neural-interface/lib/worker-relay-ports.js +227 -0
  240. package/neural-interface/lib/worker-resume.js +229 -0
  241. package/neural-interface/lib/worker-sandbox.js +299 -0
  242. package/neural-interface/package-lock.json +18 -12
  243. package/neural-interface/package.json +2 -2
  244. package/neural-interface/public/index.html +3 -1
  245. package/neural-interface/public/index2d.html +19 -11
  246. package/neural-interface/public/onboarding.html +2 -2
  247. package/neural-interface/public/shared/account-menu.js +8 -5
  248. package/neural-interface/public/shared/agent-runtime-options.js +35 -19
  249. package/neural-interface/public/shared/api.js +1527 -1336
  250. package/neural-interface/public/shared/app-frame.js +192 -0
  251. package/neural-interface/public/shared/assistant/asst-agents-dock.js +33 -2
  252. package/neural-interface/public/shared/assistant/asst-ask-styles.js +270 -0
  253. package/neural-interface/public/shared/assistant/asst-ask-tail.js +118 -0
  254. package/neural-interface/public/shared/assistant/asst-ask.js +397 -0
  255. package/neural-interface/public/shared/assistant/asst-brain-picker.js +49 -35
  256. package/neural-interface/public/shared/assistant/asst-control.js +157 -26
  257. package/neural-interface/public/shared/assistant/asst-followups-card.js +383 -0
  258. package/neural-interface/public/shared/assistant/asst-followups.js +417 -0
  259. package/neural-interface/public/shared/assistant/asst-limit-dock.js +40 -0
  260. package/neural-interface/public/shared/assistant/asst-limit-wait.js +294 -0
  261. package/neural-interface/public/shared/assistant/asst-limit.js +168 -0
  262. package/neural-interface/public/shared/assistant/asst-mascot.js +49 -12
  263. package/neural-interface/public/shared/assistant/asst-menu.js +7 -6
  264. package/neural-interface/public/shared/assistant/asst-panel.js +106 -11
  265. package/neural-interface/public/shared/assistant/asst-rack-styles.js +66 -49
  266. package/neural-interface/public/shared/assistant/asst-render.js +401 -77
  267. package/neural-interface/public/shared/assistant/asst-route.js +83 -12
  268. package/neural-interface/public/shared/assistant/asst-scenes.js +2 -0
  269. package/neural-interface/public/shared/assistant/asst-sidepanel.js +67 -4
  270. package/neural-interface/public/shared/assistant/asst-slash.js +9 -7
  271. package/neural-interface/public/shared/assistant/asst-state.js +11 -15
  272. package/neural-interface/public/shared/assistant/asst-stop.js +127 -0
  273. package/neural-interface/public/shared/assistant/asst-styles.js +59 -21
  274. package/neural-interface/public/shared/assistant/asst-tool-kinds.js +156 -16
  275. package/neural-interface/public/shared/automation-context.js +5 -2
  276. package/neural-interface/public/shared/cc-dropdown.js +89 -19
  277. package/neural-interface/public/shared/cdx/cdx-context-menu.js +10 -9
  278. package/neural-interface/public/shared/cdx/cdx-copy.js +16 -0
  279. package/neural-interface/public/shared/cdx/cdx-output-model.js +22 -1
  280. package/neural-interface/public/shared/cdx/cdx-output.js +8 -7
  281. package/neural-interface/public/shared/cdx/cdx-panel.js +45 -149
  282. package/neural-interface/public/shared/cdx/cdx-protocol.js +28 -1
  283. package/neural-interface/public/shared/cdx/cdx-render.js +47 -29
  284. package/neural-interface/public/shared/cdx/cdx-requests.js +3 -3
  285. package/neural-interface/public/shared/cdx/cdx-skill-hints.js +54 -0
  286. package/neural-interface/public/shared/cdx/cdx-styles.js +11 -3
  287. package/neural-interface/public/shared/cdx/cdx-tabs.js +52 -39
  288. package/neural-interface/public/shared/cdx/cdx-ws.js +0 -1
  289. package/neural-interface/public/shared/cli-install-view.js +4 -8
  290. package/neural-interface/public/shared/cli-status.js +2 -2
  291. package/neural-interface/public/shared/constants.js +2 -2
  292. package/neural-interface/public/shared/context-menu-areas.js +34 -0
  293. package/neural-interface/public/shared/context-menu-logic.js +243 -0
  294. package/neural-interface/public/shared/context-menu-model.js +366 -0
  295. package/neural-interface/public/shared/context-menu.js +372 -0
  296. package/neural-interface/public/shared/cp/cp-context-menu.js +10 -9
  297. package/neural-interface/public/shared/crash-notice-view.js +168 -0
  298. package/neural-interface/public/shared/desktop-update-view.js +20 -0
  299. package/neural-interface/public/shared/editor/editor-panel-logic.js +2 -2
  300. package/neural-interface/public/shared/html-shell.js +9 -11
  301. package/neural-interface/public/shared/i18n.js +2 -0
  302. package/neural-interface/public/shared/ocp-v2/ocp-v2-approvals.js +7 -7
  303. package/neural-interface/public/shared/ocp-v2/ocp-v2-binding.js +4 -4
  304. package/neural-interface/public/shared/ocp-v2/ocp-v2-changes-logic.js +3 -101
  305. package/neural-interface/public/shared/ocp-v2/ocp-v2-childpanel.js +2 -0
  306. package/neural-interface/public/shared/ocp-v2/ocp-v2-compact-button.js +1 -3
  307. package/neural-interface/public/shared/ocp-v2/ocp-v2-composer-logic.js +2 -6
  308. package/neural-interface/public/shared/ocp-v2/ocp-v2-context-menu.js +11 -11
  309. package/neural-interface/public/shared/ocp-v2/ocp-v2-context-model.js +0 -3
  310. package/neural-interface/public/shared/ocp-v2/ocp-v2-events.js +8 -4
  311. package/neural-interface/public/shared/ocp-v2/ocp-v2-manager.js +7 -7
  312. package/neural-interface/public/shared/ocp-v2/ocp-v2-outcome-notifications.js +16 -0
  313. package/neural-interface/public/shared/ocp-v2/ocp-v2-panel.js +47 -252
  314. package/neural-interface/public/shared/ocp-v2/ocp-v2-plan.js +1 -2
  315. package/neural-interface/public/shared/ocp-v2/ocp-v2-projectbar.js +95 -202
  316. package/neural-interface/public/shared/ocp-v2/ocp-v2-render.js +6 -21
  317. package/neural-interface/public/shared/ocp-v2/ocp-v2-send.js +4 -4
  318. package/neural-interface/public/shared/ocp-v2/ocp-v2-session-actions.js +8 -61
  319. package/neural-interface/public/shared/ocp-v2/ocp-v2-sessions-logic.js +2 -91
  320. package/neural-interface/public/shared/ocp-v2/ocp-v2-slash-hints.js +16 -15
  321. package/neural-interface/public/shared/ocp-v2/ocp-v2-state.js +8 -21
  322. package/neural-interface/public/shared/ocp-v2/ocp-v2-status-logic.js +1 -99
  323. package/neural-interface/public/shared/ocp-v2/ocp-v2-status.js +5 -35
  324. package/neural-interface/public/shared/ocp-v2/ocp-v2-styles.js +0 -21
  325. package/neural-interface/public/shared/ocp-v2/{ocp-v2-profile-inheritance.js → ocp-v2-tools-inheritance.js} +16 -16
  326. package/neural-interface/public/shared/ocp-v2/ocp-v2-ws.js +14 -47
  327. package/neural-interface/public/shared/page-session.js +96 -0
  328. package/neural-interface/public/shared/registry.js +5 -3
  329. package/neural-interface/public/shared/retired-2d.js +3 -0
  330. package/neural-interface/public/shared/schedules-view.js +195 -61
  331. package/neural-interface/public/shared/settings/settings-claude-hooks.js +135 -0
  332. package/neural-interface/public/shared/settings/settings-data.js +3 -1
  333. package/neural-interface/public/shared/settings/settings-ia.js +6 -6
  334. package/neural-interface/public/shared/settings/settings-opencode.js +89 -0
  335. package/neural-interface/public/shared/settings/settings-skill-folders-pane.js +265 -0
  336. package/neural-interface/public/shared/settings/settings-skill-folders.js +130 -0
  337. package/neural-interface/public/shared/settings/settings-worker-guard.js +72 -0
  338. package/neural-interface/public/shared/skills/ss-args.js +96 -0
  339. package/neural-interface/public/shared/skills/ss-creation.js +219 -0
  340. package/neural-interface/public/shared/skills/ss-dialog.js +130 -0
  341. package/neural-interface/public/shared/skills/ss-doc.js +173 -0
  342. package/neural-interface/public/shared/skills/ss-eval-adapters.js +269 -0
  343. package/neural-interface/public/shared/skills/ss-eval-grade.js +359 -0
  344. package/neural-interface/public/shared/skills/ss-eval-optimise.js +153 -0
  345. package/neural-interface/public/shared/skills/ss-eval-plan.js +315 -0
  346. package/neural-interface/public/shared/skills/ss-evals.js +417 -0
  347. package/neural-interface/public/shared/skills/ss-form.js +159 -0
  348. package/neural-interface/public/shared/skills/ss-frontmatter.js +376 -0
  349. package/neural-interface/public/shared/skills/ss-ids.js +32 -0
  350. package/neural-interface/public/shared/skills/ss-lint.js +141 -0
  351. package/neural-interface/public/shared/skills/ss-presets.js +117 -0
  352. package/neural-interface/public/shared/skills/ss-profiles.js +475 -0
  353. package/neural-interface/public/shared/skills/ss-resources.js +165 -0
  354. package/neural-interface/public/shared/skills/ss-review-view.js +190 -0
  355. package/neural-interface/public/shared/skills/ss-tabs.js +79 -0
  356. package/neural-interface/public/shared/skills/ss-unicode.js +135 -0
  357. package/neural-interface/public/shared/skills/studio/sx-actions.js +222 -0
  358. package/neural-interface/public/shared/skills/studio/sx-cm.js +101 -0
  359. package/neural-interface/public/shared/skills/studio/sx-create-ai-view.js +749 -0
  360. package/neural-interface/public/shared/skills/studio/sx-create-ai.js +236 -0
  361. package/neural-interface/public/shared/skills/studio/sx-create-view.js +254 -0
  362. package/neural-interface/public/shared/skills/studio/sx-create.js +126 -0
  363. package/neural-interface/public/shared/skills/studio/sx-diff-view.js +43 -0
  364. package/neural-interface/public/shared/skills/studio/sx-diff.js +133 -0
  365. package/neural-interface/public/shared/skills/studio/sx-docs.js +480 -0
  366. package/neural-interface/public/shared/skills/studio/sx-dom.js +229 -0
  367. package/neural-interface/public/shared/skills/studio/sx-edit-view.js +848 -0
  368. package/neural-interface/public/shared/skills/studio/sx-editor-model.js +193 -0
  369. package/neural-interface/public/shared/skills/studio/sx-errors.js +22 -0
  370. package/neural-interface/public/shared/skills/studio/sx-geometry.js +82 -0
  371. package/neural-interface/public/shared/skills/studio/sx-import.js +262 -0
  372. package/neural-interface/public/shared/skills/studio/sx-inspector.js +308 -0
  373. package/neural-interface/public/shared/skills/studio/sx-install-flow.js +279 -0
  374. package/neural-interface/public/shared/skills/studio/sx-install.js +296 -0
  375. package/neural-interface/public/shared/skills/studio/sx-library-view.js +639 -0
  376. package/neural-interface/public/shared/skills/studio/sx-library.js +475 -0
  377. package/neural-interface/public/shared/skills/studio/sx-main.js +681 -0
  378. package/neural-interface/public/shared/skills/studio/sx-operations-view.js +98 -0
  379. package/neural-interface/public/shared/skills/studio/sx-operations.js +11 -0
  380. package/neural-interface/public/shared/skills/studio/sx-plan.js +158 -0
  381. package/neural-interface/public/shared/skills/studio/sx-publish-view.js +621 -0
  382. package/neural-interface/public/shared/skills/studio/sx-review-view.js +369 -0
  383. package/neural-interface/public/shared/skills/studio/sx-review.js +148 -0
  384. package/neural-interface/public/shared/skills/studio/sx-scan.js +35 -0
  385. package/neural-interface/public/shared/skills/studio/sx-snippets.js +96 -0
  386. package/neural-interface/public/shared/skills/studio/sx-subject.js +248 -0
  387. package/neural-interface/public/shared/skills/studio/sx-test-view.js +994 -0
  388. package/neural-interface/public/shared/skills/studio/sx-test.js +328 -0
  389. package/neural-interface/public/shared/skills/studio/sx-versions-view.js +241 -0
  390. package/neural-interface/public/shared/skills/studio/sx-workspace-view.js +425 -0
  391. package/neural-interface/public/shared/styleguide/sg-panel.js +4 -2
  392. package/neural-interface/public/shared/styles.css +1525 -1779
  393. package/neural-interface/public/shared/synabun-mascot.js +1115 -9
  394. package/neural-interface/public/shared/tool-list-picker.js +55 -0
  395. package/neural-interface/public/shared/tool-list-storage.js +24 -0
  396. package/neural-interface/public/shared/tool-list-view.js +112 -0
  397. package/neural-interface/public/shared/tour/tour-actor.js +268 -0
  398. package/neural-interface/public/shared/tour/tour-beats.js +336 -0
  399. package/neural-interface/public/shared/tour/tour-engine.js +884 -0
  400. package/neural-interface/public/shared/tour/tour-ink.js +390 -0
  401. package/neural-interface/public/shared/tour/tour-stage.js +440 -0
  402. package/neural-interface/public/shared/tour/tour-state.js +40 -0
  403. package/neural-interface/public/shared/tour/tour-tips.js +99 -0
  404. package/neural-interface/public/shared/tour/tour.css +144 -0
  405. package/neural-interface/public/shared/ui-automation-studio.js +91 -128
  406. package/neural-interface/public/shared/ui-claude-panel.js +77 -5
  407. package/neural-interface/public/shared/ui-command-runner.js +6 -3
  408. package/neural-interface/public/shared/ui-context-menu.js +295 -0
  409. package/neural-interface/public/shared/ui-cost-widget.js +57 -59
  410. package/neural-interface/public/shared/ui-crash-notice.js +187 -0
  411. package/neural-interface/public/shared/ui-detail.js +15 -3
  412. package/neural-interface/public/shared/ui-image-gallery.js +50 -47
  413. package/neural-interface/public/shared/ui-keybinds.js +26 -1
  414. package/neural-interface/public/shared/ui-menubar.js +8 -18
  415. package/neural-interface/public/shared/ui-native-loop-router-state.js +5 -0
  416. package/neural-interface/public/shared/ui-native-loop-router.js +7 -1
  417. package/neural-interface/public/shared/ui-navbar.js +4 -24
  418. package/neural-interface/public/shared/ui-panels.js +96 -65
  419. package/neural-interface/public/shared/ui-schedules-studio.js +507 -423
  420. package/neural-interface/public/shared/ui-sessions.js +5 -3
  421. package/neural-interface/public/shared/ui-settings.js +594 -462
  422. package/neural-interface/public/shared/ui-sidepanel-sessions.js +1 -1
  423. package/neural-interface/public/shared/ui-sidepanel-state.js +23 -12
  424. package/neural-interface/public/shared/ui-sidepanel-windows.js +16 -11
  425. package/neural-interface/public/shared/ui-skills.js +33 -2830
  426. package/neural-interface/public/shared/ui-styleguide.js +5 -2
  427. package/neural-interface/public/shared/ui-sync.js +15 -5
  428. package/neural-interface/public/shared/ui-terminal.js +124 -180
  429. package/neural-interface/public/shared/ui-tool-updates.js +3 -1
  430. package/neural-interface/public/shared/ui-tooltip.js +10 -5
  431. package/neural-interface/public/shared/ui-trash.js +6 -4
  432. package/neural-interface/public/shared/ui-tutorial-layout.js +3 -117
  433. package/neural-interface/public/shared/ui-tutorial-preview.js +103 -0
  434. package/neural-interface/public/shared/ui-tutorial-steps.js +3 -65
  435. package/neural-interface/public/shared/ui-tutorial.css +47 -100
  436. package/neural-interface/public/shared/ui-tutorial.js +285 -509
  437. package/neural-interface/public/shared/ui-update.js +38 -2
  438. package/neural-interface/public/shared/ui-whiteboard.js +311 -58
  439. package/neural-interface/public/shared/ui-worker-end.js +4 -0
  440. package/neural-interface/public/shared/ui-workspaces.js +3 -2
  441. package/neural-interface/public/shared/view-variant.js +66 -0
  442. package/neural-interface/public/shared/whatsapp/wa-view.js +1 -1
  443. package/neural-interface/public/shared/whiteboard-list.js +172 -0
  444. package/neural-interface/public/shared/worker-end.js +10 -3
  445. package/neural-interface/public/shared/worker-restart.js +12 -0
  446. package/neural-interface/public/sidepanel-session.html +1 -1
  447. package/neural-interface/public/variant/2d/background.js +2 -1
  448. package/neural-interface/public/variant/2d/context-menu.js +8 -2
  449. package/neural-interface/public/variant/2d/graph.js +42 -20
  450. package/neural-interface/public/variant/2d/hulls.js +14 -9
  451. package/neural-interface/public/variant/2d/lasso.js +11 -7
  452. package/neural-interface/public/variant/2d/main.js +32 -1
  453. package/neural-interface/public/variant/2d/minimap.js +11 -13
  454. package/neural-interface/public/variant/3d/main.js +69 -6
  455. package/neural-interface/public/variant/3d/map-controls.js +24 -9
  456. package/neural-interface/public/vendor/caveat/OFL.txt +93 -0
  457. package/neural-interface/public/vendor/caveat/caveat-latin-400-normal.woff2 +0 -0
  458. package/neural-interface/public/vendor/caveat/caveat-latin-700-normal.woff2 +0 -0
  459. package/neural-interface/public/vendor/caveat/caveat.css +17 -0
  460. package/neural-interface/public/vendor/caveat/manifest.json +12 -0
  461. package/neural-interface/public/vendor/yaml/LICENSE +13 -0
  462. package/neural-interface/public/vendor/yaml/manifest.json +4 -0
  463. package/neural-interface/public/vendor/yaml/yaml-2.9.1.min.js +137 -0
  464. package/neural-interface/scripts/build-vendor.mjs +32 -0
  465. package/neural-interface/server.js +3934 -2454
  466. package/neural-interface/templates/rulesets/core.md +1 -1
  467. package/neural-interface/templates/rulesets/legacy-hashes.json +18 -0
  468. package/neural-interface/templates/rulesets/manifest.json +8 -8
  469. package/npm-shrinkwrap.json +18 -12
  470. package/package.json +16 -3
  471. package/postinstall.js +9 -4
  472. package/preuninstall.js +1 -1
  473. package/setup.js +97 -322
  474. package/skills/skill-forge/SKILL.md +177 -0
  475. package/skills/skill-forge/evals/evals.json +54 -0
  476. package/skills/skill-forge/references/package.md +105 -0
  477. package/skills/skill-forge/references/review-and-recovery.md +63 -0
  478. package/skills/skill-forge/references/runtime-profiles.md +20 -0
  479. package/skills/skill-forge/references/sources-and-capabilities.md +51 -0
  480. package/skills/synabun/SKILL.md +10 -7
  481. package/skills/synabun/modules/audit.md +1 -5
  482. package/skills/synabun/modules/changelog.md +1 -5
  483. package/skills/synabun/modules/idea.md +1 -1
  484. package/skills/synabun/modules/memorize.md +6 -9
  485. package/skills/synabun/modules/schedule.md +4 -4
  486. package/mcp-server/dist/services/profiles.d.ts +0 -120
  487. package/mcp-server/dist/services/profiles.d.ts.map +0 -1
  488. package/mcp-server/dist/services/profiles.js +0 -387
  489. package/mcp-server/dist/services/profiles.js.map +0 -1
  490. package/mcp-server/dist/tools/leonardo-browser-tools.d.ts +0 -97
  491. package/mcp-server/dist/tools/leonardo-browser-tools.d.ts.map +0 -1
  492. package/mcp-server/dist/tools/leonardo-browser-tools.js +0 -228
  493. package/mcp-server/dist/tools/leonardo-browser-tools.js.map +0 -1
  494. package/mcp-server/dist/tools/leonardo.d.ts +0 -13
  495. package/mcp-server/dist/tools/leonardo.d.ts.map +0 -1
  496. package/mcp-server/dist/tools/leonardo.js +0 -21
  497. package/mcp-server/dist/tools/leonardo.js.map +0 -1
  498. package/mcp-server/dist/tools/profile.d.ts +0 -17
  499. package/mcp-server/dist/tools/profile.d.ts.map +0 -1
  500. package/mcp-server/dist/tools/profile.js +0 -114
  501. package/mcp-server/dist/tools/profile.js.map +0 -1
  502. package/mcp-server/src/services/profiles.ts +0 -428
  503. package/mcp-server/src/tools/leonardo-browser-tools.ts +0 -291
  504. package/mcp-server/src/tools/leonardo.ts +0 -30
  505. package/mcp-server/src/tools/profile.ts +0 -122
  506. package/neural-interface/lib/assistant-brains/opencode-browser-policy.js +0 -47
  507. package/neural-interface/lib/assistant-brains/opencode-route-gate.js +0 -62
  508. package/neural-interface/lib/mcp-profile-servers.js +0 -120
  509. package/neural-interface/public/shared/ui-tutorial-draw.js +0 -311
  510. package/skills/leonardo/SKILL.md +0 -168
  511. package/skills/leonardo/icon.svg +0 -1
  512. package/skills/leonardo/modules/browser-guide.md +0 -378
  513. package/skills/leonardo/modules/image-prompter.md +0 -283
  514. package/skills/leonardo/modules/model-advisor.md +0 -100
  515. package/skills/leonardo/modules/prompt-library.md +0 -110
  516. package/skills/leonardo/modules/style-guide.md +0 -186
  517. package/skills/leonardo/modules/video-prompter.md +0 -317
@@ -1,6 +1,9 @@
1
+ import { cxpText, cxpSessionLabel, setCodexTranslator } from './cdx-copy.js';
1
2
  // SynaBun — Codex Panel: DOM, Events & Lifecycle
2
3
  // ═══════════════════════════════════════════
3
4
 
5
+ import { workerRestart } from '../worker-restart.js';
6
+ import { t } from '../i18n.js';
4
7
  import { storage } from '../storage.js';
5
8
  import { state, emit, on } from '../state.js';
6
9
  import { registerSidepanel, setSidepanelVisible, sidepanelAcceptsKeyboard, openAnotherSidepanelSession } from '../ui-sidepanel-windows.js';
@@ -8,6 +11,7 @@ import { mountCliBanner } from '../ui-cli-banner.js';
8
11
  import { nativeLoopWindowId } from '../ui-native-window-id.js';
9
12
  import { createStickyScrollController, getStickyScrollController } from '../ui-scroll-follow.js';
10
13
  import { wireFileLinks } from '../ui-file-links.js';
14
+ import { frameRect } from '../app-frame.js';
11
15
  import { trackWorkerEnd } from '../ui-worker-end.js';
12
16
  import { isDispatchedRun } from '../worker-end.js';
13
17
  import { runAwaitsAnswer } from '../sidepanel-session-status.js';
@@ -255,6 +259,8 @@ export function panelEl(selector) {
255
259
  // buildPanel — DOM Construction
256
260
  // ═══════════════════════════════════════════
257
261
 
262
+ setCodexTranslator(t);
263
+
258
264
  function buildPanel() {
259
265
  const panel = document.createElement('div');
260
266
  panel.id = 'codex-panel';
@@ -262,18 +268,18 @@ function buildPanel() {
262
268
  panel.innerHTML = `
263
269
  <div class="cxp-resize-handle"></div>
264
270
  <div class="cxp-header">
265
- <button class="cxp-session-btn" id="cxp-session-btn" type="button" title="${esc(_sessionLabel)}">
266
- <span class="cxp-session-label" id="cxp-session-label">${esc(_sessionLabel)}</span>
271
+ <button class="cxp-session-btn" id="cxp-session-btn" type="button" title="${esc(cxpSessionLabel(_sessionLabel))}">
272
+ <span class="cxp-session-label" id="cxp-session-label">${esc(cxpSessionLabel(_sessionLabel))}</span>
267
273
  <span class="cxp-dd-arrow">&#x25BE;</span>
268
274
  </button>
269
- <button class="cxp-header-rename" id="cxp-header-rename" type="button" title="Rename session">
275
+ <button class="cxp-header-rename" id="cxp-header-rename" type="button" title="${cxpText('rename', 'Rename session')}">
270
276
  ${ICON_EDIT}
271
277
  </button>
272
278
  <div class="cxp-actions">
273
- <button class="cxp-btn" id="cxp-new" title="New Codex tab">${ICON_PLUS}</button>
274
- <button class="cxp-btn" id="cxp-minimize" title="Minimize to pill">${ICON_MINIMIZE}</button>
275
- <button class="cxp-btn cxp-btn-danger" id="cxp-close" title="Close current tab">${ICON_X}</button>
276
- <button class="cxp-btn" id="cxp-slide" title="Slide panel"><svg viewBox="0 0 24 24"><polyline points="9 18 15 12 9 6"/></svg></button>
279
+ <button class="cxp-btn" id="cxp-new" title="${cxpText('newTab', 'New Codex tab')}">${ICON_PLUS}</button>
280
+ <button class="cxp-btn" id="cxp-minimize" title="${cxpText('minimize', 'Minimize to pill')}">${ICON_MINIMIZE}</button>
281
+ <button class="cxp-btn cxp-btn-danger" id="cxp-close" title="${cxpText('closeTab', 'Close current tab')}">${ICON_X}</button>
282
+ <button class="cxp-btn" id="cxp-slide" title="${cxpText('slide', 'Slide panel')}"><svg viewBox="0 0 24 24"><polyline points="9 18 15 12 9 6"/></svg></button>
277
283
  </div>
278
284
  <div class="cxp-session-menu" id="cxp-session-menu"></div>
279
285
  </div>
@@ -290,28 +296,23 @@ function buildPanel() {
290
296
  <div class="cxp-queue-list" id="cxp-queue-list"></div>
291
297
  </div>
292
298
  <div class="cxp-projectbar">
293
- <div class="cxp-dropdown" id="cxp-project" data-placeholder="project..." data-tooltip="Project">
299
+ <div class="cxp-dropdown" id="cxp-project" data-placeholder="project..." data-tooltip="${cxpText('project', 'Project')}">
294
300
  <span class="cxp-dd-label">project...</span>
295
301
  <span class="cxp-dd-arrow">&#x25BE;</span>
296
302
  <div class="cxp-dd-menu"></div>
297
303
  </div>
298
- <div class="cxp-dropdown cxp-dropdown-sm" id="cxp-branch" data-placeholder="branch" data-tooltip="Branch">
304
+ <div class="cxp-dropdown cxp-dropdown-sm" id="cxp-branch" data-placeholder="branch" data-tooltip="${cxpText('branch', 'Branch')}">
299
305
  <span class="cxp-dd-label">branch</span>
300
306
  <span class="cxp-dd-arrow">&#x25BE;</span>
301
307
  <div class="cxp-dd-menu"></div>
302
308
  </div>
303
- <div class="cxp-dropdown cxp-dropdown-sm" id="cxp-profile" data-placeholder="profile" data-tooltip="Tool profile">
304
- <span class="cxp-dd-label">full</span>
305
- <span class="cxp-dd-arrow">&#x25BE;</span>
306
- <div class="cxp-dd-menu"></div>
307
- </div>
308
- <div class="cxp-dropdown cxp-dropdown-sm" id="cxp-recall" data-placeholder="recall" data-tooltip="Recall profile">
309
+ <div class="cxp-dropdown cxp-dropdown-sm" id="cxp-recall" data-placeholder="recall" data-tooltip="${cxpText('recallProfile', 'Recall profile')}">
309
310
  <span class="cxp-dd-label">recall</span>
310
311
  <span class="cxp-dd-arrow">&#x25BE;</span>
311
312
  <div class="cxp-dd-menu"></div>
312
313
  </div>
313
314
  <div class="cxp-projectbar-actions">
314
- <button class="cxp-bar-action" id="cxp-action-changelog" title="Generate changelog"><svg viewBox="0 0 16 16" width="12" height="12" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M4 1.5h8.5v13H4a1.5 1.5 0 01-1.5-1.5V3A1.5 1.5 0 014 1.5z"/><path d="M5.5 5h5M5.5 7.5h3M5.5 10h4"/></svg></button>
315
+ <button class="cxp-bar-action" id="cxp-action-changelog" title="${cxpText('changelog', 'Generate changelog')}"><svg viewBox="0 0 16 16" width="12" height="12" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M4 1.5h8.5v13H4a1.5 1.5 0 01-1.5-1.5V3A1.5 1.5 0 014 1.5z"/><path d="M5.5 5h5M5.5 7.5h3M5.5 10h4"/></svg></button>
315
316
  </div>
316
317
  </div>
317
318
  <div class="cxp-image-strip" id="cxp-image-strip" hidden></div>
@@ -319,11 +320,11 @@ function buildPanel() {
319
320
  <div class="cxp-input-wrap">
320
321
  <div class="cxp-input-shell">
321
322
  <input type="file" id="cxp-file-input" accept="image/*" multiple hidden />
322
- <textarea class="cxp-input" id="cxp-input" rows="1" placeholder="Message Codex…" spellcheck="false"></textarea>
323
- <button class="cxp-mic-btn" id="cxp-mic-btn" title="Hold to talk" hidden>
323
+ <textarea class="cxp-input" id="cxp-input" rows="1" placeholder="${cxpText('message', 'Message Codex…')}" spellcheck="false"></textarea>
324
+ <button class="cxp-mic-btn" id="cxp-mic-btn" title="${cxpText('talk', 'Hold to talk')}" hidden>
324
325
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="9" y="1" width="6" height="11" rx="3"/><path d="M5 10a7 7 0 0 0 14 0"/><path d="M12 17v4M8 21h8"/></svg>
325
326
  </button>
326
- <button class="cxp-send" id="cxp-send" disabled title="Send">
327
+ <button class="cxp-send" id="cxp-send" disabled title="${cxpText('send', 'Send')}">
327
328
  <svg class="cxp-send-icon" viewBox="0 0 24 24"><path d="M12 5v14"/><path d="m5 12 7-7 7 7"/></svg>
328
329
  <svg class="cxp-stop-icon" viewBox="0 0 24 24" style="display:none"><rect x="7" y="7" width="10" height="10" rx="2"/></svg>
329
330
  </button>
@@ -332,21 +333,21 @@ function buildPanel() {
332
333
  <div class="cxp-slash-hints" id="cxp-slash-hints" hidden></div>
333
334
  <div class="cxp-footer-toolbar">
334
335
  <div class="cxp-footer-left">
335
- <a class="cxp-brand-link" href="https://chatgpt.com/codex/settings/usage" target="_blank" rel="noopener noreferrer" title="Open Codex usage settings">
336
+ <a class="cxp-brand-link" href="https://chatgpt.com/codex/settings/usage" target="_blank" rel="noopener noreferrer" title="${cxpText('usage', 'Open Codex usage settings')}">
336
337
  <svg class="cxp-brand" viewBox="0 0 24 24" width="16" height="16" fill="currentColor"><path d="M22.282 9.821a5.985 5.985 0 0 0-.516-4.91 6.046 6.046 0 0 0-6.51-2.9A6.065 6.065 0 0 0 4.981 4.18a5.998 5.998 0 0 0-3.998 2.9 6.046 6.046 0 0 0 .743 7.097 5.98 5.98 0 0 0 .51 4.911 6.051 6.051 0 0 0 6.515 2.9A5.985 5.985 0 0 0 13.26 24a6.056 6.056 0 0 0 5.772-4.206 5.99 5.99 0 0 0 3.997-2.9 6.056 6.056 0 0 0-.747-7.073zM13.26 22.43a4.476 4.476 0 0 1-2.876-1.04l.141-.081 4.779-2.758a.795.795 0 0 0 .392-.681v-6.737l2.02 1.168a.071.071 0 0 1 .038.052v5.583a4.504 4.504 0 0 1-4.494 4.494zM3.6 18.304a4.47 4.47 0 0 1-.535-3.014l.142.085 4.783 2.759a.771.771 0 0 0 .78 0l5.843-3.369v2.332a.08.08 0 0 1-.033.062L9.74 19.95a4.5 4.5 0 0 1-6.14-1.646zM2.34 7.896a4.485 4.485 0 0 1 2.366-1.973V11.6a.766.766 0 0 0 .388.676l5.815 3.355-2.02 1.168a.076.076 0 0 1-.071 0l-4.83-2.786A4.504 4.504 0 0 1 2.34 7.872zm16.597 3.855l-5.833-3.387L15.119 7.2a.076.076 0 0 1 .071 0l4.83 2.791a4.494 4.494 0 0 1-.676 8.105v-5.678a.79.79 0 0 0-.407-.667zm2.01-3.023l-.141-.085-4.774-2.782a.776.776 0 0 0-.785 0L9.409 9.23V6.897a.066.066 0 0 1 .028-.061l4.83-2.787a4.5 4.5 0 0 1 6.68 4.66zm-12.64 4.135l-2.02-1.164a.08.08 0 0 1-.038-.057V6.075a4.5 4.5 0 0 1 7.375-3.453l-.142.08L8.704 5.46a.795.795 0 0 0-.393.681zm1.097-2.365l2.602-1.5 2.607 1.5v2.999l-2.597 1.5-2.607-1.5z"/></svg>
337
338
  </a>
338
- <button class="cxp-attach-btn" id="cxp-attach-btn" title="Attach images">
339
+ <button class="cxp-attach-btn" id="cxp-attach-btn" title="${cxpText('attach', 'Attach images')}">
339
340
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48"/></svg>
340
341
  </button>
341
342
  </div>
342
343
  <div class="cxp-footer-right">
343
344
  <div class="cxp-effort-wrap">
344
- <button class="cxp-toolbar-toggle" id="cxp-effort-toggle" title="Reasoning effort" data-effort="off" type="button">${ICON_BRAIN}<span class="cxp-btn-label">Effort</span><span class="cxp-effort-dots"><i></i><i></i><i></i><i></i><i></i></span></button>
345
+ <button class="cxp-toolbar-toggle" id="cxp-effort-toggle" title="${cxpText('effort', 'Reasoning effort')}" data-effort="off" type="button">${ICON_BRAIN}<span class="cxp-btn-label">${cxpText('effortLabel', 'Effort')}</span><span class="cxp-effort-dots"><i></i><i></i><i></i><i></i><i></i></span></button>
345
346
  <div class="cxp-effort-menu" id="cxp-effort-menu"></div>
346
347
  </div>
347
- <button class="cxp-toolbar-toggle" id="cxp-plan-toggle" title="Plan mode: off">${ICON_PLAN}<span class="cxp-btn-label">Plan</span></button>
348
- <button class="cxp-toolbar-toggle" id="cxp-autoaccept-toggle" title="Auto-accept: off">${ICON_SHIELD}<span class="cxp-btn-label">Auto</span></button>
349
- <button class="cxp-toolbar-toggle" id="cxp-context-toggle" type="button" aria-pressed="false" title="Context: provider default">${ICON_SPARK}<span class="cxp-btn-label">Default</span></button>
348
+ <button class="cxp-toolbar-toggle" id="cxp-plan-toggle" title="${cxpText('planOff', 'Plan mode: off')}">${ICON_PLAN}<span class="cxp-btn-label">${cxpText('plan', 'Plan')}</span></button>
349
+ <button class="cxp-toolbar-toggle" id="cxp-autoaccept-toggle" title="${cxpText('autoOff', 'Auto-accept: off')}">${ICON_SHIELD}<span class="cxp-btn-label">${cxpText('auto', 'Auto')}</span></button>
350
+ <button class="cxp-toolbar-toggle" id="cxp-context-toggle" type="button" aria-pressed="false" title="${cxpText('contextDefault', 'Context: provider default')}">${ICON_SPARK}<span class="cxp-btn-label">${cxpText('default', 'Default')}</span></button>
350
351
  <button class="cxp-toolbar-toggle" id="cxp-context-retry" type="button" hidden aria-label="Retry model capabilities" title="Reload model capabilities">Retry</button>
351
352
  <div class="cxp-dropdown" id="cxp-model" data-placeholder="model...">
352
353
  <span class="cxp-dd-label">model...</span>
@@ -518,7 +519,6 @@ function applyVisibility(nextVisible) {
518
519
  if (!_tabs.length) createTab({ project: storage.getItem(STOR.project) || '' });
519
520
  state.lastActivePanel = 'codex';
520
521
  updateActiveTabView();
521
- loadCurrentProfile();
522
522
  loadRecallProfile();
523
523
  panelEl('#cxp-input')?.focus();
524
524
  refreshCliBanner();
@@ -551,111 +551,6 @@ async function loadBranches(path) {
551
551
  } catch {}
552
552
  }
553
553
 
554
- // ═══════════════════════════════════════════
555
- // MCP Profile — live profile switching
556
- // ═══════════════════════════════════════════
557
-
558
- let _mcpProfiles = [];
559
- let _currentProfile = 'full';
560
- let _defaultMcpProfile = 'full';
561
-
562
- function mcpProfileItemsFromPresets(presets) {
563
- if (!presets || typeof presets !== 'object') return null;
564
- return Object.entries(presets).map(([value, p]) => ({
565
- value,
566
- label: p?.label || value,
567
- hint: `${p?.tools || '?'} tools`,
568
- }));
569
- }
570
-
571
- function applyMcpProfileState(profile, presets) {
572
- if (profile) _currentProfile = profile;
573
- const items = mcpProfileItemsFromPresets(presets);
574
- if (items) _mcpProfiles = items;
575
- const $profile = panelEl('#cxp-profile');
576
- if ($profile) populateProfileDropdown($profile);
577
- }
578
-
579
- async function loadCurrentProfile() {
580
- const $profile = panelEl('#cxp-profile');
581
- if (!$profile) return;
582
- try {
583
- const resp = await fetch('/api/mcp/profile');
584
- const data = await resp.json();
585
- if (data.ok) {
586
- _defaultMcpProfile = data.defaultProfile || data.profile || 'full';
587
- const tab = activeTab();
588
- if (tab && !tab.mcpProfile) {
589
- tab.mcpProfile = _defaultMcpProfile;
590
- saveTabs();
591
- }
592
- applyMcpProfileState(tab?.mcpProfile || _defaultMcpProfile, data.presets);
593
- return;
594
- }
595
- } catch {}
596
- populateProfileDropdown($profile);
597
- }
598
-
599
- function populateProfileDropdown($dd) {
600
- const menu = $dd.querySelector('.cxp-dd-menu');
601
- const label = $dd.querySelector('.cxp-dd-label');
602
- if (!menu || !label) return;
603
- menu.innerHTML = '';
604
- const matched = _mcpProfiles.find(p => p.value === _currentProfile);
605
- label.textContent = matched ? matched.label : _currentProfile;
606
- $dd.classList.add('has-value');
607
- $dd._value = _currentProfile;
608
- for (const p of _mcpProfiles) {
609
- const el = document.createElement('div');
610
- el.className = 'cxp-dd-item' + (p.value === _currentProfile ? ' selected' : '');
611
- el.dataset.value = p.value;
612
- el.innerHTML = `<span>${p.label}</span><span style="opacity:0.35;margin-left:auto;font-size:9px">${p.hint}</span>`;
613
- el.style.display = 'flex'; el.style.gap = '6px';
614
- el.addEventListener('click', async () => {
615
- if (p.value === _currentProfile) { $dd.classList.remove('open'); return; }
616
- const previous = _currentProfile;
617
- _currentProfile = p.value;
618
- $dd._value = p.value;
619
- label.textContent = p.label;
620
- $dd.classList.remove('open');
621
- menu.querySelectorAll('.cxp-dd-item').forEach(o => o.classList.remove('selected'));
622
- el.classList.add('selected');
623
- try {
624
- await updateMcpProfile(p.value);
625
- populateProfileDropdown($dd);
626
- } catch (err) {
627
- _currentProfile = previous;
628
- populateProfileDropdown($dd);
629
- _host.appendSystem?.(err.message || 'Could not switch MCP profile', 'error');
630
- }
631
- });
632
- menu.appendChild(el);
633
- }
634
- }
635
-
636
- async function updateMcpProfile(profile) {
637
- const tab = activeTab();
638
- if (!tab) throw new Error('No active Codex tab');
639
- if (tab.running || tab.startingThread || tab.automationActive) {
640
- throw new Error('Wait for the active Codex turn or automation to finish before changing its MCP profile.');
641
- }
642
- const result = await requestSocketPayload('mcp_profile_set', {
643
- profile,
644
- threadId: tab.threadId || null,
645
- cwd: tab.project || null,
646
- model: tab.model || null,
647
- contextMode: tab.contextMode === 'extended' ? 'extended' : 'default',
648
- });
649
- const effective = result?.profile || profile;
650
- tab.mcpProfile = effective;
651
- _currentProfile = effective;
652
- saveTabs();
653
- // This selector is tab-scoped. The shared default is changed only through
654
- // an explicit future-runtime/default control, never as a side effect of
655
- // restarting the active Codex app-server.
656
- return effective;
657
- }
658
-
659
554
  // ═══════════════════════════════════════════
660
555
  // Recall Profile — live recall preset switching
661
556
  // ═══════════════════════════════════════════
@@ -666,6 +561,7 @@ const RECALL_PROFILES_META = [
666
561
  { value: 'deep', label: 'Deep', hint: '10 results' },
667
562
  { value: 'custom', label: 'Custom', hint: 'custom' },
668
563
  ];
564
+ function recallLabel(p) { return cxpText(p.value, p.label); }
669
565
  const RECALL_PROFILE_DEFAULTS = {
670
566
  quick: { limit: 3, minImportance: 5, minScore: 0.45, maxChars: 300, includeSessions: 'never', recencyBoost: false },
671
567
  balanced: { limit: 5, minImportance: 0, minScore: 0.30, maxChars: 0, includeSessions: 'auto', recencyBoost: false },
@@ -690,20 +586,20 @@ function populateRecallDropdown($dd) {
690
586
  if (!menu || !label) return;
691
587
  menu.innerHTML = '';
692
588
  const matched = RECALL_PROFILES_META.find(p => p.value === _recallProfile);
693
- label.textContent = matched ? matched.label : _recallProfile;
589
+ label.textContent = matched ? recallLabel(matched) : _recallProfile;
694
590
  $dd.classList.add('has-value');
695
591
  $dd._value = _recallProfile;
696
592
  for (const p of RECALL_PROFILES_META) {
697
593
  const el = document.createElement('div');
698
594
  el.className = 'cxp-dd-item' + (p.value === _recallProfile ? ' selected' : '');
699
595
  el.dataset.value = p.value;
700
- el.innerHTML = `<span>${p.label}</span><span style="opacity:0.35;margin-left:auto;font-size:9px">${p.hint}</span>`;
596
+ el.innerHTML = `<span>${recallLabel(p)}</span><span style="opacity:0.35;margin-left:auto;font-size:9px">${p.hint}</span>`;
701
597
  el.style.display = 'flex'; el.style.gap = '6px';
702
598
  el.addEventListener('click', () => {
703
599
  if (p.value === _recallProfile) { $dd.classList.remove('open'); return; }
704
600
  _recallProfile = p.value;
705
601
  $dd._value = p.value;
706
- label.textContent = p.label;
602
+ label.textContent = recallLabel(p);
707
603
  $dd.classList.remove('open');
708
604
  menu.querySelectorAll('.cxp-dd-item').forEach(o => o.classList.remove('selected'));
709
605
  el.classList.add('selected');
@@ -841,6 +737,7 @@ function wireEvents() {
841
737
  // Context settings: the cog and its popover take the place of the context bar.
842
738
  _contextMenu?.destroy();
843
739
  _contextMenu = mountContextMenu(panelEl('.cxp-actions'), _panel, {
740
+ bounds: frameRect, // the popover stays in the app frame
844
741
  reading: contextMenuReading,
845
742
  data: () => {
846
743
  const data = contextMenuData();
@@ -940,8 +837,6 @@ function wireEvents() {
940
837
  branchDd.classList.remove('cxp-dropdown--busy');
941
838
  }
942
839
  });
943
- const profileDd = panelEl('#cxp-profile');
944
- ddSetup(profileDd);
945
840
  const recallDd = panelEl('#cxp-recall');
946
841
  ddSetup(recallDd);
947
842
  loadRecallProfile();
@@ -1030,10 +925,6 @@ function wireEvents() {
1030
925
  // Initialize voice input
1031
926
  initVoiceInput();
1032
927
 
1033
- on('mcp:profile-changed', (msg = {}) => {
1034
- _defaultMcpProfile = msg.defaultProfile || msg.profile || _defaultMcpProfile;
1035
- applyMcpProfileState(activeTab()?.mcpProfile || _defaultMcpProfile, msg.presets);
1036
- });
1037
928
 
1038
929
  on('codex-panel:show', async (data) => {
1039
930
  setVisible(true);
@@ -1182,9 +1073,6 @@ function ensurePanel() {
1182
1073
  emit,
1183
1074
  on,
1184
1075
  loadBranches,
1185
- activeTabChanged: (tab) => {
1186
- applyMcpProfileState(tab?.mcpProfile || _defaultMcpProfile, null);
1187
- },
1188
1076
  contextMenuSync: () => _contextMenu?.sync(),
1189
1077
  });
1190
1078
 
@@ -1233,6 +1121,7 @@ export async function attachCodexAutomation(run, {
1233
1121
  await ensureProjectsLoaded();
1234
1122
  if (isCancelled()) return { ok: false, reason: 'dismissed' };
1235
1123
  const running = run.status === 'starting' || run.status === 'running';
1124
+ const restart = workerRestart(run);
1236
1125
  // The user continued this run's thread by hand after the run ended: the tab stays theirs. The
1237
1126
  // dock's Focus raises it; the run is let go again, and nothing in the tab changes.
1238
1127
  const own = allTabs().find((entry) => !entry.automationRunId && entry.releasedRunId === run.runId && entry.threadId === threadId);
@@ -1255,7 +1144,6 @@ export async function attachCodexAutomation(run, {
1255
1144
  accountId: run.accountId || 'default',
1256
1145
  model: run.model || '',
1257
1146
  effort: run.effort || 'off',
1258
- mcpProfile: run.mcpProfile || null,
1259
1147
  autoAccept: true,
1260
1148
  planMode: false,
1261
1149
  title: run.title || 'Automation',
@@ -1266,20 +1154,24 @@ export async function attachCodexAutomation(run, {
1266
1154
  // on a question needs you, like one with an approval card up (setRunning and renderPills repaint).
1267
1155
  const working = running && run.turnState !== 'idle' && run.turnState !== 'terminal';
1268
1156
  tab.automationRunId = run.runId;
1269
- tab.automationActive = running;
1157
+ tab.automationActive = restart.active;
1270
1158
  tab.automationAwaits = runAwaitsAnswer(run);
1271
1159
  tab.automationOwnerId = nativeLoopWindowId;
1272
1160
  tab.threadId = threadId;
1273
1161
  tab.project = run.cwd || tab.project;
1274
- tab.mcpProfile = run.mcpProfile || tab.mcpProfile || _defaultMcpProfile;
1275
- tab.sessionLabel = run.title || tab.sessionLabel || 'Automation';
1162
+ tab.automationTitle = run.title || tab.automationTitle || tab.sessionLabel || 'Automation';
1163
+ tab.sessionLabel = tab.automationTitle;
1276
1164
  tab._automationIteration = run.currentIteration;
1277
1165
  tab.planMode = false;
1278
- if (focus) applyMcpProfileState(tab.mcpProfile, null);
1279
1166
  clearPlanHandoffState(tab);
1280
1167
  withTab(tab, () => setRunning(working));
1281
1168
  // The router replays what it buffered right after this attach; when that
1282
1169
  // reaches back to the first prompt, history would only render it twice.
1170
+ if (restart.resumes > (tab._automationResumes || 0)) {
1171
+ tab._automationHydrated = false;
1172
+ tab._automationLiveEvents = false;
1173
+ }
1174
+ tab._automationResumes = restart.resumes;
1283
1175
  if (running && !tab._automationHydrated && !codexAutomationBufferCoversRun(bufferedEvents, bufferTruncated)) {
1284
1176
  await hydrateCodexAutomationHistory(tab);
1285
1177
  if (isCancelled() || tab.closed) {
@@ -1287,6 +1179,10 @@ export async function attachCodexAutomation(run, {
1287
1179
  return { ok: false, reason: 'dismissed' };
1288
1180
  }
1289
1181
  }
1182
+ if (restart.key && tab._restartStamp !== restart.stamp) {
1183
+ withTab(tab, () => appendSystem(t(restart.key)));
1184
+ tab._restartStamp = restart.stamp;
1185
+ }
1290
1186
  // (A dispatched worker's failure, with its reason, is on its end card.)
1291
1187
  if (run.status === 'failed' && run.error && !isDispatchedRun(run) && tab._automationLifecycleError !== run.error) {
1292
1188
  tab._automationLifecycleError = run.error;
@@ -1300,7 +1196,7 @@ export async function attachCodexAutomation(run, {
1300
1196
  const idx = allTabs().indexOf(tab);
1301
1197
  if (idx >= 0) switchTab(idx);
1302
1198
  }
1303
- if (!running && isActiveTab(tab) && _visible) connectTab(tab);
1199
+ if (!restart.active && isActiveTab(tab) && _visible) connectTab(tab);
1304
1200
  return { ok: true, tabId: tab.id };
1305
1201
  }
1306
1202
 
@@ -252,7 +252,34 @@ export function codexMcpElicitationMeta(params = {}) {
252
252
  }
253
253
 
254
254
  export function isCodexMcpToolApproval(params = {}) {
255
- return codexMcpElicitationMeta(params).codex_approval_kind === 'mcp_tool_call';
255
+ return params?.mode !== 'openai/userVerification'
256
+ && params?.mode !== 'url'
257
+ && codexMcpElicitationMeta(params).codex_approval_kind === 'mcp_tool_call';
258
+ }
259
+
260
+ /** Native Codex approvals need not include tool_name (codex-rs/core/src/mcp_tool_call.rs). */
261
+ export function codexMcpToolApproval(params = {}) {
262
+ if (!isCodexMcpToolApproval(params)) return null;
263
+ const meta = codexMcpElicitationMeta(params);
264
+ const serverName = typeof params.serverName === 'string' ? params.serverName : '';
265
+ let toolName = [meta.tool_name, meta.toolName].find(value => typeof value === 'string' && value.trim())?.trim() || '';
266
+ if (!toolName && serverName && typeof params.message === 'string') {
267
+ // Only Codex's exact fallback template is an identity source. Human tool
268
+ // titles and custom prompt prose are not names suitable for a policy check.
269
+ const prefix = `Allow the ${serverName} MCP server to run tool "`;
270
+ if (params.message.startsWith(prefix) && params.message.endsWith('"?')) {
271
+ const name = params.message.slice(prefix.length, -2);
272
+ if (name && !/["\r\n]/.test(name)) toolName = name;
273
+ }
274
+ }
275
+ const qualified = /^mcp__(.+?)__(.+)$/.exec(toolName);
276
+ if (qualified) toolName = qualified[1] === serverName ? qualified[2] : '';
277
+ return {
278
+ serverName,
279
+ toolName,
280
+ fullName: serverName && toolName ? `mcp__${serverName}__${toolName}` : '',
281
+ input: meta.tool_params ?? meta.arguments ?? {},
282
+ };
256
283
  }
257
284
 
258
285
  export function normalizeCodexMcpApprovalPersistence(params = {}) {
@@ -1,3 +1,4 @@
1
+ import { cxpText } from './cdx-copy.js';
1
2
  // ═══════════════════════════════════════════
2
3
  // SynaBun — Codex Panel: Render Module
3
4
  // Text utilities, card rendering, delta appending, and history rendering.
@@ -174,7 +175,7 @@ function extractCompactAssistantSummary(text) {
174
175
  .replace(/^[#>\-\*\d\.\s]+/gm, '')
175
176
  .replace(/\s+/g, ' ')
176
177
  .trim();
177
- if (!value) return 'Working through the next step';
178
+ if (!value) return cxpText('working', 'Working through the next step');
178
179
  return value;
179
180
  }
180
181
 
@@ -620,7 +621,7 @@ function resolveFileChangeSummary(item) {
620
621
  const changes = Array.isArray(item?.changes) ? item.changes.slice(0, OUTPUT_LIMITS.files) : [];
621
622
  const lines = changes.map((change) => describeFileChange(change)).filter(Boolean);
622
623
  if (lines.length) return lines.join('\n');
623
- return 'Pending file changes';
624
+ return cxpText('pendingFiles', 'Pending file changes');
624
625
  }
625
626
 
626
627
  function collectStructuredText(value, seen = new Set()) {
@@ -808,14 +809,27 @@ export function sanitizeStoredTranscriptDom(container) {
808
809
  });
809
810
  if (!_ctx.running) container.querySelectorAll('.cxp-reasoning').forEach(card => {
810
811
  const body = card.querySelector('.cxp-reasoning-body');
811
- if (body && /^Waiting for reasoning summary/.test(body.textContent)) body.textContent = 'No reasoning summary was provided.';
812
+ const text = body?.textContent.trim() || '';
813
+ if (!text || ['Waiting for reasoning summary...', 'No reasoning summary was provided.', cxpText('waitingReasoning', 'Waiting for reasoning summary...'), cxpText('noReasoning', 'No reasoning summary was provided.')].includes(text)) { card.remove(); return; }
814
+ const title = card.querySelector('.cxp-card-title');
815
+ if (title) title.textContent = cxpText('reasoning', 'Reasoning Summary');
812
816
  const pill = card.querySelector('.cxp-status-pill');
813
- if (pill?.textContent === 'live') pill.textContent = 'complete';
817
+ if (pill) pill.textContent = cxpText('status_complete', 'complete');
814
818
  });
815
819
  syncStatusPillTones(container);
816
820
  cleanOutputBlocks(container);
817
821
  // Old snapshots retain their classes; replace just their verbose diff body.
818
822
  container.querySelectorAll('[data-item-type="fileChange"]').forEach(card => {
823
+ const title = card.querySelector('.cxp-card-title');
824
+ if (title) title.textContent = cxpText('fileChange', 'File change');
825
+ const pill = card.querySelector('.cxp-status-pill');
826
+ const completed = ['completed', cxpText('status_completed', 'completed')].includes(pill?.textContent);
827
+ const subtitle = card.querySelector('.cxp-card-subtitle');
828
+ if (subtitle) subtitle.textContent = fileChangeSubtitle({ status: completed ? 'completed' : '' });
829
+ if (completed && pill) pill.textContent = cxpText('status_completed', 'completed');
830
+ const meta = card.querySelector('.cxp-card-meta');
831
+ const count = meta?.textContent.match(/^(\d+) file changes?$/)?.[1];
832
+ if (count) meta.textContent = cxpText(Number(count) === 1 ? 'oneFileChange' : 'fileChanges', Number(count) === 1 ? '1 file change' : '{count} file changes', { count });
819
833
  const fold = card.querySelector('.cxp-fold-diff');
820
834
  const raw = fold?.querySelector('.cxp-card-pre-diff')?.textContent;
821
835
  if (!raw) return;
@@ -2033,14 +2047,17 @@ function getReasoningPreviewText(state) {
2033
2047
  const contentText = Array.isArray(state?.contentLines)
2034
2048
  ? state.contentLines.map((line) => String(line || '').trim()).filter(Boolean).join(' ')
2035
2049
  : '';
2036
- return _ctx.cleanPreview(summaryText || contentText || 'Working through the next step');
2050
+ return _ctx.cleanPreview(summaryText || contentText || cxpText('working', 'Working through the next step'));
2037
2051
  }
2038
2052
 
2039
2053
  function updateReasoningChrome(state, { complete = false } = {}) {
2040
2054
  if (!state) return;
2041
- if (state.summaryEl) state.summaryEl.textContent = complete && !state.summaryLines?.some(line => String(line).trim()) && !state.contentLines?.some(line => String(line).trim()) ? 'No reasoning summary was provided.' : getReasoningPreviewText(state);
2042
- if (state.pillEl) state.pillEl.textContent = complete ? 'complete' : 'live';
2043
- if (state.el) state.el.classList.toggle('cxp-reasoning-done', !!complete);
2055
+ if (state.summaryEl) state.summaryEl.textContent = complete && !state.summaryLines?.some(line => String(line).trim()) && !state.contentLines?.some(line => String(line).trim()) ? cxpText('noReasoning', 'No reasoning summary was provided.') : getReasoningPreviewText(state);
2056
+ if (state.pillEl) state.pillEl.textContent = complete ? cxpText('status_complete', 'complete') : cxpText('live', 'live');
2057
+ if (state.el) {
2058
+ state.el.hidden = !state.summaryLines?.some(line => String(line).trim()) && !state.contentLines?.some(line => String(line).trim());
2059
+ state.el.classList.toggle('cxp-reasoning-done', !!complete);
2060
+ }
2044
2061
  }
2045
2062
 
2046
2063
  function cacheCollapsedCardState(state, item, itemType) {
@@ -2100,15 +2117,9 @@ function cacheCollapsedCardState(state, item, itemType) {
2100
2117
  case 'fileChange': {
2101
2118
  const changes = Array.isArray(item.changes) ? item.changes : [];
2102
2119
  if (hasOwnField(item, 'changes')) {
2103
- state.fileMetaText = changes.length ? `${changes.length} file change${changes.length > 1 ? 's' : ''}` : 'Pending file changes';
2120
+ state.fileMetaText = changes.length ? cxpText(changes.length === 1 ? 'oneFileChange' : 'fileChanges', changes.length === 1 ? '1 file change' : '{count} file changes', { count: changes.length }) : cxpText('pendingFiles', 'Pending file changes');
2104
2121
  state.filesText = resolveFileChangeSummary(item);
2105
- const diffText = changes
2106
- .map((change) => extractStructuredText(change?.diff || change?.patch || change?.content || change?.output || ''))
2107
- .filter(Boolean)
2108
- .join('\n\n');
2109
- if (item.aggregatedOutput != null || diffText) {
2110
- state.outputBuf = extractStructuredText(item.aggregatedOutput) || item.aggregatedOutput || diffText;
2111
- }
2122
+ if (item.aggregatedOutput != null) state.outputBuf = extractStructuredText(item.aggregatedOutput) || item.aggregatedOutput || '';
2112
2123
  } else if (item.aggregatedOutput != null) {
2113
2124
  state.outputBuf = extractStructuredText(item.aggregatedOutput) || item.aggregatedOutput || '';
2114
2125
  }
@@ -2162,8 +2173,8 @@ export function flushCardBody(state) {
2162
2173
  setOptionalSection(state.resultSectionEl, state.resultEl, state.resultText || '');
2163
2174
  break;
2164
2175
  case 'fileChange':
2165
- if (state.metaEl) state.metaEl.textContent = state.fileMetaText || 'Pending file changes';
2166
- if (state.filesEl) state.filesEl.textContent = state.filesText || 'Pending file changes';
2176
+ if (state.metaEl) state.metaEl.textContent = state.fileMetaText || cxpText('pendingFiles', 'Pending file changes');
2177
+ if (state.filesEl) state.filesEl.textContent = state.filesText || cxpText('pendingFiles', 'Pending file changes');
2167
2178
  refreshFileChangeView(state);
2168
2179
  break;
2169
2180
  case 'collabAgentToolCall':
@@ -2388,6 +2399,7 @@ export function ensureReasoningState(item) {
2388
2399
 
2389
2400
  const details = document.createElement('details');
2390
2401
  details.className = 'cxp-card cxp-reasoning';
2402
+ details.hidden = true;
2391
2403
  details.dataset.itemId = item.id || '';
2392
2404
  details.dataset.expanded = '1';
2393
2405
 
@@ -2395,8 +2407,8 @@ export function ensureReasoningState(item) {
2395
2407
  summary.innerHTML = `
2396
2408
  <span class="cxp-card-icon">${ICON_SPARK}</span>
2397
2409
  <span class="cxp-card-titles">
2398
- <span class="cxp-card-title">Reasoning Summary</span>
2399
- <span class="cxp-card-subtitle">Working through the next step</span>
2410
+ <span class="cxp-card-title">${cxpText('reasoning', 'Reasoning Summary')}</span>
2411
+ <span class="cxp-card-subtitle">${cxpText('working', 'Working through the next step')}</span>
2400
2412
  </span>
2401
2413
  <span class="cxp-think-dots"><span></span><span></span><span></span></span>
2402
2414
  <span class="cxp-status-pill">live</span>
@@ -2643,10 +2655,14 @@ export function completeTurnOutputs(turnId) {
2643
2655
  }
2644
2656
  }
2645
2657
 
2658
+ function fileChangeSubtitle(item) {
2659
+ return item.status === 'completed' ? cxpText('filesUpdated', 'File updates applied') : cxpText('fileUpdates', 'File updates');
2660
+ }
2661
+
2646
2662
  export function ensureFileChangeState(item) {
2647
2663
  let state = _ctx.items.get(item.id);
2648
2664
  if (state) return state;
2649
- const card = createCard(item, ICON_FILES, 'File change', 'Proposed file updates');
2665
+ const card = createCard(item, ICON_FILES, cxpText('fileChange', 'File change'), fileChangeSubtitle(item));
2650
2666
  setCardExpanded(card.el, true);
2651
2667
 
2652
2668
  const summary = document.createElement('div');
@@ -2657,7 +2673,7 @@ export function ensureFileChangeState(item) {
2657
2673
  filesSection.className = 'cxp-card-section';
2658
2674
  const filesLabel = document.createElement('div');
2659
2675
  filesLabel.className = 'cxp-card-section-label';
2660
- filesLabel.textContent = 'Files changed';
2676
+ filesLabel.textContent = cxpText('filesChanged', 'Files changed');
2661
2677
  const filesBody = document.createElement('div');
2662
2678
  filesBody.className = 'cxp-card-meta';
2663
2679
  filesSection.append(filesLabel, filesBody);
@@ -2672,6 +2688,7 @@ export function ensureFileChangeState(item) {
2672
2688
  type: 'fileChange',
2673
2689
  el: card.el,
2674
2690
  pillEl: card.pill,
2691
+ subtitleEl: card.subtitleEl,
2675
2692
  metaEl: summary,
2676
2693
  filesEl: filesBody,
2677
2694
  outputSectionEl: outputEl,
@@ -2889,8 +2906,9 @@ export function updateItemFromData(item) {
2889
2906
  state.titleEl.textContent = head?.title || h.detail || item.type || 'Item';
2890
2907
  if (head && state.subtitleEl) state.subtitleEl.textContent = head.subtitle;
2891
2908
  }
2909
+ if (itemType === 'fileChange' && state.subtitleEl) state.subtitleEl.textContent = fileChangeSubtitle(state._lastItem);
2892
2910
  if (state.pillEl && item.status != null) state.pillEl.textContent = _ctx.formatStatus(item.status);
2893
- if (isCardBodyHidden(state)) { state._bodyDirty = true; _ctx.scheduleThreadSnapshotSave(_ctx.boundTab); return; }
2911
+ if (itemType !== 'reasoning' && isCardBodyHidden(state)) { state._bodyDirty = true; _ctx.scheduleThreadSnapshotSave(_ctx.boundTab); return; }
2894
2912
  }
2895
2913
 
2896
2914
  switch (itemType) {
@@ -2978,8 +2996,8 @@ export function updateItemFromData(item) {
2978
2996
  }
2979
2997
  case 'fileChange': {
2980
2998
  state.pillEl.textContent = _ctx.formatStatus(item.status);
2981
- state.metaEl.textContent = state.fileMetaText || 'Pending file changes';
2982
- if (state.filesEl) state.filesEl.textContent = state.filesText || 'Pending file changes';
2999
+ state.metaEl.textContent = state.fileMetaText || cxpText('pendingFiles', 'Pending file changes');
3000
+ if (state.filesEl) state.filesEl.textContent = state.filesText || cxpText('pendingFiles', 'Pending file changes');
2983
3001
  if (item.aggregatedOutput != null) {
2984
3002
  state.outputBuf = extractStructuredText(item.aggregatedOutput) || item.aggregatedOutput || '';
2985
3003
  }
@@ -3104,26 +3122,26 @@ export function appendAgentDelta(itemId, delta) {
3104
3122
 
3105
3123
  export function appendPlanDelta(itemId, delta) {
3106
3124
  const state = ensurePlanState({ id: itemId });
3107
- if (state.pillEl) state.pillEl.textContent = 'live';
3125
+ if (state.pillEl) state.pillEl.textContent = cxpText('live', 'live');
3108
3126
  state.buffer += delta || '';
3109
3127
  if (isCardBodyHidden(state)) { state._bodyDirty = true; return; }
3110
3128
  setMarkdownBuffer(state, state.buffer, false);
3111
3129
  }
3112
3130
 
3113
3131
  export function getReasoningBodyText(state, { complete = false } = {}) {
3114
- if (!state) return complete ? 'No reasoning summary was provided.' : 'Waiting for reasoning summary...';
3132
+ if (!state) return complete ? cxpText('noReasoning', 'No reasoning summary was provided.') : cxpText('waitingReasoning', 'Waiting for reasoning summary...');
3115
3133
  const contentText = Array.isArray(state.contentLines) ? state.contentLines.join('').trim() : '';
3116
3134
  if (contentText) return contentText;
3117
3135
  const summaryText = Array.isArray(state.summaryLines)
3118
3136
  ? state.summaryLines.map((line) => String(line || '').trim()).filter(Boolean).join('\n')
3119
3137
  : '';
3120
- return summaryText || (complete ? 'No reasoning summary was provided.' : 'Waiting for reasoning summary...');
3138
+ return summaryText || (complete ? cxpText('noReasoning', 'No reasoning summary was provided.') : cxpText('waitingReasoning', 'Waiting for reasoning summary...'));
3121
3139
  }
3122
3140
 
3123
3141
  export function appendReasoningDelta(itemId, delta, isSummary = false, summaryIndex = null) {
3124
3142
  const state = ensureReasoningState({ id: itemId });
3125
3143
  state.el?.classList.remove('cxp-reasoning-done');
3126
- if (state.pillEl) state.pillEl.textContent = 'live';
3144
+ if (state.pillEl) state.pillEl.textContent = cxpText('live', 'live');
3127
3145
  if (!state.userToggled && state.el && !state.el.open) {
3128
3146
  state.suppressToggleTracking = true;
3129
3147
  state.el.open = true;