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
@@ -13,16 +13,43 @@
13
13
 
14
14
  export const KIND_IDS = Object.freeze(['shell', 'read', 'edit', 'search', 'web', 'subagent', 'plan', 'memory', 'runs', 'computer', 'think', 'mcp']);
15
15
 
16
- // Tool names after lowercasing and stripping `mcp__<server>__` / `<server>_`.
16
+ // Tool names after lowercasing and stripping `mcp__<server>__` / `<server>_`. Antigravity's own tools keep their
17
+ // snake_case names (run_command, read_file, write_to_file, grep_search, search_web …).
17
18
  const KIND_TOOLS = {
18
- shell: ['bash', 'bashoutput', 'killshell', 'shell', 'exec_command', 'commandexecution'],
19
- read: ['read', 'notebookread', 'view'],
20
- edit: ['edit', 'multiedit', 'write', 'notebookedit', 'patch', 'apply_patch', 'filechange'],
21
- search: ['grep', 'glob', 'ls', 'list', 'codesearch', 'toolsearch'],
22
- web: ['webfetch', 'websearch'],
23
- subagent: ['task', 'agent', 'collabtoolcall', 'taskstop'],
19
+ shell: ['bash', 'bashoutput', 'killshell', 'shell', 'exec_command', 'commandexecution', 'run_command', 'send_command_input', 'command_status', 'read_terminal', 'shell_exec'],
20
+ read: ['read', 'notebookread', 'view', 'read_file', 'view_file', 'view_file_outline', 'view_code_item', 'view_content_chunk', 'read_resource', 'read_notebook'],
21
+ edit: ['edit', 'multiedit', 'write', 'notebookedit', 'patch', 'apply_patch', 'filechange', 'write_to_file', 'write_file', 'create_file', 'replace_file_content', 'multi_replace_file_content', 'edit_file', 'edit_notebook', 'delete_file', 'move_file'],
22
+ search: ['grep', 'glob', 'ls', 'list', 'codesearch', 'toolsearch', 'grep_search', 'find_by_name', 'list_dir', 'list_directory', 'codebase_search', 'code_search'],
23
+ web: ['webfetch', 'websearch', 'search_web', 'read_url_content', 'open_browser_url', 'read_browser_page', 'browser_subagent'],
24
+ subagent: ['task', 'agent', 'collabtoolcall', 'taskstop', 'invoke_subagent'],
24
25
  plan: ['todowrite', 'todoread', 'update_plan'],
25
26
  };
27
+
28
+ // Antigravity names its arguments in its own words: each alias is filled from the first of them that is set.
29
+ const INPUT_ALIASES = [
30
+ ['command', ['CommandLine']],
31
+ ['cwd', ['Cwd']],
32
+ ['file_path', ['AbsolutePath', 'TargetFile', 'Path']],
33
+ ['path', ['DirectoryPath', 'SearchPath', 'SearchDirectory']],
34
+ ['query', ['Query']],
35
+ ['url', ['Url']],
36
+ ];
37
+
38
+ /**
39
+ * A tool call's input with the names the rack reads (command, file_path, path, query, url) filled from
40
+ * Antigravity's own (CommandLine, AbsolutePath, TargetFile, DirectoryPath, Query, Url …). A name that is set
41
+ * already is kept; anything else is left as it came. Not an object: {}.
42
+ */
43
+ export function canonicalToolInput(input) {
44
+ const i = input && typeof input === 'object' && !Array.isArray(input) ? input : {};
45
+ let out = null;
46
+ for (const [alias, sources] of INPUT_ALIASES) {
47
+ if (i[alias] !== undefined && i[alias] !== null && i[alias] !== '') continue;
48
+ const value = sources.map(key => i[key]).find(v => typeof v === 'string' && v);
49
+ if (value) { out = out || { ...i }; out[alias] = value; }
50
+ }
51
+ return out || i;
52
+ }
26
53
  // SynaBun's own tools: only when the call is SynaBun's (or carries no server).
27
54
  const MEMORY_TOOLS = ['recall', 'remember', 'reflect', 'forget', 'restore', 'memories', 'sync', 'category'];
28
55
  const COMPUTER_TOOLS = ['computer', 'computer_apps', 'computer_ax', 'computer_status'];
@@ -181,11 +208,18 @@ export function capitalize(text) {
181
208
  return s ? s[0].toLocaleUpperCase() + s.slice(1) : s;
182
209
  }
183
210
 
211
+ /** A letter or a digit: what a cut must keep some of. */
212
+ const CONTENT = /[\p{L}\p{N}]/u;
213
+ /** The "…" a text ends on (a clipped query, `"…"`), with the quote or bracket after it. */
214
+ const END_CUT = /…([^\p{L}\p{N}…]*)$/u;
215
+
184
216
  /**
185
217
  * Cut `text` in the middle so it fits `max` chars, keeping at least `minTail`
186
218
  * tail chars and cutting at token boundaries (spaces, slashes) when one is near.
187
- * One cut, shorter than the text: never a head and a tail that overlap, and a
188
- * token the text already shortened ("…/name") that the cut meets goes with it.
219
+ * One cut, shorter than the text: never a head and a tail that overlap. What it
220
+ * shows has one "…": the cut takes in every "…" the text already has (a token
221
+ * the summary shortened, "…/name"; its clipped end), so the head comes from
222
+ * before the first of them and the tail from after the last.
189
223
  */
190
224
  export function middleEllipsis(text, max = 96, minTail = 24) {
191
225
  const s = str(text);
@@ -194,28 +228,133 @@ export function middleEllipsis(text, max = 96, minTail = 24) {
194
228
  // A cut that keeps this much removes nothing: under a small `max` the budget rises to minTail + 6,
195
229
  // past a short text's end, and the head and the tail overlapped ("$ np…npm test" of "$ npm test").
196
230
  if (s.length <= budget + 1) return s;
197
- let tailStart = s.length - minTail;
198
- // Pull the tail back to the token boundary before it, within a third of the budget.
199
- const floor = s.length - Math.max(minTail, Math.floor(budget / 3) + minTail);
200
- for (let i = tailStart; i > floor && i > 0; i -= 1) {
231
+ const first = s.indexOf('…');
232
+ const last = s.lastIndexOf('…');
233
+ const headEnd = first < 0 ? s.length : first;
234
+ const tailFrom = last < 0 ? 0 : last + 1;
235
+ // "…words…" (a thought's tail that ends on its own "…"): nothing to keep on either side of the cuts (headEllipsis).
236
+ if (first >= 0 && !CONTENT.test(s.slice(0, headEnd)) && !CONTENT.test(s.slice(tailFrom))) return headEllipsis(s, max);
237
+ let tailStart = Math.max(tailFrom, s.length - minTail);
238
+ // A head that stops at the text's first "…" leaves the rest of the budget to the tail.
239
+ if (headEnd < budget - (s.length - tailStart)) tailStart = Math.max(tailFrom, s.length - (budget - headEnd));
240
+ // Pull the tail back to the token boundary before it, within a third of the budget and short of all of it
241
+ // (a char of head, or the cut runs one past `max`).
242
+ const floor = s.length - Math.min(budget - 1, Math.max(minTail, Math.floor(budget / 3) + minTail));
243
+ let atBoundary = false;
244
+ for (let i = tailStart; i > floor && i > tailFrom && i > 0; i -= 1) {
201
245
  const c = s[i - 1];
202
- if (c === ' ') { tailStart = i; break; }
203
- if (c === '/') { tailStart = i - 1; break; }
246
+ if (c === ' ') { tailStart = i; atBoundary = true; break; }
247
+ if (c === '/') { tailStart = i - 1; atBoundary = true; break; }
248
+ }
249
+ // None near enough behind a tail that opens inside a word: it starts at the next boundary instead, when
250
+ // that keeps half of it ("$ node --test…b.mjs c.mjs", never "…r.mjs b.mjs c.mjs").
251
+ if (!atBoundary && tailStart > tailFrom) {
252
+ const rest = s.slice(tailStart);
253
+ const next = rest.search(/[\s/]/);
254
+ if (next > 0 && next <= rest.length / 2 && CONTENT.test(rest.slice(next))) tailStart += rest[next] === '/' ? next : next + 1;
204
255
  }
205
256
  const tail = s.slice(tailStart);
206
- let head = s.slice(0, Math.max(1, budget - tail.length));
257
+ let head = s.slice(0, Math.min(headEnd, Math.max(1, budget - tail.length)));
207
258
  const cut = Math.max(head.lastIndexOf(' '), head.lastIndexOf('/'));
208
259
  if (cut >= head.length * 0.6) head = head.slice(0, head[cut] === '/' ? cut + 1 : cut);
209
260
  return joinCut(head, tail);
210
261
  }
211
262
 
212
- /** `head…tail`, one "…": a shortened token's own "…" beside the cut is dropped ("…/…/x.js" read as two cuts). */
263
+ /**
264
+ * "…ender-events.browser.mjs": the last `max` chars, from a token boundary when one is near. One "…":
265
+ * a "…" the text already has in that tail goes with the cut ("…--test …/x.js" reads "…/x.js"). A text
266
+ * that ends on its own "…" (a clipped query) has no tail to keep: its head stays (middleEllipsis); one
267
+ * that starts and ends on one ("…words…") loses the end's.
268
+ */
269
+ export function headEllipsis(text, max) {
270
+ let s = str(text);
271
+ if (s.length <= max) return s;
272
+ if (END_CUT.test(s)) {
273
+ if (CONTENT.test(s.slice(0, s.indexOf('…')))) return middleEllipsis(s, max, Math.min(8, max - 1));
274
+ s = s.replace(/…[^\p{L}\p{N}]*$/u, m => m.replace(/…/g, ''));
275
+ if (s.length <= max) return s;
276
+ }
277
+ let tail = s.slice(s.length - Math.max(8, max - 1));
278
+ const own = tail.lastIndexOf('…'); // followed by a word: the text no longer ends on one
279
+ if (own >= 0) return joinCut('', tail.slice(own));
280
+ const cut = tail.search(/[\s/]/);
281
+ // A fragment of a word before the first boundary goes too, when that keeps half the tail ("…c.mjs", never "…ker-stage.mjs c.mjs").
282
+ const inWord = !/[\s/]/.test(s[s.length - tail.length - 1] ?? ' ');
283
+ if (inWord && cut > 0 && cut <= tail.length / 2 && CONTENT.test(tail.slice(cut))) tail = tail.slice(tail[cut] === '/' ? cut : cut + 1);
284
+ return joinCut('', tail);
285
+ }
286
+
287
+ /** `head…tail`, one "…": a shortened token's own "…" beside the cut is dropped ("…/…/x.js" read as two cuts), and so is the space next to it. */
213
288
  export function joinCut(head, tail) {
214
289
  const h = str(head).trimEnd().replace(/\/?…\/?$/, '').trimEnd();
215
- const t = str(tail).trimStart().replace(/^\/?…/, '');
290
+ const t = str(tail).trimStart().replace(/^\/?…/, '').trimStart();
216
291
  return `${h}…${t}`;
217
292
  }
218
293
 
294
+ // A URL or a path in a subject wraps at its separators, never mid-word (wrapRuns).
295
+ const URL_START = /^[a-z][a-z0-9+.-]*:\/\//i;
296
+ const HOST_OR_FILE = /^[\p{L}\p{N}_~@%+…-]+(?:\.[\p{L}\p{N}_~@%+…-]+)+(?::\d+(?:[-:]\d+)?)?$/u; // a file may end on its lines, ":131-191"
297
+ const TOKEN_LEAD = /^[("'“‘[<{]+/;
298
+ const TOKEN_TRAIL = /[)"'”’\]>},;:!?.]+$/;
299
+ const PATH_MIN = 12; // a shorter token wraps whole, as a word does
300
+ const LONG_PIECE = 20; // a longer segment also breaks inside it
301
+ const MIN_PIECE = 3; // "~/", "…/", "./" stay with the piece after them
302
+
303
+ function isPathToken(tok) {
304
+ if (tok.length < PATH_MIN || !CONTENT.test(tok)) return false;
305
+ return URL_START.test(tok) || /[/\\]/.test(tok) || HOST_OR_FILE.test(tok);
306
+ }
307
+
308
+ /**
309
+ * A URL or path as the pieces a line may break between: after "/" (a run of
310
+ * slashes, "https://", stays whole); in a segment over LONG_PIECE chars, also
311
+ * before "?" or "#" and after "-", "_", "=" or "&" when a letter follows, and
312
+ * before "." only in a piece still that long ("queue.browser.mjs" keeps its
313
+ * extension). A piece under MIN_PIECE chars, and a scheme ("https://"), joins
314
+ * its neighbour. The pieces join to `tok`.
315
+ */
316
+ export function pathPieces(tok) {
317
+ const s = str(tok);
318
+ const long = (p) => p.replace(/[/\\]+$/, '').length > LONG_PIECE;
319
+ const pieces = [];
320
+ for (const part of s.match(/[^/\\]*[/\\]+|[^/\\]+$/g) || [s]) {
321
+ if (!long(part)) { pieces.push(part); continue; }
322
+ for (const p of part.split(/(?=[?#])|(?<=[-_=&])(?=\p{L})/u).filter(Boolean)) pieces.push(...(long(p) ? p.split(/(?=\.)/).filter(Boolean) : [p]));
323
+ }
324
+ const leans = (p) => p.length < MIN_PIECE || /^[a-z][a-z0-9+.-]*:\/+$/i.test(p);
325
+ const out = [];
326
+ for (const piece of pieces) {
327
+ if (out.length && (leans(out[out.length - 1]) || piece.length < MIN_PIECE)) out[out.length - 1] += piece;
328
+ else out.push(piece);
329
+ }
330
+ return out;
331
+ }
332
+
333
+ /**
334
+ * Where a bubble subject may wrap: its URL and path tokens (a scheme, a slash,
335
+ * or a dotted host or file name, PATH_MIN chars or more; quotes, brackets and
336
+ * the sentence's punctuation around them left out) as `{ text, pieces }` that
337
+ * break only between their pieces (pathPieces); the rest as `{ text }`, which
338
+ * wraps as any text does. The runs' texts join to `text`.
339
+ */
340
+ export function wrapRuns(text) {
341
+ const s = str(text);
342
+ const runs = [];
343
+ let at = 0;
344
+ for (const m of s.matchAll(/\S+/g)) {
345
+ const lead = m[0].match(TOKEN_LEAD)?.[0] || '';
346
+ const rest = m[0].slice(lead.length);
347
+ const core = rest.slice(0, rest.length - (rest.match(TOKEN_TRAIL)?.[0].length || 0));
348
+ if (!isPathToken(core)) continue;
349
+ const start = m.index + lead.length;
350
+ if (start > at) runs.push({ text: s.slice(at, start) });
351
+ runs.push({ text: core, pieces: pathPieces(core) });
352
+ at = start + core.length;
353
+ }
354
+ if (at < s.length) runs.push({ text: s.slice(at) });
355
+ return runs;
356
+ }
357
+
219
358
  /** A path's last two folders and its basename: `shared/assistant/asst-render.js`. */
220
359
  export function splitPath(path) {
221
360
  const clean = str(path).replace(/\\/g, '/').replace(/\/+$/, '');
@@ -274,14 +413,39 @@ export function commandCore(cmd) {
274
413
  return s;
275
414
  }
276
415
 
416
+ /** A path token's file name with what wraps it: `--config=` or a quote before, `;` or a quote after it. */
417
+ function fileNameOf(tok) {
418
+ const lead = tok.match(/^(?:[^/\\=]*=)?["'(]*/)[0];
419
+ const rest = tok.slice(lead.length);
420
+ const trail = rest.match(/[)"'\];,]*$/)[0];
421
+ const path = rest.slice(0, rest.length - trail.length);
422
+ const base = path.replace(/[/\\]+$/, '').split(/[/\\]/).pop();
423
+ return base ? { lead, base: `${base}${/[/\\]$/.test(path) ? '/' : ''}`, trail } : null;
424
+ }
425
+
277
426
  /**
278
427
  * The command a bubble says: its core (commandCore), the home directory shown
279
428
  * as ~/, whitespace collapsed and tokens over 28 chars cut in the middle.
429
+ * `oneCut` (the stage bubble): one "…" at most, however many paths it shortens.
430
+ * The first path over 28 chars spends it on its dropped folders; a later one
431
+ * keeps its file name, unmarked ("…/a.mjs b.mjs c.mjs"); every other token
432
+ * (a bare file name, a flag) stays whole. A "…" of the command's own counts.
280
433
  */
281
- export function summarizeCommand(cmd) {
434
+ export function summarizeCommand(cmd, { oneCut = false } = {}) {
282
435
  let s = commandCore(cmd);
283
436
  s = s.replace(HOME_RE, '$1~').replace(/(^|[\s"'=:(])\$HOME(?=\/|$|[\s"'])/g, '$1~');
284
- return s.split(' ').map(tok => shortenToken(tok, 28)).join(' ');
437
+ if (!oneCut) return s.split(' ').map(tok => shortenToken(tok, 28)).join(' ');
438
+ let spent = s.includes('…');
439
+ return s.split(' ').map((tok) => {
440
+ if (tok.length <= 28 || !/[/\\]/.test(tok)) return tok;
441
+ const file = fileNameOf(tok);
442
+ if (!file) return tok;
443
+ if (spent) return `${file.lead}${file.base}${file.trail}`;
444
+ spent = true;
445
+ const short = shortenToken(tok, 28);
446
+ if (short.includes('…/')) return short;
447
+ return `${file.lead}…${tok.includes('/') ? '/' : '\\'}${file.base}${file.trail}`; // never a file name cut in its middle
448
+ }).join(' ');
285
449
  }
286
450
 
287
451
  /** The command a shell call ran: `command` or `cmd`, as a string (Codex sends argv arrays). */
@@ -596,6 +760,7 @@ export function urlSubject(url) {
596
760
  /**
597
761
  * The bubble for one call: { verb, text, detail?, mono, segments?, meta[], caption, copy, tag }.
598
762
  * `detail` (computer calls) is what the call's own row shows when it differs from the bubble's subject.
763
+ * `stage` (commands) is the stage bubble's subject: `text` with one "…" at most (summarizeCommand `oneCut`).
599
764
  * `call`: { name, kind, input, result, state, memories?, app? }.
600
765
  * `ctx`: { t, runLabel(call), runState(call), describeComputer(input, name) }.
601
766
  */
@@ -614,6 +779,7 @@ export function sayCall(call, ctx = {}) {
614
779
  out.verb = 'run';
615
780
  out.text = `$ ${summarizeCommand(cmd)}`;
616
781
  out.full = `$ ${str(cmd).replace(/\s+/g, ' ').trim()}`; // the literal line: the title and the opened bubble
782
+ if (cmd.trim()) out.stage = `$ ${summarizeCommand(cmd, { oneCut: true })}`; // the stage bubble's: one "…" at most
617
783
  out.mono = true;
618
784
  out.copy = cmd;
619
785
  out.caption = firstString(input.description);
@@ -765,7 +931,7 @@ export function sayCall(call, ctx = {}) {
765
931
  case 'think': {
766
932
  out.verb = 'think';
767
933
  const text = str(call?.text).replace(/\s+/g, ' ').trim();
768
- out.text = text ? (text.length > 80 ? `…${text.slice(-79)}` : text) : '…';
934
+ out.text = text ? headEllipsis(text, 80) : '…'; // the tail: one "…", a "…" of the thought's own in it goes with the cut
769
935
  out.muted = true;
770
936
  break;
771
937
  }
@@ -807,7 +973,8 @@ export function targetKey(call) {
807
973
 
808
974
  /**
809
975
  * The subject parallel calls of one kind share: "a.js, b.js +1" for reads and
810
- * edits, "$ npm test +1" for commands; "server.js ×2" for a re-read.
976
+ * edits, "$ npm test +1" for commands (one "…" at most, as the stage says a
977
+ * command); "server.js ×2" for a re-read.
811
978
  * `calls`: the calls running side by side (the bubble's own call last);
812
979
  * `all`: every call of the row (for re-reads). Empty when one subject says it.
813
980
  */
@@ -825,7 +992,7 @@ export function groupSubject(kind, calls, all = calls) {
825
992
  if (list.length >= 2) {
826
993
  if (kind === 'shell') {
827
994
  const cmd = commandOf(list[list.length - 1].input);
828
- return cmd ? `$ ${summarizeCommand(cmd)} +${list.length - 1}` : '';
995
+ return cmd ? `$ ${summarizeCommand(cmd, { oneCut: true })} +${list.length - 1}` : '';
829
996
  }
830
997
  const names = [...new Set(list.map(nameOf).filter(Boolean))];
831
998
  if (names.length >= 2) return `${names[0]}, ${names[1]}${names.length > 2 ? ` +${names.length - 2}` : ''}`;
@@ -13,6 +13,7 @@ const REASONS = {
13
13
  'codex-no-records': ['reason.codex-no-records', 'Codex ended without final usage records.'],
14
14
  'codex-rollout-missing': ['reason.codex-rollout-missing', "Codex usage records were missing; the turn's own totals were used."],
15
15
  'opencode-not-reconciled': ['reason.opencode-not-reconciled', "OpenCode's final message check did not finish."],
16
+ 'antigravity-total-mismatch': ['reason.antigravity-total-mismatch', "Antigravity's token total did not match its token classes; the classes were counted as reported."],
16
17
  interrupted: ['reason.interrupted', 'A turn was interrupted; the call it cut off is counted from the stream.'],
17
18
  'no-result': ['reason.no-result', 'A run ended mid-turn; its last calls are counted from the stream.'],
18
19
  };
@@ -34,7 +35,7 @@ const node = (tag, cls, value) => {
34
35
  };
35
36
  const valid = (n) => Number.isSafeInteger(n) && n >= 0;
36
37
  const safe = (n) => (valid(n) ? n : 0);
37
- const providerName = (id) => ['claude-code', 'codex', 'opencode'].includes(id) ? getProviderMeta(id).label : id === 'jev' ? 'Jev' : String(id || '');
38
+ const providerName = (id) => ['claude-code', 'codex', 'opencode'].includes(id) ? getProviderMeta(id).label : id === 'antigravity' ? 'Antigravity' : id === 'jev' ? 'Jev' : String(id || '');
38
39
  const defaultTr = (_, fallback, params) => String(fallback).replace(/\{(\w+)\}/g, (_m, key) => params?.[key] ?? `{${key}}`);
39
40
  export const formatExactTokens = (n) => new Intl.NumberFormat('en-US', { maximumFractionDigits: 0 }).format(valid(n) ? n : 0);
40
41
  export function formatCompactTokens(n) {
@@ -59,14 +59,17 @@ export function claudeAutomationSupportsOneMillion(model) {
59
59
  return !/(haiku|claude-3|opus-4-[0-5](?:-|$)|opus-4-\d{8}|opus-4$)/.test(id);
60
60
  }
61
61
 
62
+ // `size` is the window as a short label ("272K"), '' when unknown: a page that words the choice in
63
+ // another language puts it in its own sentence (the Schedules window).
62
64
  export function automationContextOptions(profile, modelId, models = []) {
63
65
  const id = normalizeAutomationSelection(profile, modelId).model;
64
66
  const model = models.find((entry) => entry?.id === id);
65
67
  const baseSize = contextSizeLabel(model?.contextWindow);
66
- const options = [{ id: 'default', label: baseSize ? `Default (${baseSize})` : 'Provider default' }];
68
+ const options = [{ id: 'default', label: baseSize ? `Default (${baseSize})` : 'Provider default', size: baseSize }];
67
69
  if (profile === 'codex' && model?.supportsExtendedContext === true
68
70
  && Number(model.maxContextWindow) > Number(model.contextWindow)) {
69
- options.push({ id: 'extended', label: `Extended (${contextSizeLabel(model.maxContextWindow)})` });
71
+ const size = contextSizeLabel(model.maxContextWindow);
72
+ options.push({ id: 'extended', label: `Extended (${size})`, size });
70
73
  } else if (profile === 'claude-code'
71
74
  && (models.some((entry) => entry?.id === `${id}[1m]`) || claudeAutomationSupportsOneMillion(model))) {
72
75
  options.push({ id: '1m', label: '1M' });
@@ -25,6 +25,8 @@
25
25
  // closes and moves on, the choice as it was. An open menu is placed `fixed` against its trigger,
26
26
  // so a scrolling pane never cuts it off, and kept inside the box that clips it (a window).
27
27
 
28
+ import { placementArea } from './app-frame.js';
29
+
28
30
  const ARROW = '<svg class="cc-dropdown-arrow" viewBox="0 0 24 24" aria-hidden="true"><polyline points="6 9 12 15 18 9"/></svg>';
29
31
  const GAP = 4; // between the trigger and its menu
30
32
  const EDGE = 6; // the least room left between a menu and the edge of what clips it
@@ -94,13 +96,39 @@ export function matchIndex(options, typed, from = -1) {
94
96
  return -1;
95
97
  }
96
98
 
99
+ /** Multi-choice values in menu order. Disabled selected rows are mandatory. */
100
+ export function multipleValues(options) {
101
+ const exclusive = options.find(o => o.selected && o.exclusive && !o.scope);
102
+ if (exclusive) return [String(exclusive.value ?? '')];
103
+ const scoped = new Set(options.filter(o => o.selected && o.exclusive && o.scope).map(o => o.scope));
104
+ return options.filter(o => o.selected && (!scoped.has(o.scope) || o.exclusive)).map(o => String(o.value ?? ''));
105
+ }
106
+
107
+ /** Exclusive rows may apply globally (inheritance) or within a named section. */
108
+ export function toggleMultiple(options, values, index) {
109
+ const option = options[index];
110
+ if (!option || option.disabled) return [...values];
111
+ if (option.exclusive && !option.scope) return [String(option.value ?? '')];
112
+ const selected = new Set(values);
113
+ for (const row of options) {
114
+ if ((row.exclusive && !row.scope) || (option.exclusive && row.scope === option.scope) || (!option.exclusive && row.exclusive && row.scope === option.scope)) selected.delete(String(row.value ?? ''));
115
+ }
116
+ const value = String(option.value ?? '');
117
+ if (option.exclusive) selected.add(value);
118
+ else if (selected.has(value)) selected.delete(value); else selected.add(value);
119
+ return multipleValues(options.map(row => ({ ...row, selected: selected.has(String(row.value ?? '')) || (!option.exclusive && row.disabled && row.selected) })));
120
+ }
121
+
122
+ const multipleText = (options, values) => options.filter(o => values.includes(String(o.value ?? '')))
123
+ .map(o => o.label).join(', ');
124
+
97
125
  // ── Markup ──
98
126
 
99
127
  function optionHTML(id, option, index, chosen) {
100
128
  const label = String(option.label ?? '');
101
- const active = index === chosen;
129
+ const active = Array.isArray(chosen) ? (chosen.includes(String(option.value ?? '')) || (option.automatic && option.selected)) : index === chosen;
102
130
  return `<div class="cc-dropdown-item${active ? ' active' : ''}" id="${esc(id)}-opt-${index}" role="option" aria-selected="${active}"`
103
- + `${option.disabled ? ' aria-disabled="true"' : ''} data-value="${esc(option.value ?? '')}" data-index="${index}" title="${esc(label)}">${esc(label)}</div>`;
131
+ + `${option.disabled ? ' aria-disabled="true"' : ''} data-value="${esc(option.value ?? '')}" data-index="${index}"${option.exclusive ? ' data-exclusive="true"' : ''}${option.scope ? ` data-scope="${esc(option.scope)}"` : ''}${option.automatic ? ' data-automatic="true"' : ''} data-label="${esc(label)}" title="${esc(option.caption || label)}">${Array.isArray(chosen) ? '<span class="cc-dropdown-check" aria-hidden="true"></span>' : ''}<span>${esc(label)}${option.caption ? `<small class="cc-dropdown-caption">${esc(option.caption)}</small>` : ''}</span></div>`;
104
132
  }
105
133
 
106
134
  /** The menu's options (and headings) for `entries`, the `chosen` index marked. */
@@ -120,17 +148,17 @@ export function menuHTML(id, entries, chosen = chosenIndex(flatOptions(entries))
120
148
  * Name it with `labelledBy` (the id of its visible label) or `label`. `classes` and `attrs` go on
121
149
  * the `.cc-dropdown`.
122
150
  */
123
- export function dropdownHTML(id, entries, { classes = '', labelledBy = '', label = '', attrs = '', inputAttrs = '', disabled = false } = {}) {
151
+ export function dropdownHTML(id, entries, { classes = '', labelledBy = '', label = '', attrs = '', inputAttrs = '', disabled = false, multiple = false, summary = '' } = {}) {
124
152
  const options = flatOptions(entries);
125
- const chosen = chosenIndex(options);
153
+ const chosen = multiple ? multipleValues(options) : chosenIndex(options);
126
154
  const current = chosen >= 0 ? options[chosen] : null;
127
155
  const name = labelledBy ? ` aria-labelledby="${esc(labelledBy)}"` : label ? ` aria-label="${esc(label)}"` : '';
128
- const text = String(current?.label ?? '');
129
- return `<input type="hidden" id="${esc(id)}" value="${esc(current?.value ?? '')}"${disabled ? ' disabled' : ''}${inputAttrs ? ` ${inputAttrs}` : ''}>`
130
- + `<div class="cc-dropdown${classes ? ` ${classes}` : ''}${disabled ? ' disabled' : ''}" data-for="${esc(id)}"${attrs ? ` ${attrs}` : ''}>`
156
+ const text = multiple ? (summary || multipleText(options, chosen)) : String(current?.label ?? '');
157
+ return `<input type="hidden" id="${esc(id)}" value="${esc(multiple ? chosen.join(',') : current?.value ?? '')}"${disabled ? ' disabled' : ''}${inputAttrs ? ` ${inputAttrs}` : ''}>`
158
+ + `<div class="cc-dropdown${classes ? ` ${classes}` : ''}${disabled ? ' disabled' : ''}" data-for="${esc(id)}"${multiple ? ' data-multiple="true"' : ''}${attrs ? ` ${attrs}` : ''}>`
131
159
  + `<button type="button" class="cc-dropdown-trigger" id="${esc(id)}-trigger" role="combobox" aria-haspopup="listbox" aria-expanded="false" aria-controls="${esc(id)}-menu"${name}${disabled ? ' disabled' : ''}>`
132
160
  + `<span class="cc-dropdown-value" title="${esc(text)}">${esc(text)}</span>${ARROW}</button>`
133
- + `<div class="cc-dropdown-menu" id="${esc(id)}-menu" role="listbox"${name} tabindex="-1">${menuHTML(id, entries, chosen)}</div>`
161
+ + `<div class="cc-dropdown-menu" id="${esc(id)}-menu" role="listbox"${multiple ? ' aria-multiselectable="true"' : ''}${name} tabindex="-1">${menuHTML(id, entries, chosen)}</div>`
134
162
  + '</div>';
135
163
  }
136
164
 
@@ -143,7 +171,7 @@ const partsOf = (dd) => ({
143
171
  input: dd.dataset.for ? document.getElementById(dd.dataset.for) : null,
144
172
  });
145
173
  const itemsOf = (dd) => [...(partsOf(dd).menu?.querySelectorAll('.cc-dropdown-item') || [])];
146
- const optionsOf = (items) => items.map(el => ({ value: el.dataset.value ?? '', label: el.textContent, disabled: el.getAttribute('aria-disabled') === 'true' }));
174
+ const optionsOf = (items) => items.map(el => ({ value: el.dataset.value ?? '', label: el.dataset.label ?? el.textContent, disabled: el.getAttribute('aria-disabled') === 'true', exclusive: el.dataset.exclusive === 'true', scope: el.dataset.scope || undefined, selected: el.classList.contains('active') }));
147
175
  const highlightedOf = (items) => items.findIndex(el => el.classList.contains('highlight'));
148
176
  const chosenOf = (items) => items.findIndex(el => el.classList.contains('active'));
149
177
  const isOpen = (dd) => !!dd?.classList.contains('open');
@@ -194,6 +222,21 @@ function showChosen(dd, index) {
194
222
  }
195
223
  }
196
224
 
225
+ function showMultiple(dd, values) {
226
+ const { label, input } = partsOf(dd);
227
+ const items = itemsOf(dd);
228
+ items.forEach(el => {
229
+ const active = values.includes(el.dataset.value ?? '') || el.dataset.automatic === 'true';
230
+ el.classList.toggle('active', active);
231
+ el.setAttribute('aria-selected', String(active));
232
+ });
233
+ if (input) input.value = values.join(',');
234
+ if (label) {
235
+ label.textContent = multipleText(optionsOf(items), values);
236
+ label.title = label.textContent;
237
+ }
238
+ }
239
+
197
240
  function highlight(dd, index) {
198
241
  const { trigger, menu } = partsOf(dd);
199
242
  const items = itemsOf(dd);
@@ -227,7 +270,9 @@ function place(dd) {
227
270
  Object.assign(style, { position: 'fixed', left: '0px', top: '0px', right: 'auto', bottom: 'auto', width: 'auto', maxHeight: 'none', minWidth: '0px', maxWidth: 'none' });
228
271
  const origin = menu.getBoundingClientRect(); // where the containing block's (0, 0) is on screen
229
272
  const t = trigger.getBoundingClientRect();
230
- let room = { left: 0, top: 0, right: window.innerWidth, bottom: window.innerHeight };
273
+ // The app frame for a trigger inside it (app-frame.js), else the window; then whatever clips the menu
274
+ const area = placementArea(t.left + t.width / 2, t.top + t.height / 2);
275
+ let room = { left: area.left, top: area.top, right: area.right, bottom: area.bottom };
231
276
  const box = fixedContainer(dd);
232
277
  if (box) {
233
278
  const cs = getComputedStyle(box);
@@ -268,8 +313,12 @@ function open(dd, index = null) {
268
313
  if (!trigger || trigger.disabled || dd.classList.contains('disabled')) return;
269
314
  for (const other of document.querySelectorAll('.cc-dropdown.open')) if (other !== dd) close(other);
270
315
  ensureAria(dd);
316
+ dd._ccBefore = partsOf(dd).input?.value;
317
+ dd._ccBeforeLabel = partsOf(dd).label?.textContent;
318
+ dd._ccBeforeMenu = partsOf(dd).menu?.innerHTML;
271
319
  dd.classList.add('open');
272
320
  trigger.setAttribute('aria-expanded', 'true');
321
+ partsOf(dd).input?.dispatchEvent(new Event('cc-dropdown-open', { bubbles: true }));
273
322
  if (document.activeElement !== trigger) trigger.focus({ preventScroll: true });
274
323
  place(dd);
275
324
  const items = itemsOf(dd);
@@ -278,8 +327,14 @@ function open(dd, index = null) {
278
327
  highlight(dd, index ?? (chosen >= 0 && !options[chosen].disabled ? chosen : edgeIndex(options, 'first')));
279
328
  }
280
329
 
281
- function close(dd, { focus = false } = {}) {
282
- const { trigger, menu } = partsOf(dd);
330
+ function close(dd, { focus = false, cancel = false } = {}) {
331
+ const { trigger, menu, input, label } = partsOf(dd);
332
+ const changed = isOpen(dd) && dd.dataset.multiple === 'true' && input && input.value !== dd._ccBefore;
333
+ if (cancel && changed) {
334
+ if (menu && dd._ccBeforeMenu != null) menu.innerHTML = dd._ccBeforeMenu;
335
+ showMultiple(dd, dd._ccBefore === '' ? [''] : dd._ccBefore.split(','));
336
+ if (label) { label.textContent = dd._ccBeforeLabel; label.title = label.textContent; }
337
+ }
283
338
  dd.classList.remove('open', 'drop-up');
284
339
  trigger?.setAttribute('aria-expanded', 'false');
285
340
  trigger?.removeAttribute('aria-activedescendant');
@@ -287,6 +342,10 @@ function close(dd, { focus = false } = {}) {
287
342
  menu?.removeAttribute('style');
288
343
  dd._ccPlacedAt = null;
289
344
  if (focus && trigger?.isConnected) trigger.focus({ preventScroll: true });
345
+ if (changed && !cancel) {
346
+ input.dispatchEvent(new Event('input', { bubbles: true }));
347
+ input.dispatchEvent(new Event('change', { bubbles: true }));
348
+ }
290
349
  }
291
350
 
292
351
  /** The user's choice: shown, the menu closed, the focus on the trigger, then `input` and `change` when it changed. */
@@ -295,6 +354,12 @@ function choose(dd, index) {
295
354
  const item = items[index];
296
355
  const { input } = partsOf(dd);
297
356
  if (!item || item.getAttribute('aria-disabled') === 'true') { close(dd, { focus: true }); return; }
357
+ if (dd.dataset.multiple === 'true') {
358
+ showMultiple(dd, toggleMultiple(optionsOf(items), items.filter(el => el.classList.contains('active')).map(el => el.dataset.value), index));
359
+ input?.dispatchEvent(new Event('cc-dropdown-draft', { bubbles: true }));
360
+ highlight(dd, index);
361
+ return;
362
+ }
298
363
  const changed = !!input && input.value !== (item.dataset.value ?? '');
299
364
  showChosen(dd, index);
300
365
  close(dd, { focus: true });
@@ -315,20 +380,25 @@ export function setDropdownItems(input, entries) {
315
380
  const wasOpen = isOpen(dd);
316
381
  const before = wasOpen ? itemsOf(dd)[highlightedOf(itemsOf(dd))]?.dataset.value : undefined;
317
382
  const options = flatOptions(entries);
318
- const chosen = chosenIndex(options);
383
+ const multiple = dd.dataset.multiple === 'true';
384
+ const chosen = multiple ? multipleValues(options) : chosenIndex(options);
319
385
  menu.innerHTML = menuHTML(input.id, entries, chosen);
320
- showChosen(dd, chosen);
386
+ if (multiple) showMultiple(dd, chosen); else showChosen(dd, chosen);
321
387
  if (!wasOpen) return;
322
388
  place(dd);
323
389
  const items = itemsOf(dd);
324
390
  const again = before === undefined ? -1 : items.findIndex(el => el.dataset.value === before);
325
- highlight(dd, again >= 0 ? again : chosen);
391
+ highlight(dd, again >= 0 ? again : chosenOf(items));
326
392
  }
327
393
 
328
394
  /** `select.value = …`: the first choice with that value, or none (the value is then ''). No event. */
329
395
  export function setDropdownValue(input, value) {
330
396
  const dd = dropdownOf(input);
331
397
  if (!dd) { if (input) input.value = value ?? ''; return; }
398
+ if (dd.dataset.multiple === 'true') {
399
+ showMultiple(dd, Array.isArray(value) ? value.map(String) : String(value ?? '').split(','));
400
+ return;
401
+ }
332
402
  showChosen(dd, itemsOf(dd).findIndex(el => el.dataset.value === String(value ?? '')));
333
403
  }
334
404
 
@@ -337,16 +407,16 @@ export function setDropdownDisabled(input, disabled) {
337
407
  const dd = dropdownOf(input);
338
408
  if (input) input.disabled = !!disabled;
339
409
  if (!dd) return;
340
- if (disabled && isOpen(dd)) close(dd);
410
+ if (disabled && isOpen(dd)) close(dd, { cancel: true });
341
411
  dd.classList.toggle('disabled', !!disabled);
342
412
  const { trigger } = partsOf(dd);
343
413
  if (trigger) trigger.disabled = !!disabled;
344
414
  }
345
415
 
346
416
  /** Closes every open dropdown under `root`; true when one was open. `focus` puts the focus back on its trigger. */
347
- export function closeDropdowns(root = document, { focus = false } = {}) {
417
+ export function closeDropdowns(root = document, { focus = false, cancel = false } = {}) {
348
418
  const open = [...root.querySelectorAll('.cc-dropdown.open')];
349
- for (const dd of open) close(dd, { focus });
419
+ for (const dd of open) close(dd, { focus, cancel });
350
420
  return open.length > 0;
351
421
  }
352
422
 
@@ -446,7 +516,7 @@ export function wireDropdowns(root, { signal } = {}) {
446
516
  case 'Escape':
447
517
  e.preventDefault();
448
518
  e.stopPropagation();
449
- close(dd, { focus: true });
519
+ close(dd, { focus: true, cancel: true });
450
520
  break;
451
521
  case 'Tab':
452
522
  close(dd); // the focus moves on as usual; the choice stays as it was
@@ -164,6 +164,7 @@ function build(m, { copied = false } = {}) {
164
164
  * opts.onManage() opens the MCP servers; without it there is no "Manage"
165
165
  * opts.onSettings() opens Codex settings; without it there is no "Settings"
166
166
  * opts.onAccount() opens the account menu; without it there is no Account row
167
+ * opts.bounds() the area the popover stays in ({ left, top, right, bottom }: the app frame); the window without it
167
168
  * Returns { element, open(), close({ focus }), isOpen(), sync(), destroy() }.
168
169
  */
169
170
  export function mountContextMenu(actionsEl, panelEl, opts = {}) {
@@ -215,23 +216,23 @@ export function mountContextMenu(actionsEl, panelEl, opts = {}) {
215
216
  }
216
217
 
217
218
  // Below the cog, its right edge on the cog's; above it when there is more room
218
- // there; always inside the viewport, scrolling inside when it is taller.
219
+ // there; always inside the app frame, scrolling inside when it is taller.
219
220
  function place() {
220
221
  if (!open || !pop) return;
221
222
  const r = cog.getBoundingClientRect();
222
- const vw = window.innerWidth;
223
- const vh = window.innerHeight;
224
- const width = Math.max(0, Math.min(WIDTH, vw - MARGIN * 2));
223
+ // Inside the area the panel names (the app frame), else the window
224
+ const f = opts.bounds?.() || { left: 0, top: 0, right: window.innerWidth, bottom: window.innerHeight, width: window.innerWidth };
225
+ const width = Math.max(0, Math.min(WIDTH, f.width - MARGIN * 2));
225
226
  pop.style.width = `${width}px`;
226
- const below = vh - r.bottom - GAP - MARGIN;
227
- const above = r.top - GAP - MARGIN;
227
+ const below = f.bottom - r.bottom - GAP - MARGIN;
228
+ const above = r.top - f.top - GAP - MARGIN;
228
229
  const up = below < 220 && above > below;
229
230
  pop.style.maxHeight = `${Math.max(120, up ? above : below)}px`;
230
231
  const height = pop.offsetHeight;
231
- const left = Math.max(MARGIN, Math.min(r.right - width, vw - width - MARGIN));
232
+ const left = Math.max(f.left + MARGIN, Math.min(r.right - width, f.right - width - MARGIN));
232
233
  const top = up
233
- ? Math.max(MARGIN, r.top - GAP - height)
234
- : Math.max(MARGIN, Math.min(r.bottom + GAP, vh - MARGIN - height));
234
+ ? Math.max(f.top + MARGIN, r.top - GAP - height)
235
+ : Math.max(f.top + MARGIN, Math.min(r.bottom + GAP, f.bottom - MARGIN - height));
235
236
  pop.style.left = `${Math.round(left)}px`;
236
237
  pop.style.top = `${Math.round(top)}px`;
237
238
  // Once it has its width: only now is a cut value known.
@@ -0,0 +1,16 @@
1
+ let translate = null;
2
+ export function setCodexTranslator(fn) { translate = typeof fn === 'function' ? fn : null; }
3
+
4
+ // Detached panels/tests can render before the locale bundle is ready.
5
+ export function cxpText(key, english, params) {
6
+ const path = `codexPanel.${key}`;
7
+ const value = translate?.(path, params) || path;
8
+ if (value !== path) return value;
9
+ return english.replace(/\{(\w+)\}/g, (_, name) => params?.[name] ?? `{${name}}`);
10
+ }
11
+
12
+ export function cxpSessionLabel(label) {
13
+ if (label === 'New session') return cxpText('newSession', 'New session');
14
+ if (label === 'Saved session') return cxpText('savedSession', 'Saved session');
15
+ return label;
16
+ }