synabun 2.0.10 → 2.2.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 (656) hide show
  1. package/CHANGELOG.md +207 -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 +13 -13
  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 +30 -17
  11. package/lib/desktop-app.js +7 -1
  12. package/lib/external-tools.js +7 -6
  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 +302 -0
  24. package/lib/virustotal.mjs +203 -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/budget-judgments.d.ts +1 -1
  37. package/mcp-server/dist/services/budget-judgments.d.ts.map +1 -1
  38. package/mcp-server/dist/services/budget-judgments.js +5 -3
  39. package/mcp-server/dist/services/budget-judgments.js.map +1 -1
  40. package/mcp-server/dist/services/codex-config-heal.d.ts +6 -2
  41. package/mcp-server/dist/services/codex-config-heal.d.ts.map +1 -1
  42. package/mcp-server/dist/services/codex-config-heal.js +81 -28
  43. package/mcp-server/dist/services/codex-config-heal.js.map +1 -1
  44. package/mcp-server/dist/services/identity.d.ts +2 -2
  45. package/mcp-server/dist/services/identity.js +2 -2
  46. package/mcp-server/dist/services/memory-judge-backfill.d.ts +6 -0
  47. package/mcp-server/dist/services/memory-judge-backfill.d.ts.map +1 -1
  48. package/mcp-server/dist/services/memory-judge-backfill.js +7 -1
  49. package/mcp-server/dist/services/memory-judge-backfill.js.map +1 -1
  50. package/mcp-server/dist/services/memory-sessions.d.ts +1 -1
  51. package/mcp-server/dist/services/memory-sessions.d.ts.map +1 -1
  52. package/mcp-server/dist/services/memory-sessions.js +28 -2
  53. package/mcp-server/dist/services/memory-sessions.js.map +1 -1
  54. package/mcp-server/dist/services/neural-interface.d.ts +18 -11
  55. package/mcp-server/dist/services/neural-interface.d.ts.map +1 -1
  56. package/mcp-server/dist/services/neural-interface.js +67 -11
  57. package/mcp-server/dist/services/neural-interface.js.map +1 -1
  58. package/mcp-server/dist/services/server-instructions.d.ts +7 -2
  59. package/mcp-server/dist/services/server-instructions.d.ts.map +1 -1
  60. package/mcp-server/dist/services/server-instructions.js +22 -63
  61. package/mcp-server/dist/services/server-instructions.js.map +1 -1
  62. package/mcp-server/dist/services/tool-catalog.d.ts +120 -0
  63. package/mcp-server/dist/services/tool-catalog.d.ts.map +1 -0
  64. package/mcp-server/dist/services/tool-catalog.js +339 -0
  65. package/mcp-server/dist/services/tool-catalog.js.map +1 -0
  66. package/mcp-server/dist/services/tool-list-refresh-barrier.d.ts +12 -0
  67. package/mcp-server/dist/services/tool-list-refresh-barrier.d.ts.map +1 -0
  68. package/mcp-server/dist/services/tool-list-refresh-barrier.js +40 -0
  69. package/mcp-server/dist/services/tool-list-refresh-barrier.js.map +1 -0
  70. package/mcp-server/dist/services/tool-list.d.ts +108 -0
  71. package/mcp-server/dist/services/tool-list.d.ts.map +1 -0
  72. package/mcp-server/dist/services/tool-list.js +334 -0
  73. package/mcp-server/dist/services/tool-list.js.map +1 -0
  74. package/mcp-server/dist/services/tool-runtime.d.ts +161 -0
  75. package/mcp-server/dist/services/tool-runtime.d.ts.map +1 -0
  76. package/mcp-server/dist/services/tool-runtime.js +400 -0
  77. package/mcp-server/dist/services/tool-runtime.js.map +1 -0
  78. package/mcp-server/dist/services/typesafe-config.js +1 -1
  79. package/mcp-server/dist/services/typesafe-config.js.map +1 -1
  80. package/mcp-server/dist/services/whiteboard-geometry.d.ts +26 -2
  81. package/mcp-server/dist/services/whiteboard-geometry.d.ts.map +1 -1
  82. package/mcp-server/dist/services/whiteboard-geometry.js +91 -8
  83. package/mcp-server/dist/services/whiteboard-geometry.js.map +1 -1
  84. package/mcp-server/dist/tools/agents.d.ts +14 -14
  85. package/mcp-server/dist/tools/agents.d.ts.map +1 -1
  86. package/mcp-server/dist/tools/agents.js +29 -19
  87. package/mcp-server/dist/tools/agents.js.map +1 -1
  88. package/mcp-server/dist/tools/browser-batch.d.ts +3 -3
  89. package/mcp-server/dist/tools/choice.d.ts +6 -0
  90. package/mcp-server/dist/tools/choice.d.ts.map +1 -1
  91. package/mcp-server/dist/tools/choice.js +18 -13
  92. package/mcp-server/dist/tools/choice.js.map +1 -1
  93. package/mcp-server/dist/tools/git-tools.js +2 -2
  94. package/mcp-server/dist/tools/git-tools.js.map +1 -1
  95. package/mcp-server/dist/tools/image-tools.d.ts +1 -1
  96. package/mcp-server/dist/tools/image-tools.js +1 -1
  97. package/mcp-server/dist/tools/morelogin.d.ts.map +1 -1
  98. package/mcp-server/dist/tools/morelogin.js +9 -6
  99. package/mcp-server/dist/tools/morelogin.js.map +1 -1
  100. package/mcp-server/dist/tools/skill-tools.d.ts +505 -0
  101. package/mcp-server/dist/tools/skill-tools.d.ts.map +1 -0
  102. package/mcp-server/dist/tools/skill-tools.js +642 -0
  103. package/mcp-server/dist/tools/skill-tools.js.map +1 -0
  104. package/mcp-server/dist/tools/skill.d.ts +7 -0
  105. package/mcp-server/dist/tools/skill.d.ts.map +1 -0
  106. package/mcp-server/dist/tools/skill.js +11 -0
  107. package/mcp-server/dist/tools/skill.js.map +1 -0
  108. package/mcp-server/dist/tools/tool-groups.d.ts +68 -0
  109. package/mcp-server/dist/tools/tool-groups.d.ts.map +1 -0
  110. package/mcp-server/dist/tools/tool-groups.js +147 -0
  111. package/mcp-server/dist/tools/tool-groups.js.map +1 -0
  112. package/mcp-server/dist/tools/whiteboard-format.d.ts.map +1 -1
  113. package/mcp-server/dist/tools/whiteboard-format.js +7 -4
  114. package/mcp-server/dist/tools/whiteboard-format.js.map +1 -1
  115. package/mcp-server/dist/tools/whiteboard-tools.d.ts +64 -13
  116. package/mcp-server/dist/tools/whiteboard-tools.d.ts.map +1 -1
  117. package/mcp-server/dist/tools/whiteboard-tools.js +30 -5
  118. package/mcp-server/dist/tools/whiteboard-tools.js.map +1 -1
  119. package/mcp-server/package-lock.json +2 -2
  120. package/mcp-server/package.json +1 -1
  121. package/mcp-server/src/http.ts +75 -12
  122. package/mcp-server/src/index.ts +147 -154
  123. package/mcp-server/src/preload.ts +12 -12
  124. package/mcp-server/src/services/budget-judgments.ts +5 -3
  125. package/mcp-server/src/services/codex-config-heal.ts +80 -29
  126. package/mcp-server/src/services/identity.ts +2 -2
  127. package/mcp-server/src/services/memory-judge-backfill.ts +7 -1
  128. package/mcp-server/src/services/memory-sessions.ts +24 -3
  129. package/mcp-server/src/services/neural-interface.ts +81 -21
  130. package/mcp-server/src/services/server-instructions.ts +29 -64
  131. package/mcp-server/src/services/tool-catalog.ts +403 -0
  132. package/mcp-server/src/services/tool-list-refresh-barrier.ts +33 -0
  133. package/mcp-server/src/services/tool-list.ts +410 -0
  134. package/mcp-server/src/services/tool-runtime.ts +457 -0
  135. package/mcp-server/src/services/typesafe-config.ts +1 -1
  136. package/mcp-server/src/services/whiteboard-geometry.ts +94 -9
  137. package/mcp-server/src/tools/agents.ts +29 -20
  138. package/mcp-server/src/tools/choice.ts +17 -12
  139. package/mcp-server/src/tools/git-tools.ts +2 -2
  140. package/mcp-server/src/tools/image-tools.ts +1 -1
  141. package/mcp-server/src/tools/morelogin.ts +6 -4
  142. package/mcp-server/src/tools/skill-tools.ts +592 -0
  143. package/mcp-server/src/tools/skill.ts +13 -0
  144. package/mcp-server/src/tools/tool-groups.ts +164 -0
  145. package/mcp-server/src/tools/whiteboard-format.ts +9 -3
  146. package/mcp-server/src/tools/whiteboard-tools.ts +39 -5
  147. package/neural-interface/i18n/en.json +3953 -228
  148. package/neural-interface/i18n/pt-BR.json +3901 -179
  149. package/neural-interface/lib/agent-sandbox-elevation.js +6 -0
  150. package/neural-interface/lib/antigravity/acp-client-host.js +554 -0
  151. package/neural-interface/lib/antigravity/acp-connection.js +299 -0
  152. package/neural-interface/lib/antigravity/bypass.js +100 -0
  153. package/neural-interface/lib/antigravity/catalog.js +273 -0
  154. package/neural-interface/lib/antigravity/home.js +260 -0
  155. package/neural-interface/lib/antigravity/migrate-gemini.js +139 -0
  156. package/neural-interface/lib/antigravity/panel-bridge.js +1058 -0
  157. package/neural-interface/lib/antigravity/policy-hook.mjs +78 -0
  158. package/neural-interface/lib/antigravity/policy.js +74 -0
  159. package/neural-interface/lib/antigravity/tool-call.js +178 -0
  160. package/neural-interface/lib/antigravity/transcripts.js +252 -0
  161. package/neural-interface/lib/antigravity/usage.js +43 -0
  162. package/neural-interface/lib/assistant-api.js +128 -28
  163. package/neural-interface/lib/assistant-brains/antigravity.js +423 -0
  164. package/neural-interface/lib/assistant-brains/claude.js +4 -3
  165. package/neural-interface/lib/assistant-brains/codex-browser-policy-hook.mjs +12 -2
  166. package/neural-interface/lib/assistant-brains/codex-route-gate-hook.mjs +32 -9
  167. package/neural-interface/lib/assistant-brains/codex.js +9 -5
  168. package/neural-interface/lib/assistant-brains/opencode.js +120 -54
  169. package/neural-interface/lib/assistant-brains/opencode2-browser-policy/index.js +28 -13
  170. package/neural-interface/lib/assistant-brains/opencode2-route-gate/index.js +59 -19
  171. package/neural-interface/lib/assistant-budget-planner.js +7 -3
  172. package/neural-interface/lib/assistant-budget-split.js +42 -15
  173. package/neural-interface/lib/assistant-catalog.js +81 -15
  174. package/neural-interface/lib/assistant-config.js +6 -3
  175. package/neural-interface/lib/assistant-dispatch.js +1073 -200
  176. package/neural-interface/lib/assistant-envelope.js +156 -2
  177. package/neural-interface/lib/assistant-evidence.js +80 -0
  178. package/neural-interface/lib/assistant-hidden-models.js +7 -5
  179. package/neural-interface/lib/assistant-persona.js +93 -19
  180. package/neural-interface/lib/assistant-plan-permissions.js +25 -9
  181. package/neural-interface/lib/assistant-route-gate-codex.js +3 -0
  182. package/neural-interface/lib/assistant-route-gate.js +6 -4
  183. package/neural-interface/lib/assistant-router.js +245 -38
  184. package/neural-interface/lib/assistant-runtime.js +214 -30
  185. package/neural-interface/lib/assistant-task-prompt.js +87 -21
  186. package/neural-interface/lib/assistant-tools.js +51 -0
  187. package/neural-interface/lib/assistant-usage.js +29 -0
  188. package/neural-interface/lib/backup-service.js +626 -4
  189. package/neural-interface/lib/backup-zip-reader.js +10 -5
  190. package/neural-interface/lib/backup-zip-writer.js +257 -0
  191. package/neural-interface/lib/browser-execution.js +10 -2
  192. package/neural-interface/lib/browser-guard-cdp.js +84 -0
  193. package/neural-interface/lib/browser-network-guard.js +476 -0
  194. package/neural-interface/lib/browser-policy-roots.js +64 -0
  195. package/neural-interface/lib/browser-tool-policy.js +198 -38
  196. package/neural-interface/lib/claude-agent-bridge.js +11 -2
  197. package/neural-interface/lib/claude-history-cache.js +210 -0
  198. package/neural-interface/lib/claude-hooks-status.js +103 -0
  199. package/neural-interface/lib/claude-model-catalog.js +5 -1
  200. package/neural-interface/lib/claude-temporary.js +5 -11
  201. package/neural-interface/lib/cli-install-api.js +1 -1
  202. package/neural-interface/lib/cli-install.js +163 -154
  203. package/neural-interface/lib/cli-resolver.js +13 -3
  204. package/neural-interface/lib/cli-update-planner.js +52 -41
  205. package/neural-interface/lib/cloudflared/tunnel.js +42 -2
  206. package/neural-interface/lib/codex-mcp-approvals.js +11 -0
  207. package/neural-interface/lib/codex-rollout-reader.js +52 -0
  208. package/neural-interface/lib/codex-worker-app-server.js +191 -0
  209. package/neural-interface/lib/confined-fs.js +30 -3
  210. package/neural-interface/lib/crash-notice-api.js +98 -0
  211. package/neural-interface/lib/editor-completion-opencode.js +68 -68
  212. package/neural-interface/lib/editor-git-api.js +3 -20
  213. package/neural-interface/lib/exec-loop-command.js +13 -10
  214. package/neural-interface/lib/file-explorer-api.js +74 -40
  215. package/neural-interface/lib/file-explorer-watch.js +9 -3
  216. package/neural-interface/lib/git-bash/install.js +52 -6
  217. package/neural-interface/lib/git-bash/manager.js +59 -17
  218. package/neural-interface/lib/git-bash/pins.js +12 -0
  219. package/neural-interface/lib/git-read.js +2 -2
  220. package/neural-interface/lib/git-status-runner.js +390 -0
  221. package/neural-interface/lib/git-status-watchdog.js +40 -0
  222. package/neural-interface/lib/greeting/budgets.js +1 -0
  223. package/neural-interface/lib/greeting/engine.js +2 -2
  224. package/neural-interface/lib/greeting/sources.js +10 -12
  225. package/neural-interface/lib/greeting/writer.js +1 -1
  226. package/neural-interface/lib/http-guards.js +8 -2
  227. package/neural-interface/lib/install-details.js +4 -1
  228. package/neural-interface/lib/mcp-agent-servers.js +67 -0
  229. package/neural-interface/lib/mcp-client-config.js +35 -33
  230. package/neural-interface/lib/mcp-external-servers.js +332 -0
  231. package/neural-interface/lib/mcp-installer.js +2 -1
  232. package/neural-interface/lib/{mcp-profile-refresh-coordinator.js → mcp-tools-refresh-coordinator.js} +4 -4
  233. package/neural-interface/lib/memory-session-capture.js +17 -3
  234. package/neural-interface/lib/morelogin.js +177 -25
  235. package/neural-interface/lib/native-loop-providers.js +965 -66
  236. package/neural-interface/lib/native-loop-runtime.js +290 -42
  237. package/neural-interface/lib/opencode-config.js +557 -0
  238. package/neural-interface/lib/opencode-db-schema.js +17 -34
  239. package/neural-interface/lib/opencode-history.js +48 -218
  240. package/neural-interface/lib/opencode-mcp-ready.js +108 -0
  241. package/neural-interface/lib/opencode-native-boundary.js +53 -0
  242. package/neural-interface/lib/opencode-protocol.js +249 -112
  243. package/neural-interface/lib/opencode-runtime-config.js +32 -22
  244. package/neural-interface/lib/opencode-serve-records.js +39 -21
  245. package/neural-interface/lib/opencode-v2-client.js +48 -153
  246. package/neural-interface/lib/opencode-v2-ws-requests.js +36 -210
  247. package/neural-interface/lib/opencode-worker-data.js +27 -0
  248. package/neural-interface/lib/opencode2-client.js +73 -37
  249. package/neural-interface/lib/opencode2-proxy.js +23 -63
  250. package/neural-interface/lib/opencode2-translate.js +51 -2
  251. package/neural-interface/lib/owner-authority.js +249 -0
  252. package/neural-interface/lib/page-session.js +275 -0
  253. package/neural-interface/lib/path-confine.js +12 -9
  254. package/neural-interface/lib/peer-identity.js +793 -0
  255. package/neural-interface/lib/pty-host/core.js +28 -1
  256. package/neural-interface/lib/pty-host/lifetime.js +12 -0
  257. package/neural-interface/lib/pty-host/manager.js +12 -1
  258. package/neural-interface/lib/remote-policy.js +1 -1
  259. package/neural-interface/lib/request-gate.js +20 -2
  260. package/neural-interface/lib/rulesets/api.js +7 -6
  261. package/neural-interface/lib/rulesets/fs-safe.js +1 -1
  262. package/neural-interface/lib/rulesets/installer.js +180 -36
  263. package/neural-interface/lib/rulesets/json-edit.js +1 -1
  264. package/neural-interface/lib/rulesets/render.js +1 -1
  265. package/neural-interface/lib/session-cache-builder.js +81 -31
  266. package/neural-interface/lib/session-title-generator.js +58 -36
  267. package/neural-interface/lib/skills/api-v2.js +495 -0
  268. package/neural-interface/lib/skills/bundle.js +418 -0
  269. package/neural-interface/lib/skills/catalog.js +298 -0
  270. package/neural-interface/lib/skills/creation-api.js +191 -0
  271. package/neural-interface/lib/skills/creation-brief.js +247 -0
  272. package/neural-interface/lib/skills/creation-sources.js +285 -0
  273. package/neural-interface/lib/skills/creation.js +843 -0
  274. package/neural-interface/lib/skills/deploy.js +569 -0
  275. package/neural-interface/lib/skills/digest.js +119 -0
  276. package/neural-interface/lib/skills/discover.js +111 -0
  277. package/neural-interface/lib/skills/draft-confinement.js +216 -0
  278. package/neural-interface/lib/skills/eval-confinement.js +399 -0
  279. package/neural-interface/lib/skills/eval-sandbox.js +280 -0
  280. package/neural-interface/lib/skills/eval-trace.js +135 -0
  281. package/neural-interface/lib/skills/evals-api.js +212 -0
  282. package/neural-interface/lib/skills/evals.js +1573 -0
  283. package/neural-interface/lib/skills/export.js +203 -0
  284. package/neural-interface/lib/skills/frontmatter.js +64 -0
  285. package/neural-interface/lib/skills/health.js +75 -0
  286. package/neural-interface/lib/skills/json-edit.js +165 -0
  287. package/neural-interface/lib/skills/known-bridge-digests.json +441 -0
  288. package/neural-interface/lib/skills/known-bridges.js +96 -0
  289. package/neural-interface/lib/skills/library.js +823 -0
  290. package/neural-interface/lib/skills/local-store.js +21 -0
  291. package/neural-interface/lib/skills/migration.js +433 -0
  292. package/neural-interface/lib/skills/operations.js +45 -0
  293. package/neural-interface/lib/skills/ownership.js +427 -0
  294. package/neural-interface/lib/skills/packages.js +88 -0
  295. package/neural-interface/lib/skills/reviews.js +212 -0
  296. package/neural-interface/lib/skills/revision.js +80 -0
  297. package/neural-interface/lib/skills/roots.js +269 -0
  298. package/neural-interface/lib/skills/runtime-checks.js +358 -0
  299. package/neural-interface/lib/skills/scan-assets.js +252 -0
  300. package/neural-interface/lib/skills/scan-context.js +26 -0
  301. package/neural-interface/lib/skills/scan-shell.js +324 -0
  302. package/neural-interface/lib/skills/scan.js +364 -0
  303. package/neural-interface/lib/skills/scanners.js +54 -0
  304. package/neural-interface/lib/skills/service.js +530 -0
  305. package/neural-interface/lib/skills/telemetry.js +119 -0
  306. package/neural-interface/lib/sqlite-integrity-worker.js +22 -0
  307. package/neural-interface/lib/synabun-version.js +1 -1
  308. package/neural-interface/lib/system-activity.js +1 -1
  309. package/neural-interface/lib/tool-lists.js +124 -0
  310. package/neural-interface/lib/whatsapp/brain.js +7 -3
  311. package/neural-interface/lib/whatsapp/bridge.js +6 -3
  312. package/neural-interface/lib/whatsapp/cards.js +22 -9
  313. package/neural-interface/lib/whatsapp/config.js +1 -1
  314. package/neural-interface/lib/worker-confinement.js +1268 -0
  315. package/neural-interface/lib/worker-guard-setting.js +56 -0
  316. package/neural-interface/lib/worker-mcp-channel.js +175 -0
  317. package/neural-interface/lib/worker-question.js +74 -0
  318. package/neural-interface/lib/worker-relay-ports.js +227 -0
  319. package/neural-interface/lib/worker-resume.js +238 -0
  320. package/neural-interface/lib/worker-sandbox.js +329 -0
  321. package/neural-interface/package-lock.json +34 -12
  322. package/neural-interface/package.json +3 -2
  323. package/neural-interface/public/index.html +3 -1
  324. package/neural-interface/public/index2d.html +19 -11
  325. package/neural-interface/public/onboarding.html +3 -3
  326. package/neural-interface/public/shared/account-menu.js +8 -5
  327. package/neural-interface/public/shared/agent-runtime-options.js +125 -31
  328. package/neural-interface/public/shared/agy/agy-bypass.js +47 -0
  329. package/neural-interface/public/shared/agy/agy-client.js +266 -0
  330. package/neural-interface/public/shared/agy/agy-commands.js +120 -0
  331. package/neural-interface/public/shared/agy/agy-copy.js +326 -0
  332. package/neural-interface/public/shared/agy/agy-diff.js +161 -0
  333. package/neural-interface/public/shared/agy/agy-events.js +469 -0
  334. package/neural-interface/public/shared/agy/agy-greeting.js +26 -0
  335. package/neural-interface/public/shared/agy/agy-options.js +232 -0
  336. package/neural-interface/public/shared/agy/agy-panel.js +2543 -0
  337. package/neural-interface/public/shared/agy/agy-render.js +392 -0
  338. package/neural-interface/public/shared/agy/agy-setup.js +149 -0
  339. package/neural-interface/public/shared/agy/agy-styles.js +604 -0
  340. package/neural-interface/public/shared/agy/agy-tabs-logic.js +181 -0
  341. package/neural-interface/public/shared/api.js +1527 -1336
  342. package/neural-interface/public/shared/app-frame.js +192 -0
  343. package/neural-interface/public/shared/assistant/asst-agents-dock.js +36 -6
  344. package/neural-interface/public/shared/assistant/asst-api.js +1 -1
  345. package/neural-interface/public/shared/assistant/asst-ask-styles.js +270 -0
  346. package/neural-interface/public/shared/assistant/asst-ask-tail.js +118 -0
  347. package/neural-interface/public/shared/assistant/asst-ask.js +397 -0
  348. package/neural-interface/public/shared/assistant/asst-brain-picker.js +105 -44
  349. package/neural-interface/public/shared/assistant/asst-budget.js +5 -4
  350. package/neural-interface/public/shared/assistant/asst-control.js +205 -26
  351. package/neural-interface/public/shared/assistant/asst-followups-card.js +383 -0
  352. package/neural-interface/public/shared/assistant/asst-followups.js +417 -0
  353. package/neural-interface/public/shared/assistant/asst-hosts.js +16 -7
  354. package/neural-interface/public/shared/assistant/asst-limit-dock.js +45 -0
  355. package/neural-interface/public/shared/assistant/asst-limit-wait.js +327 -0
  356. package/neural-interface/public/shared/assistant/asst-limit.js +168 -0
  357. package/neural-interface/public/shared/assistant/asst-mascot.js +49 -12
  358. package/neural-interface/public/shared/assistant/asst-menu.js +7 -6
  359. package/neural-interface/public/shared/assistant/asst-panel.js +151 -19
  360. package/neural-interface/public/shared/assistant/asst-rack-styles.js +66 -49
  361. package/neural-interface/public/shared/assistant/asst-render.js +445 -82
  362. package/neural-interface/public/shared/assistant/asst-route.js +304 -53
  363. package/neural-interface/public/shared/assistant/asst-routes-editor.js +9 -8
  364. package/neural-interface/public/shared/assistant/asst-scenes.js +56 -1
  365. package/neural-interface/public/shared/assistant/asst-sidepanel.js +117 -10
  366. package/neural-interface/public/shared/assistant/asst-slash.js +17 -9
  367. package/neural-interface/public/shared/assistant/asst-state.js +87 -24
  368. package/neural-interface/public/shared/assistant/asst-stop.js +127 -0
  369. package/neural-interface/public/shared/assistant/asst-styles.js +93 -21
  370. package/neural-interface/public/shared/assistant/asst-tool-kinds.js +190 -23
  371. package/neural-interface/public/shared/assistant/asst-usage.js +2 -1
  372. package/neural-interface/public/shared/automation-context.js +5 -2
  373. package/neural-interface/public/shared/cc-dropdown.js +89 -19
  374. package/neural-interface/public/shared/cdx/cdx-context-menu.js +10 -9
  375. package/neural-interface/public/shared/cdx/cdx-copy.js +16 -0
  376. package/neural-interface/public/shared/cdx/cdx-output-model.js +22 -1
  377. package/neural-interface/public/shared/cdx/cdx-output.js +34 -10
  378. package/neural-interface/public/shared/cdx/cdx-panel.js +59 -151
  379. package/neural-interface/public/shared/cdx/cdx-preview.js +12 -0
  380. package/neural-interface/public/shared/cdx/cdx-protocol.js +39 -11
  381. package/neural-interface/public/shared/cdx/cdx-render.js +57 -38
  382. package/neural-interface/public/shared/cdx/cdx-requests.js +14 -4
  383. package/neural-interface/public/shared/cdx/cdx-skill-hints.js +54 -0
  384. package/neural-interface/public/shared/cdx/cdx-styles.js +15 -3
  385. package/neural-interface/public/shared/cdx/cdx-tabs.js +127 -44
  386. package/neural-interface/public/shared/cdx/cdx-ws.js +0 -1
  387. package/neural-interface/public/shared/cli-install-controller.js +218 -0
  388. package/neural-interface/public/shared/cli-install-view.js +11 -12
  389. package/neural-interface/public/shared/cli-status.js +11 -10
  390. package/neural-interface/public/shared/constants.js +5 -4
  391. package/neural-interface/public/shared/context-menu-areas.js +34 -0
  392. package/neural-interface/public/shared/context-menu-logic.js +243 -0
  393. package/neural-interface/public/shared/context-menu-model.js +367 -0
  394. package/neural-interface/public/shared/context-menu.js +372 -0
  395. package/neural-interface/public/shared/cp/cp-context-menu.js +10 -9
  396. package/neural-interface/public/shared/cp/cp-restore.js +162 -0
  397. package/neural-interface/public/shared/cp/cp-tool-cards.js +10 -3
  398. package/neural-interface/public/shared/crash-notice-view.js +168 -0
  399. package/neural-interface/public/shared/desktop-bridge.js +17 -0
  400. package/neural-interface/public/shared/desktop-titlebar-view.js +12 -0
  401. package/neural-interface/public/shared/desktop-titlebar.js +13 -4
  402. package/neural-interface/public/shared/desktop-update-view.js +21 -0
  403. package/neural-interface/public/shared/editor/editor-panel-logic.js +2 -2
  404. package/neural-interface/public/shared/explorer/fx-api.js +4 -4
  405. package/neural-interface/public/shared/explorer/fx-links.js +3 -3
  406. package/neural-interface/public/shared/explorer/fx-logic.js +1 -1
  407. package/neural-interface/public/shared/explorer/fx-main.js +48 -16
  408. package/neural-interface/public/shared/explorer/fx-tree.js +1 -0
  409. package/neural-interface/public/shared/greeting/greeting-card.js +2 -2
  410. package/neural-interface/public/shared/greeting/greeting-view.js +1 -0
  411. package/neural-interface/public/shared/html-shell.js +30 -15
  412. package/neural-interface/public/shared/i18n.js +2 -0
  413. package/neural-interface/public/shared/ocp-v2/ocp-v2-approvals.js +7 -7
  414. package/neural-interface/public/shared/ocp-v2/ocp-v2-binding.js +4 -4
  415. package/neural-interface/public/shared/ocp-v2/ocp-v2-changes-logic.js +3 -101
  416. package/neural-interface/public/shared/ocp-v2/ocp-v2-childpanel.js +2 -0
  417. package/neural-interface/public/shared/ocp-v2/ocp-v2-compact-button.js +1 -3
  418. package/neural-interface/public/shared/ocp-v2/ocp-v2-composer-logic.js +2 -6
  419. package/neural-interface/public/shared/ocp-v2/ocp-v2-context-menu.js +11 -11
  420. package/neural-interface/public/shared/ocp-v2/ocp-v2-context-model.js +0 -3
  421. package/neural-interface/public/shared/ocp-v2/ocp-v2-events.js +8 -4
  422. package/neural-interface/public/shared/ocp-v2/ocp-v2-manager.js +7 -7
  423. package/neural-interface/public/shared/ocp-v2/ocp-v2-outcome-notifications.js +16 -0
  424. package/neural-interface/public/shared/ocp-v2/ocp-v2-panel.js +74 -259
  425. package/neural-interface/public/shared/ocp-v2/ocp-v2-plan.js +1 -2
  426. package/neural-interface/public/shared/ocp-v2/ocp-v2-projectbar.js +95 -202
  427. package/neural-interface/public/shared/ocp-v2/ocp-v2-rehydrate.js +13 -4
  428. package/neural-interface/public/shared/ocp-v2/ocp-v2-render.js +13 -22
  429. package/neural-interface/public/shared/ocp-v2/ocp-v2-send.js +4 -4
  430. package/neural-interface/public/shared/ocp-v2/ocp-v2-session-actions.js +8 -61
  431. package/neural-interface/public/shared/ocp-v2/ocp-v2-sessions-logic.js +2 -91
  432. package/neural-interface/public/shared/ocp-v2/ocp-v2-slash-hints.js +16 -15
  433. package/neural-interface/public/shared/ocp-v2/ocp-v2-state.js +8 -21
  434. package/neural-interface/public/shared/ocp-v2/ocp-v2-status-logic.js +1 -99
  435. package/neural-interface/public/shared/ocp-v2/ocp-v2-status.js +5 -35
  436. package/neural-interface/public/shared/ocp-v2/ocp-v2-styles.js +17 -21
  437. package/neural-interface/public/shared/ocp-v2/{ocp-v2-profile-inheritance.js → ocp-v2-tools-inheritance.js} +16 -16
  438. package/neural-interface/public/shared/ocp-v2/ocp-v2-ws.js +60 -50
  439. package/neural-interface/public/shared/page-session.js +96 -0
  440. package/neural-interface/public/shared/provider-icons.js +4 -2
  441. package/neural-interface/public/shared/registry.js +5 -3
  442. package/neural-interface/public/shared/retired-2d.js +3 -0
  443. package/neural-interface/public/shared/schedules-view.js +195 -61
  444. package/neural-interface/public/shared/settings/settings-claude-hooks.js +135 -0
  445. package/neural-interface/public/shared/settings/settings-data.js +3 -1
  446. package/neural-interface/public/shared/settings/settings-ia.js +6 -6
  447. package/neural-interface/public/shared/settings/settings-opencode.js +89 -0
  448. package/neural-interface/public/shared/settings/settings-rules.js +2 -2
  449. package/neural-interface/public/shared/settings/settings-skill-folders-pane.js +265 -0
  450. package/neural-interface/public/shared/settings/settings-skill-folders.js +130 -0
  451. package/neural-interface/public/shared/settings/settings-worker-guard.js +72 -0
  452. package/neural-interface/public/shared/showcase-privacy.js +6 -1
  453. package/neural-interface/public/shared/sidepanel-session-status.js +3 -3
  454. package/neural-interface/public/shared/skills/ss-args.js +96 -0
  455. package/neural-interface/public/shared/skills/ss-creation.js +222 -0
  456. package/neural-interface/public/shared/skills/ss-dialog.js +133 -0
  457. package/neural-interface/public/shared/skills/ss-doc.js +173 -0
  458. package/neural-interface/public/shared/skills/ss-eval-adapters.js +269 -0
  459. package/neural-interface/public/shared/skills/ss-eval-grade.js +359 -0
  460. package/neural-interface/public/shared/skills/ss-eval-optimise.js +153 -0
  461. package/neural-interface/public/shared/skills/ss-eval-plan.js +315 -0
  462. package/neural-interface/public/shared/skills/ss-evals.js +417 -0
  463. package/neural-interface/public/shared/skills/ss-form.js +159 -0
  464. package/neural-interface/public/shared/skills/ss-frontmatter.js +376 -0
  465. package/neural-interface/public/shared/skills/ss-ids.js +32 -0
  466. package/neural-interface/public/shared/skills/ss-lint.js +149 -0
  467. package/neural-interface/public/shared/skills/ss-presets.js +117 -0
  468. package/neural-interface/public/shared/skills/ss-profiles.js +513 -0
  469. package/neural-interface/public/shared/skills/ss-resources.js +165 -0
  470. package/neural-interface/public/shared/skills/ss-review-view.js +190 -0
  471. package/neural-interface/public/shared/skills/ss-tabs.js +79 -0
  472. package/neural-interface/public/shared/skills/ss-unicode.js +135 -0
  473. package/neural-interface/public/shared/skills/studio/sx-actions.js +222 -0
  474. package/neural-interface/public/shared/skills/studio/sx-cm.js +101 -0
  475. package/neural-interface/public/shared/skills/studio/sx-create-ai-view.js +749 -0
  476. package/neural-interface/public/shared/skills/studio/sx-create-ai.js +237 -0
  477. package/neural-interface/public/shared/skills/studio/sx-create-view.js +254 -0
  478. package/neural-interface/public/shared/skills/studio/sx-create.js +126 -0
  479. package/neural-interface/public/shared/skills/studio/sx-diff-view.js +43 -0
  480. package/neural-interface/public/shared/skills/studio/sx-diff.js +133 -0
  481. package/neural-interface/public/shared/skills/studio/sx-docs.js +480 -0
  482. package/neural-interface/public/shared/skills/studio/sx-dom.js +230 -0
  483. package/neural-interface/public/shared/skills/studio/sx-edit-view.js +848 -0
  484. package/neural-interface/public/shared/skills/studio/sx-editor-model.js +193 -0
  485. package/neural-interface/public/shared/skills/studio/sx-errors.js +22 -0
  486. package/neural-interface/public/shared/skills/studio/sx-fixes-view.js +359 -0
  487. package/neural-interface/public/shared/skills/studio/sx-fixes.js +327 -0
  488. package/neural-interface/public/shared/skills/studio/sx-geometry.js +82 -0
  489. package/neural-interface/public/shared/skills/studio/sx-import.js +262 -0
  490. package/neural-interface/public/shared/skills/studio/sx-inspector.js +308 -0
  491. package/neural-interface/public/shared/skills/studio/sx-install-flow.js +282 -0
  492. package/neural-interface/public/shared/skills/studio/sx-install.js +313 -0
  493. package/neural-interface/public/shared/skills/studio/sx-library-view.js +748 -0
  494. package/neural-interface/public/shared/skills/studio/sx-library.js +479 -0
  495. package/neural-interface/public/shared/skills/studio/sx-main.js +690 -0
  496. package/neural-interface/public/shared/skills/studio/sx-operations-view.js +98 -0
  497. package/neural-interface/public/shared/skills/studio/sx-operations.js +11 -0
  498. package/neural-interface/public/shared/skills/studio/sx-plan.js +158 -0
  499. package/neural-interface/public/shared/skills/studio/sx-publish-view.js +621 -0
  500. package/neural-interface/public/shared/skills/studio/sx-review-view.js +369 -0
  501. package/neural-interface/public/shared/skills/studio/sx-review.js +148 -0
  502. package/neural-interface/public/shared/skills/studio/sx-scan.js +35 -0
  503. package/neural-interface/public/shared/skills/studio/sx-snippets.js +96 -0
  504. package/neural-interface/public/shared/skills/studio/sx-subject.js +249 -0
  505. package/neural-interface/public/shared/skills/studio/sx-test-view.js +994 -0
  506. package/neural-interface/public/shared/skills/studio/sx-test.js +328 -0
  507. package/neural-interface/public/shared/skills/studio/sx-versions-view.js +241 -0
  508. package/neural-interface/public/shared/skills/studio/sx-workspace-view.js +426 -0
  509. package/neural-interface/public/shared/state.js +1 -1
  510. package/neural-interface/public/shared/streaming-markdown.js +58 -0
  511. package/neural-interface/public/shared/styleguide/sg-panel.js +4 -2
  512. package/neural-interface/public/shared/styles.css +1822 -1756
  513. package/neural-interface/public/shared/synabun-mascot.js +1115 -9
  514. package/neural-interface/public/shared/text-cache.js +29 -0
  515. package/neural-interface/public/shared/tool-list-picker.js +55 -0
  516. package/neural-interface/public/shared/tool-list-storage.js +24 -0
  517. package/neural-interface/public/shared/tool-list-view.js +112 -0
  518. package/neural-interface/public/shared/topright-overflow-logic.js +54 -0
  519. package/neural-interface/public/shared/tour/tour-actor.js +268 -0
  520. package/neural-interface/public/shared/tour/tour-beats.js +336 -0
  521. package/neural-interface/public/shared/tour/tour-engine.js +884 -0
  522. package/neural-interface/public/shared/tour/tour-ink.js +390 -0
  523. package/neural-interface/public/shared/tour/tour-stage.js +440 -0
  524. package/neural-interface/public/shared/tour/tour-state.js +40 -0
  525. package/neural-interface/public/shared/tour/tour-tips.js +99 -0
  526. package/neural-interface/public/shared/tour/tour.css +144 -0
  527. package/neural-interface/public/shared/ui-antigravity-panel.js +19 -0
  528. package/neural-interface/public/shared/ui-assistant.js +2 -0
  529. package/neural-interface/public/shared/ui-automation-studio.js +111 -140
  530. package/neural-interface/public/shared/ui-claude-panel.js +376 -82
  531. package/neural-interface/public/shared/ui-cli-banner.js +23 -167
  532. package/neural-interface/public/shared/ui-command-runner.js +6 -3
  533. package/neural-interface/public/shared/ui-context-menu.js +295 -0
  534. package/neural-interface/public/shared/ui-cost-widget.js +57 -59
  535. package/neural-interface/public/shared/ui-crash-notice.js +187 -0
  536. package/neural-interface/public/shared/ui-detail.js +15 -3
  537. package/neural-interface/public/shared/ui-file-explorer.js +48 -6
  538. package/neural-interface/public/shared/ui-file-links.js +2 -2
  539. package/neural-interface/public/shared/ui-games.js +2 -2
  540. package/neural-interface/public/shared/ui-image-gallery.js +50 -47
  541. package/neural-interface/public/shared/ui-judgments.js +1 -1
  542. package/neural-interface/public/shared/ui-keybinds.js +33 -2
  543. package/neural-interface/public/shared/ui-link.js +3 -3
  544. package/neural-interface/public/shared/ui-menubar.js +10 -20
  545. package/neural-interface/public/shared/ui-native-loop-router-state.js +5 -0
  546. package/neural-interface/public/shared/ui-native-loop-router.js +11 -1
  547. package/neural-interface/public/shared/ui-navbar.js +49 -24
  548. package/neural-interface/public/shared/ui-notifications.js +1 -0
  549. package/neural-interface/public/shared/ui-panels.js +96 -65
  550. package/neural-interface/public/shared/ui-resume.js +9 -7
  551. package/neural-interface/public/shared/ui-schedules-studio.js +546 -431
  552. package/neural-interface/public/shared/ui-scroll-follow.js +16 -5
  553. package/neural-interface/public/shared/ui-sessions.js +27 -15
  554. package/neural-interface/public/shared/ui-settings.js +683 -526
  555. package/neural-interface/public/shared/ui-sidepanel-session-entry.js +9 -2
  556. package/neural-interface/public/shared/ui-sidepanel-sessions.js +4 -4
  557. package/neural-interface/public/shared/ui-sidepanel-state.js +23 -12
  558. package/neural-interface/public/shared/ui-sidepanel-tray.js +48 -7
  559. package/neural-interface/public/shared/ui-sidepanel-windows.js +18 -13
  560. package/neural-interface/public/shared/ui-skills.js +33 -2830
  561. package/neural-interface/public/shared/ui-styleguide.js +5 -2
  562. package/neural-interface/public/shared/ui-sync.js +15 -5
  563. package/neural-interface/public/shared/ui-terminal.js +270 -190
  564. package/neural-interface/public/shared/ui-tool-updates.js +6 -4
  565. package/neural-interface/public/shared/ui-tooltip.js +81 -51
  566. package/neural-interface/public/shared/ui-topright-overflow.js +233 -0
  567. package/neural-interface/public/shared/ui-trash.js +6 -4
  568. package/neural-interface/public/shared/ui-tutorial-layout.js +3 -117
  569. package/neural-interface/public/shared/ui-tutorial-preview.js +103 -0
  570. package/neural-interface/public/shared/ui-tutorial-steps.js +3 -65
  571. package/neural-interface/public/shared/ui-tutorial.css +47 -100
  572. package/neural-interface/public/shared/ui-tutorial.js +285 -509
  573. package/neural-interface/public/shared/ui-update.js +38 -2
  574. package/neural-interface/public/shared/ui-whiteboard.js +312 -59
  575. package/neural-interface/public/shared/ui-worker-end.js +5 -1
  576. package/neural-interface/public/shared/ui-workspaces.js +3 -2
  577. package/neural-interface/public/shared/view-variant.js +66 -0
  578. package/neural-interface/public/shared/whatsapp/wa-view.js +3 -3
  579. package/neural-interface/public/shared/whiteboard-list.js +172 -0
  580. package/neural-interface/public/shared/worker-end.js +10 -3
  581. package/neural-interface/public/shared/worker-questions.js +34 -0
  582. package/neural-interface/public/shared/worker-restart.js +12 -0
  583. package/neural-interface/public/sidepanel-session.html +2 -2
  584. package/neural-interface/public/variant/2d/background.js +2 -1
  585. package/neural-interface/public/variant/2d/context-menu.js +8 -2
  586. package/neural-interface/public/variant/2d/graph.js +42 -20
  587. package/neural-interface/public/variant/2d/hulls.js +14 -9
  588. package/neural-interface/public/variant/2d/lasso.js +11 -7
  589. package/neural-interface/public/variant/2d/main.js +32 -1
  590. package/neural-interface/public/variant/2d/minimap.js +11 -13
  591. package/neural-interface/public/variant/3d/main.js +69 -6
  592. package/neural-interface/public/variant/3d/map-controls.js +24 -9
  593. package/neural-interface/public/vendor/caveat/OFL.txt +93 -0
  594. package/neural-interface/public/vendor/caveat/caveat-latin-400-normal.woff2 +0 -0
  595. package/neural-interface/public/vendor/caveat/caveat-latin-700-normal.woff2 +0 -0
  596. package/neural-interface/public/vendor/caveat/caveat.css +17 -0
  597. package/neural-interface/public/vendor/caveat/manifest.json +12 -0
  598. package/neural-interface/public/vendor/yaml/LICENSE +13 -0
  599. package/neural-interface/public/vendor/yaml/manifest.json +4 -0
  600. package/neural-interface/public/vendor/yaml/yaml-2.9.1.min.js +137 -0
  601. package/neural-interface/scripts/build-vendor.mjs +32 -0
  602. package/neural-interface/server.js +4553 -2855
  603. package/neural-interface/templates/rulesets/README.md +1 -1
  604. package/neural-interface/templates/rulesets/core.md +1 -1
  605. package/neural-interface/templates/rulesets/legacy-hashes.json +23 -5
  606. package/neural-interface/templates/rulesets/manifest.json +8 -8
  607. package/npm-shrinkwrap.json +34 -12
  608. package/package.json +17 -3
  609. package/postinstall.js +9 -4
  610. package/preuninstall.js +1 -1
  611. package/setup.js +97 -322
  612. package/skills/skill-forge/SKILL.md +177 -0
  613. package/skills/skill-forge/evals/evals.json +54 -0
  614. package/skills/skill-forge/references/package.md +105 -0
  615. package/skills/skill-forge/references/review-and-recovery.md +63 -0
  616. package/skills/skill-forge/references/runtime-profiles.md +20 -0
  617. package/skills/skill-forge/references/sources-and-capabilities.md +51 -0
  618. package/skills/synabun/SKILL.md +10 -7
  619. package/skills/synabun/modules/audit.md +1 -5
  620. package/skills/synabun/modules/changelog.md +1 -5
  621. package/skills/synabun/modules/idea.md +1 -1
  622. package/skills/synabun/modules/memorize.md +6 -9
  623. package/skills/synabun/modules/schedule.md +6 -6
  624. package/mcp-server/dist/services/profiles.d.ts +0 -120
  625. package/mcp-server/dist/services/profiles.d.ts.map +0 -1
  626. package/mcp-server/dist/services/profiles.js +0 -387
  627. package/mcp-server/dist/services/profiles.js.map +0 -1
  628. package/mcp-server/dist/tools/leonardo-browser-tools.d.ts +0 -97
  629. package/mcp-server/dist/tools/leonardo-browser-tools.d.ts.map +0 -1
  630. package/mcp-server/dist/tools/leonardo-browser-tools.js +0 -228
  631. package/mcp-server/dist/tools/leonardo-browser-tools.js.map +0 -1
  632. package/mcp-server/dist/tools/leonardo.d.ts +0 -13
  633. package/mcp-server/dist/tools/leonardo.d.ts.map +0 -1
  634. package/mcp-server/dist/tools/leonardo.js +0 -21
  635. package/mcp-server/dist/tools/leonardo.js.map +0 -1
  636. package/mcp-server/dist/tools/profile.d.ts +0 -17
  637. package/mcp-server/dist/tools/profile.d.ts.map +0 -1
  638. package/mcp-server/dist/tools/profile.js +0 -114
  639. package/mcp-server/dist/tools/profile.js.map +0 -1
  640. package/mcp-server/src/services/profiles.ts +0 -428
  641. package/mcp-server/src/tools/leonardo-browser-tools.ts +0 -291
  642. package/mcp-server/src/tools/leonardo.ts +0 -30
  643. package/mcp-server/src/tools/profile.ts +0 -122
  644. package/neural-interface/lib/assistant-brains/opencode-browser-policy.js +0 -47
  645. package/neural-interface/lib/assistant-brains/opencode-route-gate.js +0 -62
  646. package/neural-interface/lib/mcp-profile-servers.js +0 -120
  647. package/neural-interface/public/shared/ui-tutorial-draw.js +0 -311
  648. package/skills/leonardo/SKILL.md +0 -168
  649. package/skills/leonardo/icon.svg +0 -1
  650. package/skills/leonardo/modules/browser-guide.md +0 -378
  651. package/skills/leonardo/modules/image-prompter.md +0 -283
  652. package/skills/leonardo/modules/model-advisor.md +0 -100
  653. package/skills/leonardo/modules/prompt-library.md +0 -110
  654. package/skills/leonardo/modules/style-guide.md +0 -186
  655. package/skills/leonardo/modules/video-prompter.md +0 -317
  656. /package/neural-interface/templates/rulesets/{gemini.md → antigravity.md} +0 -0
@@ -10,6 +10,8 @@
10
10
  // Claude → cp/cp-permissions.js { behavior, always, updatedInput, updatedPermissions, message, planDecision }
11
11
  // Codex → cdx/cdx-requests.js result:{ decision } | result:{ permissions, scope } | result:{ answers } | result:{ action, content }
12
12
  // OpenCode → ocp-v2/ocp-v2-render.js reply:'once'|'always'|'reject' | answers:[[label]]
13
+ // Antigravity (a dispatched worker's ACP session/request_permission, relayed by the broker as
14
+ // { toolName, input: <the ACP toolCall> }) → { behavior } once or deny, never "always"
13
15
  // Every response additionally carries `behavior`, `provider` and `kind` so the
14
16
  // server-side envelope translator can route without re-deriving them; Codex
15
17
  // replies repeat `answers` / `content` and OpenCode replies repeat `always` at
@@ -25,11 +27,22 @@
25
27
  // Submit answers them, Skip lets the brain go on its assumptions; the reply is
26
28
  // { kind:'clarify', behavior, answers: string[][] } and the server's clarifier
27
29
  // (lib/assistant-clarify.js) owns it, never the brain.
30
+ //
31
+ // Every card that asks (question, elicitation, clarify) is drawn by the mascot,
32
+ // like the follow-ups card (asst-ask.js): its face (`ask`, live while it is
33
+ // the newest open card of the panel) beside its first bubble, the questions in
34
+ // its bubbles, the options as numbered rows (1-9, arrows, Enter; Esc goes to
35
+ // the composer). Only the drawing changed: what each provider is sent is built by
36
+ // buildControlResponse from the same answers as before.
28
37
 
29
38
  import { normalizeProvider } from './asst-state.js';
30
39
  import { sanitizeInto } from './asst-sanitize.js';
31
40
  import { fill, maskEcho, redactInput } from './asst-tool-kinds.js';
32
41
  import { mascotSvg, paintMascot, stillFrame } from '../synabun-mascot.js';
42
+ import { splitRecommended } from './asst-followups.js';
43
+ import {
44
+ askOption, createPresenter, injectAskStyles, keyRange, setOptionChecked, wireCardKeys, wireGaze, wireOptionGroup, wireWatch,
45
+ } from './asst-ask.js';
33
46
  import {
34
47
  SYNABUN_CHOICE_MARKER,
35
48
  SYNABUN_OTHER_VALUE,
@@ -181,6 +194,9 @@ export function describeToolInput(toolName, input = {}) {
181
194
  function inferProvider(req, packet) {
182
195
  const explicit = normalizeProvider(packet?.provider ?? req?.provider);
183
196
  if (explicit) return explicit;
197
+ // An ACP permission request (Antigravity): a tool call with its id, options of allow_* / reject_* kinds.
198
+ if (req?.brain_native?.toolCall?.toolCallId || req?.toolCall?.toolCallId) return 'antigravity';
199
+ if (Array.isArray(req?.options) && req.options.some(o => typeof o?.optionId === 'string' && /^(allow|reject)_(once|always)$/.test(String(o?.kind || '')))) return 'antigravity';
184
200
  if (typeof req?.method === 'string' && req.method.includes('/')) return 'codex';
185
201
  if (typeof req?.brain_native?.method === 'string' && req.brain_native.method.includes('/')) return 'codex';
186
202
  if (req?.subtype === 'can_use_tool' || req?.subtype === 'permission_request' || req?.tool_name) return 'claude-code';
@@ -285,9 +301,49 @@ export function normalizeControlRequest(packet, { origin = null } = {}) {
285
301
  if (firstStr(req.tool_name, req.toolName) === 'ExitPlanMode') return normalizeClaude(req, base);
286
302
  if (provider === 'codex') return normalizeCodex(req, base);
287
303
  if (provider === 'opencode') return normalizeOpenCode(req, base);
304
+ if (provider === 'antigravity') return normalizeAntigravity(req, base);
288
305
  return normalizeClaude(req, base);
289
306
  }
290
307
 
308
+ // The path-like fields of an Antigravity tool call's arguments (lib/worker-confinement.js reads the same ones).
309
+ const ACP_PATH_KEYS = ['path', 'file_path', 'filePath', 'Path', 'AbsolutePath', 'TargetFile', 'DirectoryPath', 'SearchPath'];
310
+
311
+ /**
312
+ * An Antigravity worker's permission request: the broker relays the ACP tool call
313
+ * ({ toolCallId, title, kind, status, locations, rawInput }) as `input`. The card shows
314
+ * the call's own arguments, and its command (execute) or the paths it touches as the detail.
315
+ */
316
+ function normalizeAntigravity(req, base) {
317
+ // A worker's relay sends the ACP tool call as `input`; the brain sends the call's arguments as `input` and the
318
+ // call itself as `brain_native.toolCall`. Either way: the call, then its arguments.
319
+ const given = obj(req.input) || {};
320
+ const looksLikeCall = given.rawInput !== undefined || given.toolCallId !== undefined || Array.isArray(given.locations);
321
+ const call = obj(req.brain_native?.toolCall) || obj(req.toolCall) || (looksLikeCall ? given : {});
322
+ const args = obj(call.rawInput) || (looksLikeCall ? {} : given);
323
+ const kind = str(call.kind) || 'other';
324
+ // An MCP call names its server and tool in its arguments ({ ServerName, ToolName, Arguments }).
325
+ const mcpServer = firstStr(args.ServerName, args.serverName);
326
+ const mcpTool = firstStr(args.ToolName, args.toolName);
327
+ const mcpArgs = obj(args.Arguments) || obj(args.arguments);
328
+ const command = Array.isArray(args.command) ? args.command.map(str).join(' ') : firstStr(args.command, args.CommandLine, args.cmd);
329
+ const paths = [...new Set([
330
+ ...(Array.isArray(call.locations) ? call.locations : []).map(location => str(location?.path)),
331
+ ...ACP_PATH_KEYS.map(key => (typeof args[key] === 'string' ? str(args[key]) : '')),
332
+ ].filter(Boolean))];
333
+ let mcpDetail = '';
334
+ if (mcpServer && mcpTool && mcpArgs) { try { mcpDetail = JSON.stringify(mcpArgs).slice(0, 400); } catch { mcpDetail = ''; } }
335
+ const detail = mcpServer && mcpTool ? (mcpDetail || `${mcpServer} · ${mcpTool}`)
336
+ : kind === 'execute' && command ? command : paths.length ? paths.join('\n') : str(call.title);
337
+ return {
338
+ ...base,
339
+ kind: CONTROL_KINDS.PERMISSION,
340
+ toolName: (mcpServer && mcpTool ? `${mcpServer}_${mcpTool}` : '') || firstStr(req.toolName, req.tool_name, call.title, kind) || 'tool',
341
+ title: 'Permission required',
342
+ detail,
343
+ input: mcpServer && mcpTool && mcpArgs ? mcpArgs : args,
344
+ };
345
+ }
346
+
291
347
  function normalizeClaude(req, base) {
292
348
  const toolName = firstStr(req.tool_name, req.toolName) || 'Unknown';
293
349
  const input = obj(req.input) || {};
@@ -532,6 +588,8 @@ export function buildControlResponse(normalized, decision = {}) {
532
588
  if (normalized.kind === CONTROL_KINDS.PLAN) return buildClaude(normalized, decision, base, allow, always);
533
589
  if (normalized.provider === 'codex') return buildCodex(normalized, decision, base, allow, always);
534
590
  if (normalized.provider === 'opencode') return buildOpenCode(normalized, decision, base, allow, always);
591
+ // Antigravity: allowed once or denied; an "always" is never sent (see controlActions).
592
+ if (normalized.provider === 'antigravity') return buildClaude(normalized, decision, base, allow, false);
535
593
  return buildClaude(normalized, decision, base, allow, always);
536
594
  }
537
595
 
@@ -640,6 +698,7 @@ export function controlActions(normalized) {
640
698
  ];
641
699
  }
642
700
  const actions = [];
701
+ // Never for Antigravity: its "always" option is saved by Antigravity for later sessions too, beyond this run.
643
702
  const canAlways = n.provider === 'claude-code'
644
703
  || n.provider === 'opencode'
645
704
  || (n.provider === 'codex' && (n.method === 'item/permissions/requestApproval'
@@ -691,6 +750,17 @@ export function renderControlCard(container, normalized, hooks = {}) {
691
750
  card.setAttribute('role', 'group');
692
751
  card.setAttribute('aria-label', t(`assistant.control.${n.kind}`, n.title || n.kind));
693
752
 
753
+ // A card that asks is the mascot asking (asst-ask.js): its face beside its first bubble (renderQuestionBody).
754
+ const asking = n.kind === CONTROL_KINDS.QUESTION || n.kind === CONTROL_KINDS.ELICITATION || n.kind === CONTROL_KINDS.CLARIFY;
755
+ const presenter = asking ? createPresenter({ pose: 'ask', waits: true, entrance: 'pulse' }) : null;
756
+ if (presenter) {
757
+ injectAskStyles();
758
+ card.classList.add('asst-ask');
759
+ }
760
+ // What the renderer reads to make this card's face live while it is the newest open card (asst-render.js).
761
+ const ask = presenter ? { el: card, presenter, isOpen: () => !state.resolved, onChange: null } : null;
762
+ if (ask) card._ask = ask;
763
+
694
764
  const head = el('div', 'asst-control-head');
695
765
  const kindLabel = el('span', 'asst-control-kind', t(`assistant.control.${n.kind}`, n.title || n.kind));
696
766
  head.appendChild(kindLabel);
@@ -710,11 +780,14 @@ export function renderControlCard(container, normalized, hooks = {}) {
710
780
  card.appendChild(body);
711
781
 
712
782
  const state = { resolved: false, answers: n.questions.map(() => ({ selected: new Set(), custom: '' })), bashInput: null, denyMsg: null, checkedSuggestions: new Set() };
783
+ // Back to the message box (Esc in the card, and after an answer the card had focus for).
784
+ const toComposer = () => { try { hooks.focusComposer?.(); } catch { /* the host is gone */ } };
785
+ let groups = [];
713
786
 
714
787
  if (n.kind === CONTROL_KINDS.PERMISSION) renderPermissionBody(body, n, state, t);
715
788
  else if (n.kind === CONTROL_KINDS.COMPUTER) body.appendChild(el('div', 'asst-control-message', t('assistant.control.computerBody', n.detail)));
716
789
  else if (n.kind === CONTROL_KINDS.PLAN) renderPlanBody(body, n, hooks);
717
- else renderQuestionBody(body, n, state, t);
790
+ else groups = renderQuestionBody(body, n, state, t, { presenter, onEscape: toComposer });
718
791
 
719
792
  const actions = el('div', 'asst-control-actions');
720
793
  const denyMsg = el('textarea', 'asst-control-deny-msg');
@@ -726,11 +799,15 @@ export function renderControlCard(container, normalized, hooks = {}) {
726
799
  denyMsg.setAttribute('aria-label', denyMsg.placeholder);
727
800
  denyMsg.rows = 1;
728
801
  denyMsg.hidden = n.kind !== CONTROL_KINDS.PLAN;
729
- denyMsg.addEventListener('keydown', (e) => e.stopPropagation());
802
+ denyMsg.addEventListener('keydown', (e) => {
803
+ if (presenter && e.key === 'Escape') { e.preventDefault(); toComposer(); }
804
+ e.stopPropagation();
805
+ });
730
806
  state.denyMsg = denyMsg;
731
807
 
732
808
  const buttons = [];
733
- const finish = (label) => {
809
+ /** `answered`: the user answered here (the mascot hops and settles on its "got it" face); else it just goes still. */
810
+ const finish = (label, answered = false) => {
734
811
  state.resolved = true;
735
812
  card.classList.remove('active');
736
813
  card.classList.add('resolved');
@@ -739,7 +816,13 @@ export function renderControlCard(container, normalized, hooks = {}) {
739
816
  card.querySelectorAll('button, input, textarea').forEach(node => { if (!node.classList?.contains('asst-reveal')) node.disabled = true; });
740
817
  status.textContent = label;
741
818
  status.hidden = false;
819
+ if (presenter) {
820
+ presenter.settle(answered ? 'success' : 'idle', {}, { hop: answered });
821
+ presenter.el.classList.toggle('is-answered', answered);
822
+ }
823
+ try { ask?.onChange?.(); } catch { /* the renderer is gone */ }
742
824
  };
825
+ const focusInside = () => { try { return !!card.contains?.(globalThis.document?.activeElement); } catch { return false; } };
743
826
 
744
827
  for (const action of controlActions(n)) {
745
828
  const btn = el('button', `asst-btn asst-btn-${action.tone}`);
@@ -757,6 +840,7 @@ export function renderControlCard(container, normalized, hooks = {}) {
757
840
  }
758
841
  btn.addEventListener('click', () => {
759
842
  if (state.resolved) return;
843
+ const hadFocus = presenter && focusInside();
760
844
  const decision = { ...action.decision };
761
845
  if (decision.behavior === 'deny' && denyMsg.value.trim()) decision.message = denyMsg.value.trim();
762
846
  if (n.kind === CONTROL_KINDS.PERMISSION && decision.behavior === 'allow') {
@@ -769,17 +853,29 @@ export function renderControlCard(container, normalized, hooks = {}) {
769
853
  decision.answers = state.answers.map(a => (a.custom ? [a.custom] : [...a.selected]));
770
854
  }
771
855
  if (n.kind === CONTROL_KINDS.CLARIFY) {
772
- finish(decision.behavior === 'allow' ? t('assistant.control.state.answered', 'Answered') : t('assistant.control.state.skipped', 'Skipped'));
856
+ finish(decision.behavior === 'allow' ? t('assistant.control.state.answered', 'Answered') : t('assistant.control.state.skipped', 'Skipped'), decision.behavior === 'allow');
857
+ } else if (presenter) {
858
+ // A question is answered or declined, not allowed or denied (the reply is the same as before).
859
+ finish(decision.behavior === 'allow' ? t('assistant.control.state.answered', 'Answered') : t('assistant.control.state.declined', 'Declined'), decision.behavior === 'allow');
773
860
  } else {
774
861
  finish(decision.behavior === 'allow'
775
862
  ? (decision.always ? t('assistant.control.state.always', 'Always') : t('assistant.control.state.allowed', 'Allowed'))
776
- : t('assistant.control.state.denied', 'Denied'));
863
+ : t('assistant.control.state.denied', 'Denied'), !!presenter && decision.behavior === 'allow');
777
864
  }
778
865
  hooks.onRespond?.(n, decision);
866
+ if (hadFocus) toComposer();
779
867
  });
780
868
  buttons.push(btn);
781
869
  actions.appendChild(btn);
782
870
  }
871
+ if (presenter) {
872
+ // The keys, said once focus is in the card (asst-ask-styles.js).
873
+ const most = Math.max(0, ...groups.map((g) => g.buttons.length));
874
+ const keys = el('span', 'asst-ask-keys', most
875
+ ? fill(t('assistant.control.keys', '{keys} to pick · Enter to answer · Esc for the message box', { keys: keyRange(most) }), { keys: keyRange(most) })
876
+ : t('assistant.control.keysText', 'Enter to answer · Esc for the message box'));
877
+ actions.appendChild(keys);
878
+ }
783
879
  state.updateSubmit = () => {
784
880
  if (!state.submitBtn) return;
785
881
  const needed = n.questions.map((q, i) => ({ q, i })).filter(({ q }) => q.required !== false);
@@ -795,6 +891,7 @@ export function renderControlCard(container, normalized, hooks = {}) {
795
891
 
796
892
  card.appendChild(denyMsg);
797
893
  card.appendChild(actions);
894
+ if (presenter) wireAsking(card, { groups, state, presenter, toComposer });
798
895
  if (container) container.appendChild(card);
799
896
  try { hooks.scrollEnd?.(); } catch { /* ignore */ }
800
897
 
@@ -804,9 +901,61 @@ export function renderControlCard(container, normalized, hooks = {}) {
804
901
  lock(label) { if (!state.resolved) finish(label || t('assistant.control.state.resolved', 'Resolved')); },
805
902
  // Answered here, but the request closed before the answer reached it: the answer did nothing.
806
903
  expire(label) { finish(label || t('assistant.control.state.expired', 'Expired')); card.classList.add('expired'); },
904
+ // The mascot's part, for the renderer (null on a card that does not ask).
905
+ ask,
807
906
  };
808
907
  }
809
908
 
909
+ /**
910
+ * A question card's keys and gaze (asst-ask.js). Each question's options are one tab stop (arrows move;
911
+ * a radio follows focus, as radios do); 1-9 pick an option of the question focus is in (else the first one
912
+ * still unanswered); Enter on a radio picks it and moves on: to the next question still unanswered, else
913
+ * Submit, which a card of one question presses at once; Esc goes back to the composer. The mascot looks
914
+ * at the option pointed at or focused, and watches a typed answer.
915
+ */
916
+ function wireAsking(card, { groups, state, presenter, toComposer }) {
917
+ const active = () => { try { return globalThis.document?.activeElement || null; } catch { return null; } };
918
+ const done = (g) => !!(state.answers[g.qIdx]?.custom || state.answers[g.qIdx]?.selected.size);
919
+ const current = () => groups.find((g) => g.section.contains?.(active())) || groups.find((g) => !done(g)) || groups[0] || null;
920
+ const focus = (node) => { try { node?.focus?.(); } catch { /* not focusable here */ } };
921
+ const focusGroup = (g) => focus(g.buttons.find((b) => b.classList.contains('selected')) || g.buttons[0] || g.input);
922
+ /** After a pick by key: the next question still unanswered, else Submit (pressed at once for a lone question). */
923
+ function advance(g) {
924
+ const after = groups.slice(groups.indexOf(g) + 1).find((x) => !done(x)) || groups.find((x) => x !== g && !done(x));
925
+ if (after) { focusGroup(after); return; }
926
+ const submit = state.submitBtn;
927
+ if (!submit || submit.disabled) return;
928
+ if (groups.length === 1) submit.click();
929
+ else focus(submit);
930
+ }
931
+ for (const g of groups) {
932
+ if (!g.options || !g.buttons.length) continue;
933
+ wireOptionGroup(g.options, { options: () => g.buttons, onMove: (btn) => { if (!g.q.multiple && !btn.classList.contains('selected')) btn.click(); } });
934
+ }
935
+ wireCardKeys(card, {
936
+ options: () => current()?.buttons || [],
937
+ onPick: (_i, btn) => {
938
+ const g = current();
939
+ if (state.resolved || !btn || !g) return;
940
+ focus(btn);
941
+ btn.click();
942
+ if (!g.q.multiple) advance(g);
943
+ },
944
+ onComposer: toComposer,
945
+ onEnter: (e) => {
946
+ if (state.resolved) return false;
947
+ const g = groups.find((x) => x.buttons.includes(e.target));
948
+ if (!g || g.q.multiple) return false; // a checkbox toggles, a button presses: their own Enter
949
+ if (!e.target.classList.contains('selected')) e.target.click();
950
+ advance(g);
951
+ return true;
952
+ },
953
+ });
954
+ wireGaze(card, presenter);
955
+ presenter.setHome(groups[0]?.buttons[0] || groups[0]?.input || null);
956
+ for (const g of groups) if (g.input) wireWatch(g.input, presenter);
957
+ }
958
+
810
959
  /**
811
960
  * A card that waits on the user says so the same way everywhere (this card,
812
961
  * the route card): a still blocked cameo before its kind, which the
@@ -922,52 +1071,79 @@ function renderPlanBody(body, n, hooks) {
922
1071
  body.appendChild(planEl);
923
1072
  }
924
1073
 
925
- function renderQuestionBody(body, n, state, t) {
926
- if (n.message) body.appendChild(el('div', 'asst-control-message', n.message));
1074
+ /**
1075
+ * The questions of a card that asks, as the mascot asks them: its words in bubbles (the card's message
1076
+ * first, then each question), the first beside its face with the notch pointing at it, each question's
1077
+ * options as numbered rows (asst-ask.js askOption, radios or checkboxes), and a field for a typed answer.
1078
+ * Picks and typed answers go to `state.answers` as they always did. → the question groups, for the keys.
1079
+ */
1080
+ function renderQuestionBody(body, n, state, t, { presenter = null, onEscape = null } = {}) {
1081
+ let lead = true;
1082
+ /** A bubble; the first one shares a stage row with the mascot's face. */
1083
+ const speech = (node) => {
1084
+ node.classList.add('asst-ask-bubble');
1085
+ if (!lead) return node;
1086
+ lead = false;
1087
+ node.classList.add('is-lead');
1088
+ if (!presenter) return node;
1089
+ const stage = el('div', 'asst-ask-stage');
1090
+ stage.appendChild(presenter.el);
1091
+ stage.appendChild(node);
1092
+ return stage;
1093
+ };
1094
+ // Nothing for it to say (no message, no question text): the face still leads the card.
1095
+ if (presenter && !n.message && !n.questions.some((q) => q.text || q.header)) body.appendChild(presenter.el);
1096
+ const groups = [];
1097
+ if (n.message) body.appendChild(speech(el('div', 'asst-control-message', n.message)));
927
1098
  n.questions.forEach((q, qIdx) => {
928
1099
  const section = el('div', 'asst-control-q');
929
- if (q.header) section.appendChild(el('div', 'asst-control-q-header', q.header));
930
- if (q.text && q.text !== q.header) section.appendChild(el('div', 'asst-control-q-text', q.text));
1100
+ // The mascot says the question; a header that only repeats it is not said twice.
1101
+ if (q.header && q.text && q.text !== q.header) section.appendChild(el('div', 'asst-control-q-header', q.header));
1102
+ if (q.text || q.header) section.appendChild(speech(el('div', 'asst-control-q-text', q.text || q.header)));
931
1103
  if (q.multiple) section.appendChild(el('div', 'asst-control-q-hint', t('assistant.control.multiHint', 'Select all that apply')));
932
1104
  const optionButtons = [];
933
1105
  let customInput = null;
1106
+ let opts = null;
934
1107
  if (q.options.length) {
935
- const opts = el('div', `asst-control-options${q.multiple ? ' multi' : ''}`);
1108
+ opts = el('div', `asst-control-options${q.multiple ? ' multi' : ''}`);
936
1109
  opts.setAttribute('role', q.multiple ? 'group' : 'radiogroup');
937
1110
  opts.setAttribute('aria-label', q.header || q.text || t('assistant.control.question', 'Question'));
938
- for (const opt of q.options) {
939
- const btn = el('button', 'asst-control-option');
940
- btn.type = 'button';
941
- btn.setAttribute('role', q.multiple ? 'checkbox' : 'radio');
942
- btn.setAttribute('aria-checked', 'false');
943
- btn.appendChild(el('span', 'asst-control-option-label', opt.label));
944
- if (opt.description) btn.appendChild(el('span', 'asst-control-option-desc', opt.description));
1111
+ q.options.forEach((opt, oIdx) => {
1112
+ // Shown without a "(Recommended)" suffix, badged instead; the answer keeps the label as written.
1113
+ const shown = splitRecommended(opt.label);
1114
+ const btn = askOption({
1115
+ label: shown.label,
1116
+ description: opt.description,
1117
+ index: oIdx,
1118
+ role: q.multiple ? 'checkbox' : 'radio',
1119
+ badge: shown.recommended ? t('assistant.followups.recommended', 'Recommended') : '',
1120
+ });
1121
+ btn.classList.add('asst-control-option');
945
1122
  btn.addEventListener('click', () => {
946
1123
  if (state.resolved) return;
947
1124
  const ans = state.answers[qIdx];
948
1125
  ans.custom = '';
949
1126
  if (customInput) customInput.value = '';
1127
+ const was = ans.selected.has(opt.label);
950
1128
  if (q.multiple) {
951
- if (ans.selected.has(opt.label)) ans.selected.delete(opt.label); else ans.selected.add(opt.label);
1129
+ if (was) ans.selected.delete(opt.label); else ans.selected.add(opt.label);
952
1130
  } else {
953
1131
  ans.selected = new Set([opt.label]);
954
1132
  }
955
- for (const b of optionButtons) {
956
- const on = ans.selected.has(b.dataset.label);
957
- b.classList.toggle('selected', on);
958
- b.setAttribute('aria-checked', on ? 'true' : 'false');
959
- }
1133
+ for (const b of optionButtons) setOptionChecked(b, ans.selected.has(b.dataset.label));
1134
+ // The mascot answers the pick: a pop for a tick, a nod for a choice.
1135
+ if (!was) presenter?.react(q.multiple ? 'pop' : 'nod');
960
1136
  state.updateSubmit?.();
961
1137
  });
962
1138
  btn.dataset.label = opt.label;
963
1139
  optionButtons.push(btn);
964
1140
  opts.appendChild(btn);
965
- }
1141
+ });
966
1142
  section.appendChild(opts);
967
1143
  }
968
1144
  customInput = document.createElement('input');
969
1145
  customInput.type = q.type === 'number' || q.type === 'integer' ? 'number' : 'text';
970
- customInput.className = 'asst-control-custom';
1146
+ customInput.className = 'asst-control-custom asst-ask-input';
971
1147
  customInput.placeholder = q.options.length
972
1148
  ? t('assistant.control.customAnswer', 'Or type your own answer…')
973
1149
  : t('assistant.control.typeAnswer', 'Type your answer…');
@@ -977,16 +1153,18 @@ function renderQuestionBody(body, n, state, t) {
977
1153
  ans.custom = customInput.value.trim();
978
1154
  if (ans.custom) {
979
1155
  ans.selected.clear();
980
- for (const b of optionButtons) { b.classList.remove('selected'); b.setAttribute('aria-checked', 'false'); }
1156
+ for (const b of optionButtons) setOptionChecked(b, false);
981
1157
  }
982
1158
  state.updateSubmit?.();
983
1159
  });
984
1160
  customInput.addEventListener('keydown', (e) => {
985
1161
  if (e.key === 'Enter' && state.submitBtn && !state.submitBtn.disabled) { e.preventDefault(); state.submitBtn.click(); }
1162
+ if (e.key === 'Escape' && onEscape) { e.preventDefault(); onEscape(); }
986
1163
  e.stopPropagation();
987
1164
  });
988
1165
  section.appendChild(customInput);
989
1166
  body.appendChild(section);
1167
+ groups.push({ q, qIdx, section, options: opts, buttons: optionButtons, input: customInput });
990
1168
  });
991
1169
  // A clarify card also shows what the assistant will assume for the rest, so the user can correct it.
992
1170
  const assumptions = n.clarify?.assumptions || [];
@@ -994,6 +1172,7 @@ function renderQuestionBody(body, n, state, t) {
994
1172
  const list = assumptions.join(' · ');
995
1173
  body.appendChild(el('div', 'asst-control-assume', t('assistant.control.assuming', `Otherwise I'll assume: ${list}`, { list })));
996
1174
  }
1175
+ return groups;
997
1176
  }
998
1177
 
999
1178
  export function describeSuggestion(s) {