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
@@ -0,0 +1,29 @@
1
+ // String caches need a size budget as well as an entry count: streaming
2
+ // revisions are different keys and may each hold a nearly complete transcript.
3
+ export function createTextCache({ maxEntries = 512, maxChars = 1_000_000, maxEntryChars = 64_000 } = {}) {
4
+ const entries = new Map();
5
+ let chars = 0;
6
+ const drop = key => {
7
+ const value = entries.get(key);
8
+ if (value === undefined) return;
9
+ chars -= key.length + value.length;
10
+ entries.delete(key);
11
+ };
12
+ return {
13
+ get(key) {
14
+ const value = entries.get(key);
15
+ if (value !== undefined) { entries.delete(key); entries.set(key, value); }
16
+ return value;
17
+ },
18
+ set(key, value) {
19
+ drop(key);
20
+ const size = key.length + value.length;
21
+ if (size > Math.min(maxChars, maxEntryChars) || maxEntries < 1) return;
22
+ while (entries.size && (entries.size >= maxEntries || chars + size > maxChars)) drop(entries.keys().next().value);
23
+ entries.set(key, value);
24
+ chars += size;
25
+ },
26
+ clear() { entries.clear(); chars = 0; },
27
+ stats: () => ({ entries: entries.size, chars }),
28
+ };
29
+ }
@@ -0,0 +1,55 @@
1
+ // Shared cc-dropdown rendering; the pure view owns labels and catalog-derived choices.
2
+ import { dropdownHTML, setDropdownItems, dropdownOf } from './cc-dropdown.js';
3
+ import { toolListView, toolListWord, toolsFromInput, strictToolHost, taskToolHost } from './tool-list-view.js';
4
+ import { getCachedToolCatalog, fetchToolCatalog } from './agent-runtime-options.js';
5
+ let translate;
6
+ export function configureToolPickerTranslation(fn) { if (typeof fn === 'function') translate = fn; }
7
+ export { toolsFromInput, strictToolHost, taskToolHost };
8
+ export const toolWord = (key, params) => toolListWord(key, params, translate);
9
+ export function toolPickerHTML(id, tools, options = {}) {
10
+ const catalog = options.catalog || getCachedToolCatalog(options.cwd);
11
+ if (!catalog) return '';
12
+ const view = toolListView(catalog, tools, { translate, ...options });
13
+ return dropdownHTML(id, view.entries, { multiple: true, label: toolWord('label'), classes: 'tool-list-picker',
14
+ summary: view.summary, ...options, classes: `tool-list-picker ${options.classes || ''}`.trim(), attrs: `data-tool-options="${encodeURIComponent(JSON.stringify({ inheritLabel: options.inheritLabel, usesBrowser: options.usesBrowser, taskClass: options.taskClass, cwd: options.cwd, provider: options.provider, includeServers: options.includeServers, externalSelection: catalog.externalServersVersion >= 2 && options.includeServers !== false && options.provider !== 'antigravity', externalRefs: (tools ?? catalog.defaultTools ?? []).filter(id => id.startsWith('mcp:')) }))}"` });
15
+ }
16
+ export function updateToolPicker(input, tools, options = {}) {
17
+ options = { ...JSON.parse(decodeURIComponent(dropdownOf(input)?.dataset.toolOptions || '%7B%7D')), ...options };
18
+ const catalog = options.catalog || getCachedToolCatalog(options.cwd);
19
+ if (!catalog || !input) return;
20
+ const view = toolListView(catalog, tools, { translate, ...options });
21
+ setDropdownItems(input, view.entries);
22
+ const dd = dropdownOf(input);
23
+ if (dd) dd.dataset.toolOptions = encodeURIComponent(JSON.stringify({ inheritLabel: options.inheritLabel, usesBrowser: options.usesBrowser, taskClass: options.taskClass, cwd: options.cwd, provider: options.provider, includeServers: options.includeServers, externalSelection: catalog.externalServersVersion >= 2 && options.includeServers !== false && options.provider !== 'antigravity', externalRefs: (tools ?? catalog.defaultTools ?? []).filter(id => id.startsWith('mcp:')) }));
24
+ const label = dropdownOf(input)?.querySelector('.cc-dropdown-value');
25
+ if (label) { label.textContent = view.summary; label.title = view.summary; }
26
+ }
27
+ export function readToolPicker(input, options = {}) {
28
+ if (!input) return undefined; // old server: do not invent a selection
29
+ const dd = dropdownOf(input);
30
+ const raw = options.requested ? input.value.split(',').filter(id => ![...(dd?.querySelectorAll('[data-automatic="true"]') || [])].some(row => row.dataset.value === id)).join(',') : input.value;
31
+ const stored = JSON.parse(decodeURIComponent(dd?.dataset.toolOptions || '%7B%7D'));
32
+ const value = toolsFromInput(raw, { ...stored, ...options });
33
+ if (value && !stored.externalSelection && stored.externalRefs?.length) return [...value.filter(id => !id.startsWith('mcp:')), ...stored.externalRefs];
34
+ return value?.filter(id => id !== 'memory') ?? value;
35
+ }
36
+
37
+ // A draft changes check rows/counts immediately; only cc-dropdown's close emits change.
38
+ if (typeof document !== 'undefined') document.addEventListener('cc-dropdown-draft', (event) => {
39
+ const dd = dropdownOf(event.target);
40
+ if (!dd?.classList.contains('tool-list-picker')) return;
41
+ const options = JSON.parse(decodeURIComponent(dd.dataset.toolOptions || '%7B%7D'));
42
+ updateToolPicker(event.target, readToolPicker(event.target, { requested: true }), options);
43
+ });
44
+
45
+ if (typeof document !== 'undefined') document.addEventListener('mcp:servers-changed', () => {
46
+ const pickers = [...document.querySelectorAll('.tool-list-picker')];
47
+ for (const dd of pickers) {
48
+ const input = document.getElementById(dd.dataset.for);
49
+ const options = JSON.parse(decodeURIComponent(dd.dataset.toolOptions || '%7B%7D'));
50
+ const tools = readToolPicker(input, { requested: true });
51
+ fetchToolCatalog(false, { cwd: options.cwd }).then(catalog => {
52
+ if (catalog && input?.isConnected) updateToolPicker(input, tools, { ...options, catalog });
53
+ }).catch(() => {});
54
+ }
55
+ });
@@ -0,0 +1,24 @@
1
+ // Read-only legacy conversion uses the server's one catalog, including custom saved names.
2
+ // Failed conversion leaves the old preference intact so it can be retried after a server update.
3
+ export async function migrateStoredTools(storage, key, legacyKey, { entry, fetcher = globalThis.fetch } = {}) {
4
+ let current;
5
+ try { current = JSON.parse(storage.getItem(key) || 'null'); } catch { current = null; }
6
+ const value = entry == null ? current : current?.[entry];
7
+ if (Array.isArray(value)) return value;
8
+ let old = storage.getItem(legacyKey);
9
+ if (entry != null) { try { old = JSON.parse(old || '{}')[entry]; } catch { old = null; } }
10
+ if (typeof old !== 'string' || !old.trim()) return null;
11
+ try {
12
+ const response = await fetcher('/api/mcp/tools/convert', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ value: old }) });
13
+ const result = await response.json();
14
+ if (!response.ok || !result.ok || !Array.isArray(result.tools)) return null;
15
+ const tools = result.tools;
16
+ // A picker may have saved while the conversion was awaiting its reply; never overwrite it.
17
+ let latest;
18
+ try { latest = JSON.parse(storage.getItem(key) || 'null'); } catch { latest = null; }
19
+ const saved = entry == null ? latest : latest?.[entry];
20
+ if (Array.isArray(saved)) return saved;
21
+ storage.setItem(key, JSON.stringify(entry == null ? tools : { ...latest, [entry]: tools }));
22
+ return tools;
23
+ } catch { return null; }
24
+ }
@@ -0,0 +1,112 @@
1
+ // DOM-free presentation of the server's catalog. No second group/count/preset table.
2
+ export const TOOL_LIST_COPY = Object.freeze({
3
+ label: 'Tools and MCP servers',
4
+ defaultTools: 'Default tools',
5
+ default: 'Default',
6
+ templateDefault: 'Template default',
7
+ noOverride: 'No override',
8
+ all: 'All SynaBun tools',
9
+ alwaysOn: 'Always-on tools',
10
+ count: '{count} tools',
11
+ countOne: '{count} tool',
12
+ browser: 'Browser and social',
13
+ workspace: 'Workspace',
14
+ other: 'Other',
15
+ addedBrowser: 'Added for browser use',
16
+ addedDesign: 'Added for design work',
17
+ focus: 'Loads every SynaBun tool on demand.',
18
+ strict: 'Loads the selected SynaBun groups.',
19
+ future: 'Applies to future runtimes. Running sessions keep their own tools.',
20
+ servers: 'Your other MCP servers',
21
+ allServers: 'All my servers',
22
+ configuredExternally: 'Configured in provider',
23
+ noServers: 'No external servers',
24
+ blockedServer: 'Blocked by Agents may use it',
25
+ unavailableServer: 'Unavailable on this provider',
26
+ agentAccess: 'Agents may use it',
27
+ agentAccessHelp: 'Applies to task workers and automations on Codex, OpenCode and Claude, including FleetView, plus the OpenCode tools picker. Other sessions you drive keep their servers.',
28
+ loadFailed: 'Could not load the tool catalog. Try again.',
29
+ saveFailed: 'Could not save the tool list. Try again.',
30
+ saved: 'Default tools saved.',
31
+ reloadFailed: 'OpenCode could not reload the requested tools.',
32
+ });
33
+
34
+ export function toolListWord(key, params = {}, translate) {
35
+ const full = `toolList.${key}`;
36
+ let translated;
37
+ try { translated = translate?.(full, params); } catch {}
38
+ const text = typeof translated === 'string' && translated !== full ? translated : TOOL_LIST_COPY[key] || key;
39
+ return text.replace(/\{(\w+)\}/g, (whole, name) => params[name] ?? whole);
40
+ }
41
+
42
+ function groupWord(group, field, translate) {
43
+ const key = `toolGroups.${group.id}.${field}`;
44
+ try { const value = translate?.(key); if (typeof value === 'string' && value && value !== key) return value; } catch {}
45
+ return group[field];
46
+ }
47
+
48
+ export const strictToolHost = provider => provider === 'opencode' || provider === 'antigravity';
49
+ export const taskToolHost = provider => strictToolHost(provider) || provider === 'claude-code' || provider === 'codex';
50
+
51
+ /** Hidden-input encoding: inheritance differs from an explicit empty group list. */
52
+ export function toolListInput(tools) {
53
+ return tools == null ? '__inherit__' : tools.join(',');
54
+ }
55
+ export function toolsFromInput(value, { inherit = true, externalSelection = false } = {}) {
56
+ if (value == null || String(value).split(',').includes('__inherit__')) return inherit ? null : (externalSelection ? [] : ['mcp:*']);
57
+ const items = String(value).split(',').filter(id => id && id !== 'memory' && id !== '__no_servers__');
58
+ return [...new Set([...items, ...(!externalSelection && !items.some(id => id.startsWith('mcp:')) ? ['mcp:*'] : [])])];
59
+ }
60
+
61
+ export function toolListView(catalog, tools, { inheritLabel = null, usesBrowser, taskClass,
62
+ provider = 'opencode', translate, includeServers = true } = {}) {
63
+ const word = (key, params) => toolListWord(key, params, translate);
64
+ const inherited = tools == null;
65
+ const source = inherited ? catalog?.defaultTools ?? catalog?.default ?? [] : tools;
66
+ const refs = source.filter(id => id.startsWith('mcp:'));
67
+ const requested = source.filter(id => !id.startsWith('mcp:'));
68
+ const all = requested.includes('all');
69
+ const groups = catalog?.groups || [];
70
+ const chosen = new Set(all ? groups.map(g => g.id) : requested);
71
+ const added = [];
72
+ const add = (id, why) => { if (groups.some(g => g.id === id) && !chosen.has(id)) { chosen.add(id); added.push({ id, why }); } };
73
+ if (usesBrowser || groups.some(g => chosen.has(g.id) && g.browser) || (taskClass === 'design' && usesBrowser !== false)) add('browser', 'addedBrowser');
74
+ if (taskClass === 'design') { add('image', 'addedDesign'); add('styleguide', 'addedDesign'); }
75
+ const entries = [];
76
+ if (inheritLabel) entries.push({ value: '__inherit__', label: inheritLabel, exclusive: true, selected: inherited });
77
+ entries.push({ value: 'all', label: word('all'), caption: catalog?.effect?.[provider] === 'focus' ? word('focus') : null, exclusive: true, scope: 'groups', selected: !inherited && all });
78
+ // A real value for explicit always-on avoids conflating it with the exclusive inheritance row.
79
+ entries.push({ value: 'memory', label: word('alwaysOn'), exclusive: true, scope: 'groups', selected: !inherited && !requested.length });
80
+ for (const section of ['browser', 'workspace', 'other']) {
81
+ const options = groups.filter(g => g.section === section).map(g => {
82
+ const automatic = added.find(a => a.id === g.id);
83
+ return { value: g.id, scope: 'groups', label: `${groupWord(g, 'label', translate)} · ${word(g.count === 1 ? 'countOne' : 'count', { count: g.count })}`,
84
+ caption: automatic ? word(automatic.why) : groupWord(g, 'purpose', translate),
85
+ selected: (!inherited && !all && chosen.has(g.id)) || !!automatic,
86
+ disabled: !!automatic, automatic: !!automatic };
87
+ });
88
+ if (options.length) entries.push({ group: word(section), options });
89
+ }
90
+ if (includeServers && provider !== 'antigravity' && catalog?.externalServersVersion >= 2) {
91
+ const wildcard = refs.includes('mcp:*');
92
+ const rows = (catalog.servers || []).filter(row => row.selectable !== false);
93
+ // A saved unavailable ref stays visible and round-trips; loading a catalog never silently clears it.
94
+ for (const ref of refs) if (ref !== 'mcp:*' && !rows.some(row => row.ref === ref)) rows.push({ ref, label: ref.slice(4), providers: {} });
95
+ const options = [
96
+ { value: 'mcp:*', scope: 'servers', label: word('allServers'), exclusive: true, selected: !inherited && wildcard },
97
+ { value: '__no_servers__', scope: 'servers', label: word('noServers'), exclusive: true, selected: !inherited && !refs.length },
98
+ ...rows.map(row => {
99
+ const availability = row.providers?.[provider];
100
+ const unavailable = provider && provider !== 'all' ? availability !== 'deliverable' : !Object.values(row.providers || {}).includes('deliverable');
101
+ return { value: row.ref, scope: 'servers', label: row.label || row.ref.slice(4), selected: !inherited && !wildcard && refs.includes(row.ref), disabled: row.blocked || unavailable, caption: row.blocked ? word('blockedServer') : unavailable ? word('unavailableServer') : row.ref };
102
+ }),
103
+ ];
104
+ entries.push({ group: word('servers'), options });
105
+ }
106
+ const count = (catalog?.alwaysOn || 0) + groups.filter(g => chosen.has(g.id)).reduce((n, g) => n + g.count, 0);
107
+ const labels = groups.filter(g => chosen.has(g.id)).map(g => groupWord(g, 'label', translate));
108
+ const short = all ? word('all') : labels.length ? `${labels.slice(0, 2).join(', ')}${labels.length > 2 ? ` +${labels.length - 2}` : ''}` : word('alwaysOn');
109
+ const serverLabel = refs.length ? ` · ${refs.includes('mcp:*') ? word('allServers') : refs.map(ref => ref.slice(4)).join(', ')}` : '';
110
+ const summary = `${inherited ? `${inheritLabel || word('default')} · ` : ''}${short} · ${word('count', { count })}${serverLabel}`;
111
+ return { entries, summary, count, added, groups: [...chosen], effect: catalog?.effect?.[provider] || (strictToolHost(provider) ? 'strict' : 'focus') };
112
+ }
@@ -0,0 +1,54 @@
1
+ // The top-right toolbar's overflow, what decides (no DOM, no imports: node --test loads it).
2
+ // The page side is ui-topright-overflow.js.
3
+
4
+ // Lowest priority first: the first entries are the first to leave the row for the ⋯ menu.
5
+ export const OVERFLOW_ORDER = [
6
+ 'topright-keybinds-btn',
7
+ 'invite-overlay',
8
+ 'topright-trash-btn',
9
+ 'topright-bookmarks-btn',
10
+ 'topright-antigravity-panel-btn',
11
+ 'topright-opencode-panel-btn',
12
+ 'topright-file-explorer-btn',
13
+ 'topright-memory-explorer-btn',
14
+ 'topright-codex-panel-btn',
15
+ 'topright-update-btn',
16
+ 'topright-claude-panel-btn',
17
+ 'topright-assistant-panel-btn',
18
+ // the very last resort, a band of about 120 px: the toggle too (its entry in the menu shows and hides the tools)
19
+ 'topright-tools-btn',
20
+ ];
21
+
22
+ /**
23
+ * Which entries of OVERFLOW_ORDER leave the row: the fewest, in order, that bring the row's width within `available`.
24
+ * `total` is the row with everything in it and no ⋯; `widths[i]` what entry i takes in the row (its width and the gap
25
+ * before it; 0 when it is not shown at all, and then never listed); `menuWidth` what the ⋯ adds once anything
26
+ * overflows. Pinned entries never leave.
27
+ */
28
+ export function overflowCount({ total, available, widths, menuWidth, pinned = [] }) {
29
+ if (total <= available) return { count: 0, hidden: [] };
30
+ let need = total + menuWidth;
31
+ const hidden = [];
32
+ for (let i = 0; i < widths.length && need > available; i++) {
33
+ if (pinned.includes(i) || !widths[i]) continue;
34
+ need -= widths[i];
35
+ hidden.push(i);
36
+ }
37
+ return { count: hidden.length, hidden };
38
+ }
39
+
40
+ /**
41
+ * Where a dropdown of the bar (workspaces, bookmarks, share) goes across: kept within [minLeft, maxRight] (the band's
42
+ * clip on the left, which already clears the Focus Mode rail and the left panels; the viewport on the right).
43
+ * `left` / `width` are its box as the stylesheet hangs it. Returns the `shift` (px, + is to the right) and the
44
+ * `maxWidth` it may take (null when it fits as it is). Too wide for the room: as wide as the room, flush with minLeft.
45
+ */
46
+ export function clampDropdownX({ left, width, minLeft, maxRight }) {
47
+ const room = Math.max(0, maxRight - minLeft);
48
+ const w = Math.min(width, room);
49
+ const maxWidth = width > room ? room : null;
50
+ let x = left;
51
+ if (x + w > maxRight) x = maxRight - w;
52
+ if (x < minLeft) x = minLeft;
53
+ return { shift: Math.round(x - left), maxWidth };
54
+ }
@@ -0,0 +1,268 @@
1
+ // The mascot as the tour's narrator: the empty state's real rig, in its real
2
+ // box, moved by transform only. Travel is physical: the box springs toward its
3
+ // place (a hop arc, a small crouch on take-off, a stretch and a lean in flight,
4
+ // a landing with a hint of give), so a new place in mid-flight carries on from
5
+ // where it is, at the speed it has. Every frame the body's change of velocity
6
+ // goes to the rig's arms (rig.nudge): they trail on take-off and wobble on
7
+ // arrival; its change of place goes to rig.shift, so a hand keeps pointing at
8
+ // the same control while the body flies, and the rig measures again once the
9
+ // body is still. Pointing is the rig's own (rig.point: arms + gaze). The
10
+ // mascot's keep-out (what it can draw: mascotBounds, plus a margin) is handed
11
+ // to `onMove` every frame it moves, for the ink layers' hole. Frames come from
12
+ // the shared ticker (the rig's own loop), only while the body moves; rects
13
+ // are read once per move, never per frame. Under reduced motion the box is
14
+ // placed, never flown.
15
+ import { subscribe } from '../synabun-ticker.js';
16
+ import { mascotBounds } from '../synabun-mascot.js';
17
+ import { springStep } from './tour-ink.js';
18
+
19
+ const MOVE = [12, 0.74]; // ω (rad/s), ζ: ≈ 3 % overshoot, the --asst-ease-spring landing
20
+ const ARC = [13, 0.62]; // the hop's rise and fall
21
+ const CROUCH = [26, 0.45]; // the take-off squash, rubbery
22
+ const SCALE = [14, 0.72];
23
+ const ARRIVED = { px: 4, speed: 140 }; // close and slow enough for the beat to go on (the spring finishes on its own)
24
+ const KEEP_OUT_MARGIN = 6; // px of clear board round what the mascot draws
25
+
26
+ export function createActor(target, { reduced = () => false, onMove = null } = {}) {
27
+ const rig = target.rig;
28
+ const svg = target.el;
29
+ const box = svg?.parentElement || null; // .asst-empty-mascot: the svg is centred in it, so scale and lean pivot on the face
30
+ const s = { x: 0, y: 0, vx: 0, vy: 0, arc: 0, varc: 0, q: 0, vq: 0, k: 1, vk: 0 };
31
+ const goal = { x: 0, y: 0, k: 1 };
32
+ let stop = null;
33
+ let waiters = [];
34
+ let lastV = { x: 0, y: 0 };
35
+ let lastAt = { x: 0, y: 0 }; // where the body was on the last frame (for rig.shift)
36
+ let place = null; // the last place asked for (a client point or null = home), for a replay after a resize
37
+ let base = null; // { cx, cy, w, h }: the face's centre and size with no transform (one read per move)
38
+ let lastPose = { name: 'idle', opts: undefined };
39
+
40
+ const present = () => !!(box && svg?.isConnected && box.offsetWidth > 0);
41
+
42
+ /**
43
+ * The untransformed face: its client centre (one read) and its own size (the SVG's attributes). When the
44
+ * layout under it moved (the board made room, the panel changed), the body keeps its place on screen:
45
+ * the offset and the goal take the shift, so nothing jumps.
46
+ */
47
+ function readBase() {
48
+ if (!svg) return null;
49
+ const r = svg.getBoundingClientRect();
50
+ const w = Number(svg.getAttribute('width')) || r.width / (s.k || 1);
51
+ const h = Number(svg.getAttribute('height')) || r.height / (s.k || 1);
52
+ // Where the box would be with no transform: its client centre less the offset we set (scale and lean pivot on it).
53
+ const at = { cx: r.left + r.width / 2 - s.x, cy: r.top + r.height / 2 - (s.y + s.arc) };
54
+ const prev = base;
55
+ base = { cx: at.cx, cy: at.cy, w, h };
56
+ if (prev && box?.style.transform && (Math.abs(prev.cx - at.cx) > 0.5 || Math.abs(prev.cy - at.cy) > 0.5)) {
57
+ // The layout moved under a transform we set: hold the body where it is on screen, and its goal too.
58
+ const dx = prev.cx - at.cx;
59
+ const dy = prev.cy - at.cy;
60
+ s.x += dx;
61
+ s.y += dy;
62
+ goal.x += dx;
63
+ goal.y += dy;
64
+ lastAt = { x: lastAt.x + dx, y: lastAt.y + dy };
65
+ write();
66
+ }
67
+ return base;
68
+ }
69
+
70
+ /** The face-unit box the pose draws in, as a client rect for the face at (x, y) offset and scale k, plus `margin`. */
71
+ function boundsAt(x, y, k, margin = KEEP_OUT_MARGIN) {
72
+ if (!base) return null;
73
+ const b = mascotBounds(lastPose.name, lastPose.opts);
74
+ const u = (base.w / 280) * k; // CSS px per face unit
75
+ const left = base.cx + x - (base.w * k) / 2;
76
+ const top = base.cy + y - (base.h * k) / 2;
77
+ const rect = { left: left + b.left * u - margin, top: top + b.top * u - margin, right: left + b.right * u + margin, bottom: top + b.bottom * u + margin };
78
+ rect.width = rect.right - rect.left;
79
+ rect.height = rect.bottom - rect.top;
80
+ return rect;
81
+ }
82
+
83
+ const tellMove = () => { if (onMove && base) try { onMove(boundsAt(s.x, s.y + s.arc, s.k)); } catch { /* the host's */ } };
84
+
85
+ function write() {
86
+ if (!box) return;
87
+ const speed = Math.hypot(s.vx, s.vy + s.varc);
88
+ const stretch = Math.min(0.04, speed / 9000);
89
+ const lean = Math.max(-7, Math.min(7, s.vx * 0.011));
90
+ const sx = s.k * (1 + s.q) * (1 - stretch);
91
+ const sy = s.k * (1 - s.q) * (1 + stretch);
92
+ const still = Math.abs(s.x) < 0.05 && Math.abs(s.y + s.arc) < 0.05 && Math.abs(sx - 1) < 1e-3 && Math.abs(sy - 1) < 1e-3 && Math.abs(lean) < 0.05;
93
+ box.style.transform = still ? '' : `translate(${s.x.toFixed(2)}px, ${(s.y + s.arc).toFixed(2)}px) rotate(${lean.toFixed(2)}deg) scale(${sx.toFixed(4)}, ${sy.toFixed(4)})`;
94
+ tellMove();
95
+ }
96
+
97
+ /** Where the face's centre sits with no transform (one read per move). */
98
+ function layoutCentre() {
99
+ const r = svg.getBoundingClientRect();
100
+ return { x: r.left + r.width / 2 - s.x, y: r.top + r.height / 2 - (s.y + s.arc) };
101
+ }
102
+
103
+ const near = () => Math.hypot(goal.x - s.x, goal.y - s.y) < ARRIVED.px && Math.hypot(s.vx, s.vy) < ARRIVED.speed && Math.abs(s.arc) < ARRIVED.px;
104
+ const still = () => Math.hypot(goal.x - s.x, goal.y - s.y) < 0.2 && Math.hypot(s.vx, s.vy) < 2 && Math.abs(s.arc) < 0.2 && Math.abs(s.varc) < 2
105
+ && Math.abs(s.q) < 0.001 && Math.abs(s.vq) < 0.01 && Math.abs(s.k - goal.k) < 0.001 && Math.abs(s.vk) < 0.01;
106
+
107
+ function release(all = false) {
108
+ const keep = [];
109
+ for (const w of waiters) { if (all || w.when()) w.resolve(); else keep.push(w); }
110
+ waiters = keep;
111
+ }
112
+
113
+ function onFrame(_now, dtMs) {
114
+ const dt = dtMs / 1000;
115
+ if (!svg?.isConnected) { halt(); return; } // no layout read per frame: present() is asked once per move
116
+ let r = springStep(s.x, s.vx, goal.x, MOVE[0], MOVE[1], dt); s.x = r.x; s.vx = r.v;
117
+ r = springStep(s.y, s.vy, goal.y, MOVE[0], MOVE[1], dt); s.y = r.x; s.vy = r.v;
118
+ r = springStep(s.arc, s.varc, 0, ARC[0], ARC[1], dt); s.arc = r.x; s.varc = r.v;
119
+ r = springStep(s.q, s.vq, 0, CROUCH[0], CROUCH[1], dt); s.q = r.x; s.vq = r.v;
120
+ r = springStep(s.k, s.vk, goal.k, SCALE[0], SCALE[1], dt); s.k = r.x; s.vk = r.v;
121
+ write();
122
+ // The body's change of velocity this frame: the arms keep their old speed and trail.
123
+ const v = { x: s.vx, y: s.vy + s.varc };
124
+ const dvx = v.x - lastV.x;
125
+ const dvy = v.y - lastV.y;
126
+ lastV = v;
127
+ if (Math.abs(dvx) + Math.abs(dvy) > 1) try { rig.nudge?.(dvx, dvy); } catch { /* an older rig */ }
128
+ // The body moved: a hand that points keeps pointing at the same control (no layout read).
129
+ const at = { x: s.x, y: s.y + s.arc };
130
+ if (rig.pointing) try { rig.shift?.(at.x - lastAt.x, at.y - lastAt.y); } catch { /* an older rig */ }
131
+ lastAt = at;
132
+ release();
133
+ if (still()) {
134
+ Object.assign(s, { x: goal.x, y: goal.y, vx: 0, vy: 0, arc: 0, varc: 0, q: 0, vq: 0, k: goal.k, vk: 0 });
135
+ write();
136
+ halt();
137
+ if (rig.pointing) try { rig.remeasure?.(); } catch { /* an older rig */ } // landed, scale settled: read the rects once more
138
+ }
139
+ }
140
+
141
+ function halt() {
142
+ stop?.();
143
+ stop = null;
144
+ lastV = { x: 0, y: 0 };
145
+ release(true);
146
+ }
147
+
148
+ /**
149
+ * Fly to `point` (client px; null = home) at `scale`. Resolves once it has
150
+ * arrived closely enough for the next op (the landing finishes on its own),
151
+ * at once under reduced motion or when there is no character on screen.
152
+ */
153
+ function travel(point, { scale = 1 } = {}) {
154
+ place = { point: point ? { ...point } : null, scale };
155
+ if (!present()) return Promise.resolve();
156
+ const c = readBase() ? { x: base.cx, y: base.cy } : layoutCentre();
157
+ const to = { x: point ? point.x - c.x : 0, y: point ? point.y - c.y : 0, k: scale };
158
+ const dist = Math.hypot(to.x - s.x, to.y - s.y);
159
+ Object.assign(goal, to);
160
+ if (reduced()) {
161
+ halt();
162
+ Object.assign(s, { x: to.x, y: to.y, vx: 0, vy: 0, arc: 0, varc: 0, q: 0, vq: 0, k: to.k, vk: 0 });
163
+ write();
164
+ lastAt = { x: s.x, y: s.y };
165
+ if (rig.pointing) try { rig.remeasure?.(); } catch { /* an older rig */ }
166
+ return Promise.resolve();
167
+ }
168
+ if (dist > 6) {
169
+ // Take-off: a small crouch and a hop, both scaled to the distance (a short move barely hops).
170
+ s.vq += Math.min(2.6, 0.9 + dist / 160);
171
+ s.varc -= Math.min(260, 40 + dist * 1.2);
172
+ }
173
+ if (!stop) { lastV = { x: s.vx, y: s.vy + s.varc }; lastAt = { x: s.x, y: s.y + s.arc }; stop = subscribe(onFrame, { fps: 60 }); }
174
+ return new Promise((resolve) => { waiters.push({ resolve, when: near }); });
175
+ }
176
+
177
+ /** The panel was resized: fly to the same place again (its client point is the caller's to recompute). */
178
+ function replay(point) {
179
+ if (!place) return Promise.resolve();
180
+ return travel(point === undefined ? place.point : point, { scale: place.scale });
181
+ }
182
+
183
+ /**
184
+ * What the mascot draws (mascotBounds for its pose: the eyes over their
185
+ * travel, the smile, its prop), where it lands, as a client rect plus
186
+ * `margin` px: the board keeps its ink out of it.
187
+ */
188
+ function keepOut(margin = KEEP_OUT_MARGIN) {
189
+ if (!svg) return null;
190
+ if (!base) readBase();
191
+ return boundsAt(goal.x, goal.y, goal.k, margin);
192
+ }
193
+
194
+ /** keepOut() for the face landed at client point `point` (its centre) at `scale`: for choosing a place. */
195
+ function keepOutAt(point, scale = 1, margin = KEEP_OUT_MARGIN) {
196
+ if (!svg) return null;
197
+ if (!base) readBase();
198
+ if (!base) return null;
199
+ return boundsAt(point ? point.x - base.cx : 0, point ? point.y - base.cy : 0, scale, margin);
200
+ }
201
+
202
+ /** The face's client rect where it will land (its goal), for ink placed beside it. */
203
+ function rect() {
204
+ if (!svg) return null;
205
+ const r = svg.getBoundingClientRect();
206
+ const k = goal.k / (s.k || 1);
207
+ const cx = r.left + r.width / 2 + (goal.x - s.x);
208
+ const cy = r.top + r.height / 2 + (goal.y - (s.y + s.arc));
209
+ const w = r.width * k;
210
+ const h = r.height * k;
211
+ return { left: cx - w / 2, top: cy - h / 2, right: cx + w / 2, bottom: cy + h / 2, width: w, height: h };
212
+ }
213
+
214
+ /**
215
+ * A point on the landed face's visible edge (the eyes and the smile, not the SVG's box:
216
+ * the eyes span 29-71 % of its width, 17-86 % of its height): 'top' | 'bottom' | 'left' | 'right' | 'center'.
217
+ */
218
+ function edge(side = 'center') {
219
+ const r = rect();
220
+ if (!r) return null;
221
+ const c = { x: r.left + r.width / 2, y: r.top + r.height * 0.5 };
222
+ if (side === 'top') return { x: c.x, y: r.top + r.height * 0.14 };
223
+ if (side === 'bottom') return { x: c.x, y: r.top + r.height * 0.9 };
224
+ if (side === 'left') return { x: r.left + r.width * 0.26, y: c.y };
225
+ if (side === 'right') return { x: r.left + r.width * 0.74, y: c.y };
226
+ return c;
227
+ }
228
+
229
+ return {
230
+ rig,
231
+ box,
232
+ present,
233
+ travel,
234
+ replay,
235
+ rect,
236
+ edge,
237
+ keepOut,
238
+ keepOutAt,
239
+ /** Read the untransformed face again (the panel was resized or scrolled). */
240
+ measure() { readBase(); tellMove(); },
241
+ pose(name, opts) { lastPose = { name, opts }; try { rig.setPose(name, opts); } catch { /* gone */ } tellMove(); },
242
+ react(name) { if (!reduced()) try { rig.react(name); } catch { /* gone */ } },
243
+ /** Point with the arms and the eyes (null: put them away); opts: { poke, gap } (rig.point). */
244
+ point(targetEl, opts) { try { rig.point?.(targetEl, opts); } catch { /* an older rig */ } },
245
+ poke() { if (!reduced()) try { rig.poke?.(); } catch { /* an older rig */ } },
246
+ /** Look toward a client point without pointing. */
247
+ look(point) {
248
+ const r = rect();
249
+ if (!r || !point) return;
250
+ const vx = point.x - (r.left + r.width / 2);
251
+ const vy = point.y - (r.top + r.height / 2);
252
+ const d = Math.hypot(vx, vy);
253
+ if (d < 1) { rig.look(0, 0); return; }
254
+ const m = (d / (d + 140)) * 1.25;
255
+ rig.look(Math.max(-1, Math.min(1, (vx / d) * m)), Math.max(-1, Math.min(1, (vy / d) * m)));
256
+ },
257
+ get lastPose() { return lastPose; },
258
+ /** Back to rest at once: no transform, nothing pending. */
259
+ reset() {
260
+ halt();
261
+ Object.assign(s, { x: 0, y: 0, vx: 0, vy: 0, arc: 0, varc: 0, q: 0, vq: 0, k: 1, vk: 0 });
262
+ Object.assign(goal, { x: 0, y: 0, k: 1 });
263
+ if (box) box.style.transform = '';
264
+ place = null;
265
+ },
266
+ get moving() { return !!stop; },
267
+ };
268
+ }