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
@@ -15,8 +15,8 @@ import { emit } from './state.js';
15
15
  import { getLocale, t } from './i18n.js';
16
16
  import { desktopBridge } from './desktop-bridge.js';
17
17
  import {
18
- desktopCheckOutcome, desktopUpdateMeta, desktopUpdateNotice, desktopUpdateTooltip, desktopUpdateView, fillDesktopCopy, readDesktopUpdateState,
19
- versionDataFromDesktop,
18
+ desktopCheckOutcome, desktopRestartButton, desktopUpdateMeta, desktopUpdateNotice, desktopUpdateTooltip, desktopUpdateView, fillDesktopCopy,
19
+ readDesktopUpdateState, versionDataFromDesktop,
20
20
  } from './desktop-update-view.js';
21
21
 
22
22
  const $ = (id) => document.getElementById(id);
@@ -83,6 +83,25 @@ function applyTopRightButton(data) {
83
83
  ? desktopUpdateTooltip(_desktopState, { t: desktopT })
84
84
  : `SynaBun update available: v${data.current} → v${data.latest} (${srcLabel})`;
85
85
  }
86
+ // The desktop app with an update downloaded: the button says Restart to update, as Discord's green one does.
87
+ const restart = has && data.desktop ? desktopRestartButton(_desktopState, { t: desktopT }) : null;
88
+ btn.classList.toggle('update-ready', !!restart);
89
+ let label = btn.querySelector('.update-ready-label');
90
+ if (restart) {
91
+ if (!label) {
92
+ label = document.createElement('span');
93
+ label.className = 'update-ready-label';
94
+ btn.appendChild(label);
95
+ }
96
+ if (label.textContent !== restart.label) label.textContent = restart.label;
97
+ btn.dataset.tooltip = restart.tooltip;
98
+ btn.setAttribute('aria-label', restart.label);
99
+ btn.classList.toggle('update-ready--asked', restart.asked);
100
+ } else {
101
+ label?.remove();
102
+ btn.classList.remove('update-ready--asked');
103
+ btn.removeAttribute('aria-label');
104
+ }
86
105
  if (!_btnWired) {
87
106
  _btnWired = true;
88
107
  // Whole button opens the update flow — it's a dedicated SynaBun-update
@@ -92,11 +111,28 @@ function applyTopRightButton(data) {
92
111
  if (!_versionData?.updateAvailable) return;
93
112
  e.stopPropagation();
94
113
  e.preventDefault();
114
+ if (btn.classList.contains('update-ready')) { restartToUpdate(); return; }
95
115
  openUpdateModal();
96
116
  });
97
117
  }
98
118
  }
99
119
 
120
+ /**
121
+ * Restart to update (the desktop app's ready button): Install now. When SynaBun is idle the app restarts into the
122
+ * update at once (its splash takes the window's place); while something runs, the dialog says what it waits for.
123
+ */
124
+ async function restartToUpdate() {
125
+ const desktop = desktopBridge();
126
+ if (!desktop) return;
127
+ const btn = $('topright-update-btn');
128
+ btn?.setAttribute('aria-busy', 'true');
129
+ let answer = null;
130
+ try { answer = await desktop.updates.install(); } catch { /* the dialog below says what the app reports */ }
131
+ btn?.removeAttribute('aria-busy');
132
+ if (answer) applyDesktopState(answer, { alert: false });
133
+ if (readDesktopUpdateState(answer || _desktopState).status !== 'installing') openDesktopUpdateModal();
134
+ }
135
+
100
136
  function maybeShowUpdateAlert(data, { once = true } = {}) {
101
137
  if (!data?.updateAvailable) return;
102
138
  const key = `synabun-update-alert:${data.current}->${data.latest}:${synabunUpdateSourceLabel(data)}`;
@@ -13,6 +13,9 @@ import { storage } from './storage.js';
13
13
  import { isGuest, hasPermission } from './ui-sync.js';
14
14
  import { openSettingsModal } from './ui-settings.js';
15
15
  import { fetchRulesStatus } from './api.js';
16
+ import { registerContextMenuArea } from './context-menu-areas.js';
17
+ import { frameRect } from './app-frame.js';
18
+ import { readListItems, writeListItems, fitListLevels, indentListItem, outdentListItem, listMarkers } from './whiteboard-list.js';
16
19
 
17
20
  // ── Helpers ──
18
21
 
@@ -412,11 +415,31 @@ function flushListEdits() {
412
415
  const elId = dom.dataset.wbId;
413
416
  const el = _elements.find(e => e.id === elId);
414
417
  if (el && ul) {
415
- el.items = [...ul.querySelectorAll('li')].map(li => li.innerText.trimEnd());
416
- if (!el.items.length) el.items = [''];
418
+ const { items, levels } = _readListDom(ul);
419
+ if (items.length) writeListItems(el, items, levels);
420
+ else writeListItems(el, [''], [0]);
417
421
  }
418
422
  }
419
423
 
424
+ /** Text and level of every <li> of a list, an edit in progress included (levels: whiteboard-list.js). */
425
+ function _readListDom(ul) {
426
+ const lis = [...ul.querySelectorAll('li')];
427
+ return {
428
+ items: lis.map(li => li.innerText.trimEnd()),
429
+ levels: lis.map(li => Number(li.dataset.level) || 0),
430
+ };
431
+ }
432
+
433
+ // The list being edited as it was when editing began (the "before" of its undo entry).
434
+ let _listEditBefore = null;
435
+
436
+ /** A copy of a list element for an undo entry: its own items and levels arrays. */
437
+ function _listSnapshot(el) {
438
+ const copy = { ...el, items: [...(el.items || [])] };
439
+ if (Array.isArray(el.levels)) copy.levels = [...el.levels];
440
+ return copy;
441
+ }
442
+
420
443
  /** Flush in-progress text edits from contenteditable DOM back into _elements (without exiting edit mode). */
421
444
  function flushTextEdits() {
422
445
  const editingText = _root?.querySelector('.wb-text.editing .wb-text-content');
@@ -874,7 +897,8 @@ function updateElementDOM(dom, el) {
874
897
  } else if (el.type === 'list') {
875
898
  let list = dom.querySelector('ul, ol');
876
899
  if (list && !dom.classList.contains('editing')) {
877
- const items = el.items && el.items.length ? el.items : [''];
900
+ // Plain strings without `levels` (every older board) read as level 0.
901
+ const { items, levels } = readListItems(el.items && el.items.length ? el.items : [''], el.levels);
878
902
  const wantTag = el.ordered ? 'OL' : 'UL';
879
903
  if (list.tagName !== wantTag) {
880
904
  // ordered flag changed — swap the container (never while editing)
@@ -883,10 +907,10 @@ function updateElementDOM(dom, el) {
883
907
  list = swapped;
884
908
  dom._wbListKey = null;
885
909
  }
886
- const key = wantTag + '|' + JSON.stringify(items);
910
+ const key = wantTag + '|' + JSON.stringify(items) + '|' + levels.join(',');
887
911
  if (dom._wbListKey !== key) {
888
- list.innerHTML = items.map(item =>
889
- `<li>${item.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')}</li>`
912
+ list.innerHTML = items.map((item, i) =>
913
+ `<li${levels[i] ? ` data-level="${levels[i]}"` : ''}>${item.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')}</li>`
890
914
  ).join('');
891
915
  dom._wbListKey = key;
892
916
  }
@@ -2060,25 +2084,28 @@ function exitEditMode() {
2060
2084
  if (editing) editing.blur();
2061
2085
  }
2062
2086
 
2063
- function enterListEditMode(dom, elId) {
2087
+ /**
2088
+ * Edit a list. `point` ({ x, y }, viewport px) is where the double-click that opened it landed: the caret goes
2089
+ * exactly there (that item, that line, that character). The items were not editable when the press came, so the
2090
+ * browser placed no caret of its own. Without a point (a list the list tool just made) the caret goes to the end
2091
+ * of the last item.
2092
+ */
2093
+ function enterListEditMode(dom, elId, point = null) {
2064
2094
  const ul = dom.querySelector('ul, ol');
2065
2095
  if (!ul) return;
2066
2096
  dom.classList.add('editing');
2097
+ // The undo entry of this edit starts from here: the saves made while editing (Tab, Enter, Backspace call
2098
+ // persistDebounced, which flushes the items into the element) must not become its "before".
2099
+ const el = _elements.find(e => e.id === elId);
2100
+ _listEditBefore = el ? _listSnapshot(el) : null;
2067
2101
 
2068
2102
  // Make all existing items editable
2069
2103
  [...ul.querySelectorAll('li')].forEach(li => li.setAttribute('contenteditable', 'true'));
2070
2104
 
2071
- // Focus last item, cursor at end
2105
+ if (point && _placeListCaretAt(dom, point.x, point.y)) return;
2072
2106
  const lis = [...ul.querySelectorAll('li')];
2073
2107
  const target = lis[lis.length - 1] || null;
2074
- if (target) {
2075
- target.focus();
2076
- const range = document.createRange();
2077
- range.selectNodeContents(target);
2078
- range.collapse(false);
2079
- window.getSelection().removeAllRanges();
2080
- window.getSelection().addRange(range);
2081
- }
2108
+ if (target) _placeCaret(target, 'end');
2082
2109
  }
2083
2110
 
2084
2111
  function exitListEditMode() {
@@ -2093,18 +2120,156 @@ function exitListEditMode() {
2093
2120
  if (document.activeElement?.closest('.wb-list')) document.activeElement.blur();
2094
2121
 
2095
2122
  const el = _elements.find(e => e.id === elId);
2123
+ const editBefore = _listEditBefore;
2124
+ _listEditBefore = null;
2096
2125
  if (el) {
2097
- const before = { ...el, items: [...(el.items || [])] };
2098
- const rawItems = [...ul.querySelectorAll('li')].map(li => li.innerText.trimEnd());
2099
- el.items = rawItems.filter((t, i, arr) => t !== '' || arr.length === 1);
2100
- if (!el.items.length) el.items = [''];
2101
- pushUndo('edit', before, { ...el, items: [...el.items] });
2126
+ const before = editBefore?.id === el.id ? editBefore : _listSnapshot(el);
2127
+ const { items, levels } = _readListDom(ul);
2128
+ // Empty items are dropped (the only item stays); the levels of what is left are fitted again.
2129
+ const kept = items.map((text, i) => ({ text, level: levels[i] })).filter((it, i, arr) => it.text !== '' || arr.length === 1);
2130
+ if (kept.length) writeListItems(el, kept.map(it => it.text), kept.map(it => it.level));
2131
+ else writeListItems(el, [''], [0]);
2132
+ pushUndo('edit', before, _listSnapshot(el));
2102
2133
  dom._wbListKey = null; // editing mutated the <li>s directly — force a clean rewrite
2103
2134
  renderElements();
2104
2135
  persistDebounced();
2105
2136
  }
2106
2137
  }
2107
2138
 
2139
+ /** A collapsed range at a viewport point (the standard call, then the WebKit/Blink one), or null. */
2140
+ function _caretRangeAtPoint(x, y) {
2141
+ if (typeof document.caretPositionFromPoint === 'function') {
2142
+ const pos = document.caretPositionFromPoint(x, y);
2143
+ if (pos?.offsetNode) {
2144
+ const range = document.createRange();
2145
+ range.setStart(pos.offsetNode, pos.offset);
2146
+ range.collapse(true);
2147
+ return range;
2148
+ }
2149
+ }
2150
+ if (typeof document.caretRangeFromPoint === 'function') return document.caretRangeFromPoint(x, y);
2151
+ return null;
2152
+ }
2153
+
2154
+ /** Focus an item being edited with the caret at its start or end. */
2155
+ function _placeCaret(li, where) {
2156
+ li.focus({ preventScroll: true });
2157
+ const range = document.createRange();
2158
+ range.selectNodeContents(li);
2159
+ range.collapse(where === 'start');
2160
+ const sel = window.getSelection();
2161
+ sel.removeAllRanges();
2162
+ sel.addRange(range);
2163
+ }
2164
+
2165
+ /**
2166
+ * Put the caret of a list being edited under a viewport point: in the item on that row, at the character under
2167
+ * the point. A point beside the text (the padding, a bullet, past the end of a line) lands on the nearest spot
2168
+ * of the nearest item. Returns false when the list has no item.
2169
+ */
2170
+ function _placeListCaretAt(listDom, x, y) {
2171
+ const lis = [...listDom.querySelectorAll('li')];
2172
+ if (!lis.length) return false;
2173
+ let li = lis[0], best = Infinity;
2174
+ for (const item of lis) {
2175
+ const r = item.getBoundingClientRect();
2176
+ const d = y < r.top ? r.top - y : y > r.bottom ? y - r.bottom : 0;
2177
+ if (d < best) { best = d; li = item; }
2178
+ }
2179
+ const r = li.getBoundingClientRect();
2180
+ const cx = Math.min(Math.max(x, r.left + 1), r.right - 1);
2181
+ const cy = Math.min(Math.max(y, r.top + 1), r.bottom - 1);
2182
+ let range = _caretRangeAtPoint(cx, cy);
2183
+ if (!range || !li.contains(range.startContainer)) {
2184
+ range = document.createRange();
2185
+ range.selectNodeContents(li);
2186
+ range.collapse(x < r.left + r.width / 2);
2187
+ }
2188
+ li.focus({ preventScroll: true });
2189
+ const sel = window.getSelection();
2190
+ sel.removeAllRanges();
2191
+ sel.addRange(range);
2192
+ return true;
2193
+ }
2194
+
2195
+ /** Write levels onto <li>s (level 0 is no attribute, as the render writes it). */
2196
+ function _applyListLevels(lis, levels) {
2197
+ lis.forEach((li, i) => {
2198
+ const level = levels[i] || 0;
2199
+ if (level) li.dataset.level = String(level);
2200
+ else delete li.dataset.level;
2201
+ });
2202
+ }
2203
+
2204
+ /** Fit the levels of a list being edited after an item was removed or merged (whiteboard-list.js rules). */
2205
+ function _refitListDom(ul) {
2206
+ const lis = [...ul.querySelectorAll('li')];
2207
+ _applyListLevels(lis, fitListLevels(lis.map(li => Number(li.dataset.level) || 0), lis.length));
2208
+ }
2209
+
2210
+ /** Tab / Shift+Tab on an item being edited: one level deeper (+1) or shallower (-1). False when it cannot move. */
2211
+ function _shiftListItemLevel(li, dir) {
2212
+ const lis = [...li.parentElement.querySelectorAll('li')];
2213
+ const levels = lis.map(n => Number(n.dataset.level) || 0);
2214
+ const index = lis.indexOf(li);
2215
+ const next = dir > 0 ? indentListItem(levels, index) : outdentListItem(levels, index);
2216
+ if (!next) return false;
2217
+ _applyListLevels(lis, next);
2218
+ return true;
2219
+ }
2220
+
2221
+ /** An item left with no text holds nothing (no stray <br>), so the empty placeholder shows. */
2222
+ function _tidyEmptyItem(li) {
2223
+ if (li.textContent === '' && !li.querySelector('img')) li.replaceChildren();
2224
+ }
2225
+
2226
+ /** Whether the caret (collapsed) sits at the very start of an item being edited. */
2227
+ function _caretAtItemStart(li) {
2228
+ const sel = window.getSelection();
2229
+ if (!sel.rangeCount || !sel.isCollapsed) return false;
2230
+ const caret = sel.getRangeAt(0);
2231
+ if (!li.contains(caret.startContainer)) return false;
2232
+ const before = document.createRange();
2233
+ before.setStart(li, 0);
2234
+ before.setEnd(caret.startContainer, caret.startOffset);
2235
+ return before.toString() === '' && !before.cloneContents().querySelector('br, img');
2236
+ }
2237
+
2238
+ /** Enter: what follows the caret (the selection removed first) leaves the item, for the new one. */
2239
+ function _cutAfterCaret(li) {
2240
+ const sel = window.getSelection();
2241
+ if (!sel.rangeCount) return null;
2242
+ const range = sel.getRangeAt(0);
2243
+ if (!li.contains(range.startContainer)) return null;
2244
+ if (!li.contains(range.endContainer)) range.collapse(true);
2245
+ else if (!range.collapsed) range.deleteContents();
2246
+ const tail = document.createRange();
2247
+ tail.setStart(range.startContainer, range.startOffset);
2248
+ tail.setEnd(li, li.childNodes.length);
2249
+ return tail.extractContents();
2250
+ }
2251
+
2252
+ /** Backspace at the start of an item that has text: it joins the end of the item above, the caret at the seam. */
2253
+ function _mergeIntoPrevious(li) {
2254
+ const prev = li.previousElementSibling;
2255
+ if (!prev) return false;
2256
+ _tidyEmptyItem(prev);
2257
+ const seam = prev.childNodes.length;
2258
+ _tidyEmptyItem(li);
2259
+ while (li.firstChild) prev.appendChild(li.firstChild);
2260
+ const ul = li.parentElement;
2261
+ li.remove();
2262
+ _refitListDom(ul);
2263
+ prev.focus({ preventScroll: true });
2264
+ const range = document.createRange();
2265
+ range.setStart(prev, seam);
2266
+ range.collapse(true);
2267
+ const sel = window.getSelection();
2268
+ sel.removeAllRanges();
2269
+ sel.addRange(range);
2270
+ return true;
2271
+ }
2272
+
2108
2273
 
2109
2274
  // ═══════════════════════════════════════════
2110
2275
  // MULTI-SELECT HELPERS
@@ -2172,6 +2337,19 @@ function onMouseDown(e) {
2172
2337
  // Block drawing for guests without whiteboard permission (select/view still allowed)
2173
2338
  if (isGuest() && !hasPermission('whiteboard') && _activeTool !== 'select') return;
2174
2339
 
2340
+ // A press inside the list being edited belongs to its text, as in a text editor: the browser puts the caret
2341
+ // under the pointer (any item, any line, any character) and a drag selects. Leaving edit mode here, starting
2342
+ // a move and preventDefault() (below, for any press on an element) is what threw the caret onto the end of
2343
+ // the last item. A press beside the items (padding, bullets) is placed on the nearest item by hand.
2344
+ const editingList = e.target.closest?.('.wb-list.editing');
2345
+ if (editingList) {
2346
+ if (!e.target.closest('li')) {
2347
+ e.preventDefault();
2348
+ _placeListCaretAt(editingList, e.clientX, e.clientY);
2349
+ }
2350
+ return;
2351
+ }
2352
+
2175
2353
  // Steal focus from terminal/other elements so Ctrl+V paste works on whiteboard
2176
2354
  _root.focus({ preventScroll: true });
2177
2355
 
@@ -2799,12 +2977,14 @@ function onDblClick(e) {
2799
2977
  return;
2800
2978
  }
2801
2979
 
2802
- // Double-click list → edit
2980
+ // Double-click list → edit, the caret where the double-click landed
2803
2981
  const listEl = e.target.closest('.wb-list[data-wb-id]');
2804
2982
  if (listEl && _activeTool === 'select') {
2983
+ // Already editing: the double-click is the text's (the browser selects the word under it).
2984
+ if (listEl.classList.contains('editing')) return;
2805
2985
  const id = listEl.dataset.wbId;
2806
2986
  selectElement(id);
2807
- enterListEditMode(listEl, id);
2987
+ enterListEditMode(listEl, id, { x: e.clientX, y: e.clientY });
2808
2988
  e.preventDefault();
2809
2989
  return;
2810
2990
  }
@@ -2878,7 +3058,7 @@ function isWhiteboardActive() {
2878
3058
  }
2879
3059
 
2880
3060
  // A key pressed inside a side panel is the panel's: registerSidepanel marks every panel root
2881
- // (Claude, Codex, OpenCode, Assistant) with data-sidepanel-provider.
3061
+ // (Claude, Codex, OpenCode, Antigravity, Assistant) with data-sidepanel-provider.
2882
3062
  export function isSidepanelKeyTarget(el) {
2883
3063
  return !!el?.closest?.('[data-sidepanel-provider]');
2884
3064
  }
@@ -2915,35 +3095,63 @@ function onKeyDown(e) {
2915
3095
  const editingListLi = document.activeElement?.closest('.wb-list.editing li') || null;
2916
3096
  const isEditing = isEditingText || !!editingListLi;
2917
3097
 
2918
- // List Enter → insert new item
2919
- if (editingListLi && e.key === 'Enter') {
3098
+ // Keys of a list item being edited (an IME composition keeps its own Enter / Tab / Backspace).
3099
+ // Tab / Shift+Tab → one level deeper / shallower (whiteboard-list.js rules). Always taken here: Tab never
3100
+ // leaves the list or types a tab, even when the item cannot move.
3101
+ if (editingListLi && e.key === 'Tab' && !e.isComposing && !e.ctrlKey && !e.metaKey && !e.altKey) {
3102
+ e.preventDefault();
3103
+ e.stopImmediatePropagation();
3104
+ if (_shiftListItemLevel(editingListLi, e.shiftKey ? -1 : 1)) persistDebounced();
3105
+ return;
3106
+ }
3107
+
3108
+ // List Enter → a new item at the same level; what follows the caret moves into it
3109
+ if (editingListLi && e.key === 'Enter' && !e.isComposing) {
2920
3110
  e.preventDefault();
2921
3111
  e.stopImmediatePropagation();
2922
3112
  const newLi = document.createElement('li');
2923
3113
  newLi.setAttribute('contenteditable', 'true');
3114
+ if (editingListLi.dataset.level) newLi.dataset.level = editingListLi.dataset.level;
3115
+ const tail = _cutAfterCaret(editingListLi);
3116
+ if (tail) newLi.appendChild(tail);
3117
+ _tidyEmptyItem(editingListLi);
3118
+ _tidyEmptyItem(newLi);
2924
3119
  editingListLi.after(newLi);
2925
- newLi.focus();
3120
+ _placeCaret(newLi, 'start');
3121
+ persistDebounced();
2926
3122
  return;
2927
3123
  }
2928
3124
 
2929
- // List Backspace on empty item → remove item (keep at least 1)
2930
- if (editingListLi && e.key === 'Backspace' && editingListLi.textContent === '') {
3125
+ // List Backspace at the start of an item: an indented item goes one level up first; then an empty item is
3126
+ // removed (keep at least 1) and one with text joins the item above.
3127
+ if (editingListLi && e.key === 'Backspace' && !e.isComposing
3128
+ && (editingListLi.textContent === '' || _caretAtItemStart(editingListLi))) {
2931
3129
  const ul = editingListLi.parentElement;
2932
- if (ul && ul.children.length > 1) {
3130
+ const plain = !e.ctrlKey && !e.metaKey && !e.altKey;
3131
+ if (plain && (Number(editingListLi.dataset.level) || 0) > 0) {
2933
3132
  e.preventDefault();
2934
3133
  e.stopImmediatePropagation();
2935
- const prev = editingListLi.previousElementSibling;
2936
- const next = editingListLi.nextElementSibling;
2937
- editingListLi.remove();
2938
- const focusTarget = prev || next;
2939
- if (focusTarget) {
2940
- focusTarget.focus();
2941
- const range = document.createRange();
2942
- range.selectNodeContents(focusTarget);
2943
- range.collapse(false);
2944
- window.getSelection().removeAllRanges();
2945
- window.getSelection().addRange(range);
3134
+ if (_shiftListItemLevel(editingListLi, -1)) persistDebounced();
3135
+ return;
3136
+ }
3137
+ if (editingListLi.textContent === '') {
3138
+ if (ul && ul.children.length > 1) {
3139
+ e.preventDefault();
3140
+ e.stopImmediatePropagation();
3141
+ const prev = editingListLi.previousElementSibling;
3142
+ const next = editingListLi.nextElementSibling;
3143
+ editingListLi.remove();
3144
+ _refitListDom(ul);
3145
+ const focusTarget = prev || next;
3146
+ if (focusTarget) _placeCaret(focusTarget, 'end');
3147
+ persistDebounced();
2946
3148
  }
3149
+ return;
3150
+ }
3151
+ if (plain && editingListLi.previousElementSibling) {
3152
+ e.preventDefault();
3153
+ e.stopImmediatePropagation();
3154
+ if (_mergeIntoPrevious(editingListLi)) persistDebounced();
2947
3155
  }
2948
3156
  return;
2949
3157
  }
@@ -3400,6 +3608,41 @@ export function addImageToWhiteboard(url) {
3400
3608
  img.src = url;
3401
3609
  }
3402
3610
 
3611
+ // ═══════════════════════════════════════════
3612
+ // THE APP'S RIGHT-CLICK MENU (context-menu-model.js focusItems)
3613
+ // ═══════════════════════════════════════════
3614
+
3615
+ // Each row goes through what the board already does: its toolbar's own buttons (onToolbarClick, with
3616
+ // its guest check and the multi-select mode a tool leaves) and Ctrl+A's selectMultiple.
3617
+ const pressToolbar = (selector) => _toolbar?.querySelector(selector)?.click();
3618
+
3619
+ // The whole focus-mode screen (#static-bg while it is shown): the board, its toolbar, the logo.
3620
+ const focusMenuArea = {
3621
+ id: 'focus-whiteboard',
3622
+ match(el) {
3623
+ if (!el?.closest?.('#static-bg.visible')) return null;
3624
+ return {
3625
+ kind: 'focus',
3626
+ focus: {
3627
+ tool: _activeTool,
3628
+ multi: _multiSelectMode,
3629
+ canUndo: _undoStack.length > 0,
3630
+ canRedo: _redoStack.length > 0,
3631
+ hasElements: _elements.length > 0,
3632
+ canEdit: !(isGuest() && !hasPermission('whiteboard')),
3633
+ },
3634
+ act: {
3635
+ setTool: (name) => pressToolbar(`.wb-tool[data-tool="${name}"]`),
3636
+ toggleMulti: () => pressToolbar('#wb-multiselect'),
3637
+ undo: () => pressToolbar('#wb-undo'),
3638
+ redo: () => pressToolbar('#wb-redo'),
3639
+ selectAll: () => { const ids = _elements.map(e => e.id); if (ids.length) selectMultiple(ids); },
3640
+ exitFocus: () => $('titlebar-viz-toggle')?.click(), // the navbar's button, as the V key presses it
3641
+ },
3642
+ };
3643
+ },
3644
+ };
3645
+
3403
3646
  // ═══════════════════════════════════════════
3404
3647
  // INIT
3405
3648
  // ═══════════════════════════════════════════
@@ -3487,8 +3730,10 @@ export function initWhiteboard() {
3487
3730
  // Logo-adjacent ruleset reminder
3488
3731
  initRulesetAlert();
3489
3732
 
3490
- // Prevent context menu on whiteboard
3491
- _root.addEventListener('contextmenu', e => e.preventDefault());
3733
+ // Right-click: the board has no menu of its own, so it leaves the event to the app's menu
3734
+ // (ui-context-menu.js), which adds the board's section from focusMenuArea. A card being
3735
+ // edited keeps the browser's menu (spelling, paste), as every field does.
3736
+ registerContextMenuArea(focusMenuArea);
3492
3737
 
3493
3738
  // Listen for workspace events
3494
3739
  on('whiteboard:restore', restoreWhiteboardSnapshot);
@@ -3618,27 +3863,31 @@ function _cssPx(name) {
3618
3863
  }
3619
3864
 
3620
3865
  /** Usable whiteboard viewport in CSS px relative to #wb-root's top-left: the
3621
- * root minus the left tool rail, the navbar and the docked right-side agent
3622
- * panel (its reserved width is published as --right-panel-width by
3623
- * ui-sidepanel-layout.js; 0 when hidden or floating). #wb-root already ends
3624
- * above a docked terminal (--terminal-height). Sent to the server so MCP
3625
- * coordinate math and screenshots describe what the user can actually see. */
3866
+ * part of the root inside the app frame (below the navbar, right of the
3867
+ * explorers, the gutter around it: app-frame.js), minus the left tool rail
3868
+ * and the docked right-side agent panel (its reserved width is published as
3869
+ * --right-panel-width by ui-sidepanel-layout.js; 0 when hidden or floating).
3870
+ * #wb-root already ends above a docked terminal (--terminal-height). Sent to
3871
+ * the server so MCP coordinate math and screenshots describe what the user
3872
+ * can actually see. */
3626
3873
  function _computeViewport() {
3627
3874
  const rect = _root.getBoundingClientRect();
3628
- const titleBar = document.getElementById('title-bar');
3629
3875
  const toolbar = document.getElementById('wb-toolbar');
3630
- const navH = titleBar ? titleBar.getBoundingClientRect().height : _cssPx('--navbar-height');
3631
- const tbW = toolbar ? Math.max(0, toolbar.getBoundingClientRect().right - rect.left + 12) : 60;
3632
3876
  const rightW = Math.max(0, _cssPx('--right-panel-width') || _cssPx('--claude-panel-width'));
3877
+ const f = frameRect();
3878
+ const top = Math.max(rect.top, f.top);
3879
+ const left = Math.max(rect.left, f.left, toolbar ? toolbar.getBoundingClientRect().right + 12 : rect.left + 60);
3880
+ const right = Math.min(rect.right, f.right, window.innerWidth - rightW);
3881
+ const bottom = Math.min(rect.bottom, f.bottom);
3633
3882
  return {
3634
3883
  type: 'viewport',
3635
3884
  clientId: _clientId,
3636
3885
  focusActive: isWhiteboardActive(),
3637
3886
  visible: document.visibilityState === 'visible',
3638
- width: Math.max(0, Math.round(rect.width - tbW - rightW)),
3639
- height: Math.max(0, Math.round(rect.height - navH)),
3640
- xOffset: Math.round(tbW),
3641
- yOffset: Math.round(navH),
3887
+ width: Math.max(0, Math.round(right - left)),
3888
+ height: Math.max(0, Math.round(bottom - top)),
3889
+ xOffset: Math.round(left - rect.left),
3890
+ yOffset: Math.round(top - rect.top),
3642
3891
  rootWidth: Math.round(rect.width),
3643
3892
  rootHeight: Math.round(rect.height),
3644
3893
  rightPanelWidth: Math.round(rightW),
@@ -3695,6 +3944,7 @@ function _handleExternalCommand(msg) {
3695
3944
  const before = { ...el, points: el.points ? el.points.map(p => [...p]) : undefined };
3696
3945
  for (const [key, value] of Object.entries(msg.updates || {})) {
3697
3946
  if (key === 'id' || key === 'type') continue;
3947
+ if (key === 'levels' && value == null) { delete el.levels; continue; } // the list went flat
3698
3948
  el[key] = value;
3699
3949
  }
3700
3950
  pushUndo('edit', before, { ...el, points: el.points ? el.points.map(p => [...p]) : undefined });
@@ -3756,6 +4006,7 @@ function _handleExternalCommand(msg) {
3756
4006
  befores.push(copyEl(el));
3757
4007
  for (const [key, value] of Object.entries(op.updates || {})) {
3758
4008
  if (key === 'id' || key === 'type') continue;
4009
+ if (key === 'levels' && value == null) { delete el.levels; continue; } // the list went flat
3759
4010
  el[key] = value;
3760
4011
  }
3761
4012
  afters.push(copyEl(el));
@@ -3980,20 +4231,22 @@ async function _captureScreenshot(requestId, { crop } = {}) {
3980
4231
  lineTop += lineH;
3981
4232
  }
3982
4233
  } else if (el.type === 'list') {
3983
- // .wb-list: same box, line-height 1.5, <ul>/<ol> padding-left 1.4em
4234
+ // .wb-list: same box, line-height 1.5, <ul>/<ol> padding-left 1.4em, plus 1.4em per nesting level;
4235
+ // each level's bullet / numbering as styles.css draws it (whiteboard-list.js listMarkers)
3984
4236
  const fs = el.fontSize || 18;
3985
4237
  ctx.font = `400 ${fs}px ${mono}`;
3986
4238
  ctx.fillStyle = el.color || 'rgba(255,255,255,0.85)';
3987
4239
  ctx.textBaseline = 'alphabetic';
3988
4240
  const lineH = fs * 1.5;
3989
4241
  const baseOff = _lineBaseline(ctx, fs, lineH);
3990
- const items = el.items && el.items.length ? el.items : [''];
3991
- const contentLeft = el.x + 15 + 1.4 * fs;
4242
+ const { items, levels } = readListItems(el.items && el.items.length ? el.items : [''], el.levels);
4243
+ const markers = listMarkers(levels, !!el.ordered);
3992
4244
  let lineTop = el.y + 11;
3993
4245
  items.forEach((item, i) => {
3994
4246
  const baseline = lineTop + baseOff;
4247
+ const contentLeft = el.x + 15 + 1.4 * fs * (1 + levels[i]);
3995
4248
  ctx.textAlign = 'right';
3996
- ctx.fillText(el.ordered ? `${i + 1}.` : '•', contentLeft - 0.6 * fs, baseline);
4249
+ ctx.fillText(markers[i], contentLeft - 0.6 * fs, baseline);
3997
4250
  ctx.textAlign = 'left';
3998
4251
  if (item) ctx.fillText(item, contentLeft, baseline);
3999
4252
  lineTop += lineH;
@@ -2,7 +2,7 @@
2
2
  // SynaBun Neural Interface — how a dispatched worker's tab ends: the page side
3
3
  // ═══════════════════════════════════════════
4
4
  //
5
- // What the three provider sidepanels (Claude Code, Codex, OpenCode) share for
5
+ // What the four provider sidepanels (Claude Code, Codex, OpenCode, Antigravity) share for
6
6
  // the end of a worker the Assistant dispatched: following the run until it
7
7
  // has something to show, asking the dispatcher how it went (GET
8
8
  // /api/assistant/runs/:runId, then its `assistant:dispatch` events), the card
@@ -34,6 +34,10 @@ let _wired = false;
34
34
 
35
35
  function newer(next, current) {
36
36
  if (!current) return true;
37
+ // A run resumed after a server restart (`resumes` only grows) is newer whatever its version: a crash can lose the
38
+ // last saved versions of a run a page already saw.
39
+ const resumed = (Number(next?.resumes) || 0) - (Number(current?.resumes) || 0);
40
+ if (resumed) return resumed > 0;
37
41
  const a = Number(next?.version) || 0;
38
42
  const b = Number(current?.version) || 0;
39
43
  if (a !== b) return a > b;
@@ -24,6 +24,7 @@ import { storage } from './storage.js';
24
24
  import { t } from './i18n.js';
25
25
  import { posStore } from './node-positions-store.js';
26
26
  import { getVariant } from './registry.js';
27
+ import { normalizeWorkspaceVariant } from './view-variant.js';
27
28
  import {
28
29
  getOpenCardsSnapshot,
29
30
  closeAllCards,
@@ -51,14 +52,14 @@ let _isOpen = false;
51
52
 
52
53
  function getWorkspaces() {
53
54
  try {
54
- return JSON.parse(storage.getItem(KEYS.WORKSPACES) || '[]');
55
+ return JSON.parse(storage.getItem(KEYS.WORKSPACES) || '[]').map(normalizeWorkspaceVariant);
55
56
  } catch {
56
57
  return [];
57
58
  }
58
59
  }
59
60
 
60
61
  function saveWorkspacesToStorage(list) {
61
- storage.setItem(KEYS.WORKSPACES, JSON.stringify(list));
62
+ storage.setItem(KEYS.WORKSPACES, JSON.stringify(list.map(normalizeWorkspaceVariant)));
62
63
  }
63
64
 
64
65
  function _readStoredPositions(key) {