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
@@ -12,8 +12,9 @@
12
12
  // (OpenCode); the panel element gets `<prefix>-cli-blocked` while sending is
13
13
  // off.
14
14
  //
15
- // What it says is cli-install-view.js (DOM-free, tested under node); the data
16
- // and the install stream are cli-status.js. A panel mounts one controller:
15
+ // What it says is cli-install-view.js (DOM-free, tested under node); the state
16
+ // (the answer, the install, Re-check, Add to PATH) is cli-install-controller.js,
17
+ // which the Antigravity panel's setup card uses too. A panel mounts one banner:
17
18
  //
18
19
  // const cli = mountCliBanner({ toolKey: 'codex', prefix: 'cxp',
19
20
  // panel: () => panelEl, anchor: () => messagesContainer,
@@ -23,16 +24,12 @@
23
24
  // cli.nudge(); a send that was held back
24
25
  // cli.flagFailure(text); a session could not start the CLI
25
26
 
26
- import { subscribeCliStatus, recheckCliStatus, getCliDocUrl, getCliInstallCommand, getCliLabel, installCli, followCliInstall, getCliInstallJobs, addCliToPath } from './cli-status.js';
27
- import { cliBannerView, cliInstallText, cliStateOf, reduceInstallJob, setCliInstallTranslator, INSTALLABLE_CLIS } from './cli-install-view.js';
27
+ import { cliInstallText, setCliInstallTranslator } from './cli-install-view.js';
28
+ import { createCliInstallController, DONE_NOTICE_MS } from './cli-install-controller.js';
28
29
  import { t } from './i18n.js';
29
30
 
30
31
  setCliInstallTranslator((key, params) => t(`cliInstall.${key}`, params));
31
32
 
32
- /** How long the note about where an install put the CLI stays, when it has one. */
33
- const DONE_NOTICE_MS = 12000;
34
- const NUDGE_MS = 700;
35
-
36
33
  /**
37
34
  * @param {object} o
38
35
  * @param {'claude-code' | 'codex' | 'opencode'} o.toolKey
@@ -44,29 +41,10 @@ const NUDGE_MS = 700;
44
41
  */
45
42
  export function mountCliBanner({ toolKey, prefix, panel, anchor, onBlockedChange = () => {}, doneNoticeMs = DONE_NOTICE_MS } = {}) {
46
43
  const p = String(prefix || 'cp');
47
- let info = null; // this CLI in the latest answer of /api/system/tool-versions (null: none yet)
48
- let forced = null; // { reason }: a session could not start it, and the server was not asked again yet
49
- let job = null; // the install under way or just ended (cli-install-view.js reduceInstallJob)
50
- let installing = false;
51
- let addingPath = false;
52
- let pathError = '';
53
- let looked = false; // asked whether the server is already installing it since it went missing
54
44
  let el = null;
55
- let doneTimer = null;
56
- let nudgeTimer = null;
57
45
  let lastBlocked = null;
58
46
  let destroyed = false;
59
-
60
- const view = () => cliBannerView({
61
- toolKey,
62
- label: getCliLabel(toolKey),
63
- info,
64
- forced,
65
- job,
66
- addingPath, pathError,
67
- guideUrl: getCliDocUrl(toolKey),
68
- installCommand: getCliInstallCommand(toolKey),
69
- }, { t: cliInstallText });
47
+ let controller = null;
70
48
 
71
49
  const cls = (name) => `${p}-cli-banner-${name}`;
72
50
 
@@ -93,10 +71,10 @@ export function mountCliBanner({ toolKey, prefix, panel, anchor, onBlockedChange
93
71
  </div>
94
72
  </div>
95
73
  `;
96
- root.querySelector(`.${cls('install')}`).addEventListener('click', () => { startInstall(); });
97
- root.querySelector(`.${cls('recheck')}`).addEventListener('click', () => { recheck(); });
98
- root.querySelector(`.${cls('path')}`).addEventListener('click', () => { addPath(); });
99
- root.querySelector(`.${cls('dismiss')}`).addEventListener('click', () => { clearDone(); });
74
+ root.querySelector(`.${cls('install')}`).addEventListener('click', () => { controller?.install(); });
75
+ root.querySelector(`.${cls('recheck')}`).addEventListener('click', () => { controller?.recheck(); });
76
+ root.querySelector(`.${cls('path')}`).addEventListener('click', () => { controller?.addPath(); });
77
+ root.querySelector(`.${cls('dismiss')}`).addEventListener('click', () => { controller?.clearDone(); });
100
78
  root.querySelector(`.${cls('copy')}`).addEventListener('click', async (event) => {
101
79
  const button = event.currentTarget;
102
80
  const command = root.querySelector(`.${cls('command')} code`)?.textContent || '';
@@ -117,7 +95,7 @@ export function mountCliBanner({ toolKey, prefix, panel, anchor, onBlockedChange
117
95
  }
118
96
 
119
97
  function paint(v) {
120
- el.className = `${p}-cli-banner ${p}-cli-banner--${v.kind}${nudgeTimer ? ` ${p}-cli-banner--nudge` : ''}`;
98
+ el.className = `${p}-cli-banner ${p}-cli-banner--${v.kind}${v.nudging ? ` ${p}-cli-banner--nudge` : ''}`;
121
99
  el.setAttribute('role', v.live === 'assertive' ? 'alert' : 'status');
122
100
  el.setAttribute('aria-live', v.live);
123
101
  el.querySelector(`.${cls('icon')}`).textContent = v.icon;
@@ -180,7 +158,8 @@ export function mountCliBanner({ toolKey, prefix, panel, anchor, onBlockedChange
180
158
  else link.removeAttribute('href');
181
159
  const recheckButton = el.querySelector(`.${cls('recheck')}`);
182
160
  recheckButton.hidden = !v.recheck;
183
- if (!recheckButton.disabled) recheckButton.textContent = cliInstallText('recheck');
161
+ recheckButton.disabled = !!v.checking;
162
+ recheckButton.textContent = cliInstallText(v.checking ? 'checking' : 'recheck');
184
163
  const pathButton = el.querySelector(`.${cls('path')}`);
185
164
  pathButton.hidden = !v.addPath;
186
165
  pathButton.textContent = v.addPath?.label || '';
@@ -191,8 +170,8 @@ export function mountCliBanner({ toolKey, prefix, panel, anchor, onBlockedChange
191
170
  }
192
171
 
193
172
  function render() {
194
- if (destroyed) return;
195
- const v = view();
173
+ if (destroyed || !controller) return;
174
+ const v = controller.view();
196
175
  const panelEl = panel?.();
197
176
  if (panelEl) panelEl.classList.toggle(`${p}-cli-blocked`, v.blocked);
198
177
  if (v.show && place()) paint(v);
@@ -203,151 +182,28 @@ export function mountCliBanner({ toolKey, prefix, panel, anchor, onBlockedChange
203
182
  }
204
183
  }
205
184
 
206
- function clearDone() {
207
- clearTimeout(doneTimer);
208
- doneTimer = null;
209
- if (job?.phase === 'done') job = null;
210
- render();
211
- }
212
-
213
- function apply(event) {
214
- if (!job && event?.type !== 'start') job = reduceInstallJob(null, { type: 'start' });
215
- job = reduceInstallJob(job, event);
216
- if (event?.type === 'done' && event.ok && event.status && typeof event.status === 'object') {
217
- info = event.status;
218
- forced = null;
219
- }
220
- render();
221
- }
222
-
223
- function settle(final) {
224
- if (job?.phase === 'running' && final) job = reduceInstallJob(job, final);
225
- if (job?.phase === 'done') {
226
- clearTimeout(doneTimer);
227
- const where = job.path;
228
- if (where && (where.onPath === false || where.added === true)) doneTimer = setTimeout(clearDone, doneNoticeMs);
229
- else job = null;
230
- }
231
- render();
232
- }
233
-
234
- async function startInstall() {
235
- if (installing || !INSTALLABLE_CLIS.includes(toolKey)) return;
236
- installing = true;
237
- clearTimeout(doneTimer);
238
- job = reduceInstallJob(null, { type: 'start' });
239
- render();
240
- let final = null;
241
- try {
242
- final = await installCli(toolKey, { onEvent: apply });
243
- } catch (error) {
244
- final = { type: 'done', ok: false, code: 'internal', error: error?.message || null };
245
- } finally {
246
- installing = false;
247
- settle(final);
248
- }
249
- }
250
-
251
- async function addPath() {
252
- if (addingPath) return;
253
- addingPath = true; pathError = ''; render();
254
- try {
255
- const result = await addCliToPath(toolKey);
256
- info = { ...info, pathStatus: { dir: result.dir, onPath: true, canAdd: false } };
257
- job = reduceInstallJob(null, { type: 'done', ok: true, status: info, path: { ...result, added: true } });
258
- settle();
259
- } catch (error) { pathError = error.message; }
260
- finally { addingPath = false; render(); }
261
- }
262
-
263
- // An install the server is already running (another window started it, or this page was reloaded during
264
- // one): followed here as if this banner had started it.
265
- async function followRunning() {
266
- if (installing) return;
267
- const jobs = await getCliInstallJobs();
268
- if (destroyed || installing || jobs?.[toolKey]?.state !== 'running') return;
269
- installing = true;
270
- job = reduceInstallJob(null, { type: 'start' });
271
- render();
272
- let final = null;
273
- try {
274
- final = await followCliInstall(toolKey, { onEvent: apply });
275
- } catch (error) {
276
- final = { type: 'done', ok: false, code: 'connection', error: error?.message || null };
277
- } finally {
278
- installing = false;
279
- settle(final);
280
- }
281
- }
282
-
283
- async function recheck() {
284
- const button = el?.querySelector(`.${cls('recheck')}`);
285
- if (button) { button.disabled = true; button.textContent = cliInstallText('checking'); }
286
- // Asking again starts over: an earlier failure is not repeated over a fresh answer.
287
- if (job?.phase === 'failed') job = null;
288
- try {
289
- const next = await recheckCliStatus(toolKey);
290
- info = next || info;
291
- if (cliStateOf(info) === 'installed' || cliStateOf(info) === 'broken') forced = null;
292
- } catch { /* the banner stays as it is */ }
293
- finally {
294
- if (button?.isConnected) { button.disabled = false; button.textContent = cliInstallText('recheck'); }
295
- render();
296
- }
297
- }
298
-
299
- const unsubscribe = subscribeCliStatus(toolKey, (next) => {
300
- info = next || null;
301
- const state = cliStateOf(info);
302
- if (state === 'installed') {
303
- forced = null;
304
- if (job?.phase === 'failed') job = null;
305
- }
306
- if (state === 'missing') {
307
- if (!looked) { looked = true; followRunning().catch(() => {}); }
308
- } else {
309
- looked = false;
310
- }
311
- render();
312
- });
185
+ controller = createCliInstallController({ toolKey, doneNoticeMs, onChange: () => render() });
186
+ render();
313
187
 
314
188
  return {
315
189
  /** Draw again (the panel was shown, or rebuilt). */
316
190
  refresh: render,
317
191
  /** Sending is held back: the CLI is missing, broken, failed to install, or being installed. */
318
- blocked: () => view().blocked,
192
+ blocked: () => controller.blocked(),
319
193
  /** What the banner shows now (cli-install-view.js cliBannerView). */
320
- view,
194
+ view: () => controller.view(),
321
195
  /** A send was held back: draw attention to the banner for a moment. */
322
- nudge() {
323
- if (!view().show) return;
324
- clearTimeout(nudgeTimer);
325
- nudgeTimer = setTimeout(() => { nudgeTimer = null; render(); }, NUDGE_MS);
326
- render();
327
- },
196
+ nudge: () => controller.nudge(),
328
197
  /**
329
198
  * A session could not start the CLI ("Claude CLI not found", a spawn error): show "failed to start" with its
330
199
  * words at once, then ask the server again; its answer decides what stays.
331
200
  */
332
- flagFailure(reason = null) {
333
- forced = { reason: reason ? String(reason).slice(0, 300) : null };
334
- render();
335
- recheckCliStatus(toolKey)
336
- .then((next) => {
337
- info = next || info;
338
- const state = cliStateOf(info);
339
- if (state === 'installed' || state === 'broken') forced = null;
340
- render();
341
- })
342
- .catch(() => {});
343
- },
201
+ flagFailure: (reason = null) => controller.flagFailure(reason),
344
202
  /** Install from the banner's own button (for a panel's own entry point). */
345
- install: startInstall,
203
+ install: () => controller.install(),
346
204
  destroy() {
347
205
  destroyed = true;
348
- unsubscribe();
349
- clearTimeout(doneTimer);
350
- clearTimeout(nudgeTimer);
206
+ controller.destroy();
351
207
  el?.remove();
352
208
  el = null;
353
209
  },
@@ -2,6 +2,7 @@
2
2
  import { emit, on } from './state.js';
3
3
  import { KEYS, COLOR_PALETTE } from './constants.js';
4
4
  import { storage } from './storage.js';
5
+ import { frameRect, clampBox } from './app-frame.js';
5
6
  import { commandLaunchPayload, selectCommandGroups, isCommandLaunchAvailable } from './command-runner-model.js';
6
7
 
7
8
  const $ = id => document.getElementById(id);
@@ -35,9 +36,11 @@ export function initCommandRunner() { return on('command-runner:open', openPanel
35
36
  function clampPanel() {
36
37
  if (!_panel) return;
37
38
  const width = _panel.offsetWidth, height = _panel.offsetHeight;
38
- const top = parseFloat(getComputedStyle(document.documentElement).getPropertyValue('--navbar-height')) || 48;
39
- _panel.style.left = Math.max(8, Math.min(parseFloat(_panel.style.left) || 8, window.innerWidth - width - 8)) + 'px';
40
- _panel.style.top = Math.max(top + 8, Math.min(parseFloat(_panel.style.top) || top + 8, window.innerHeight - height - 8)) + 'px';
39
+ // Inside the app frame (8px from the window and the bar, as before, and clear of an open explorer)
40
+ const f = frameRect();
41
+ const at = clampBox(parseFloat(_panel.style.left) || f.left, parseFloat(_panel.style.top) || f.top, width, height, f);
42
+ _panel.style.left = at.x + 'px';
43
+ _panel.style.top = at.y + 'px';
41
44
  }
42
45
  function openPanel() {
43
46
  if (_panel) { $('cr-search')?.focus(); return; }
@@ -0,0 +1,295 @@
1
+ // ═══════════════════════════════════════════
2
+ // SynaBun Neural Interface — The app's right-click menu
3
+ // A right-click anywhere that has no menu of its own opens the app's menu
4
+ // instead of the browser's: page actions, then what fits what was clicked
5
+ // (selected text, a link, an image, a memory, the memory map, the 2D graph,
6
+ // the focus-mode whiteboard), then the app's panels and tools. The
7
+ // ContextMenu key and Shift+F10 open it at the focused element.
8
+ //
9
+ // The rule: the app's menu opens unless the element under the pointer shows
10
+ // a menu of its own for that very click. Such an element takes the event
11
+ // (preventDefault) only when it opens its menu: the terminal's viewport, a
12
+ // File Explorer row or its empty tree, an editor tab, a 2D graph card, an
13
+ // Automation Studio item or folder, the map's canvas (OrbitControls takes
14
+ // every right-click there for right-drag pan; the map opens this menu itself
15
+ // when the right button comes up where it went down). An area that only
16
+ // suppressed the browser's menu would leave the user with nothing, so none
17
+ // does. NATIVE_CONTEXTMENU_SELECTORS names exact elements, never a whole
18
+ // screen or panel. Fields keep the browser's menu (spelling, paste), and so
19
+ // does any right-click with Shift held.
20
+ //
21
+ // The items are context-menu-model.js; the component is context-menu.js;
22
+ // the areas registry is context-menu-areas.js. Every action is a function the
23
+ // app already has: a registered keybind action, a bus event the menubar
24
+ // emits, a panel's button, sendToPanel, the memory card's functions.
25
+ // ═══════════════════════════════════════════
26
+
27
+ import { openContextMenu, isContextMenuOpen } from './context-menu.js';
28
+ import { isEditableTarget, isMenuKey, nativeMenuReason, selectionPayload, usableImage, usableLink } from './context-menu-logic.js';
29
+ import { buildAppMenu } from './context-menu-model.js';
30
+ import { areaAt, registerContextMenuArea } from './context-menu-areas.js';
31
+ import { t } from './i18n.js';
32
+ import { state, emit } from './state.js';
33
+ import { actionForKey, getShortcutLabel, hasAction, runAction } from './ui-keybinds.js';
34
+ import { isGuest, hasPermission } from './ui-sync.js';
35
+ import { sendToPanel } from './ui-claude-panel.js';
36
+ import { closeMemoryCard, focusLinkedMemories, getOpenCardsSnapshot } from './ui-detail.js';
37
+ import { formatMemoryForCLI } from './ui-terminal.js';
38
+ import { fetchMemory } from './api.js';
39
+
40
+ /**
41
+ * Where the browser's menu stays: the exact elements with a menu of their own (also for a click their handler did
42
+ * not take, such as Shift+F10 on them or a moment before they are wired), the other menus themselves, code editors,
43
+ * and what is not SynaBun's page or sits above the menu. Never a whole screen or panel: the rest of a panel gets the
44
+ * app's menu. Add `data-native-contextmenu` to an element to keep the browser's menu there.
45
+ */
46
+ export const NATIVE_CONTEXTMENU_SELECTORS = [
47
+ '[data-native-contextmenu]',
48
+ '.term-viewport', '.xterm', '#term-context-menu', // terminals (docked and floating) and their menu
49
+ '#fe-tree', '.fe-ctx-flyout', // the File Explorer's tree (rows and its empty space) and its menus
50
+ '.cm-editor', '.fe-editor-menu', // a code editor anywhere; the editor's menus and palette
51
+ '#context-menu', // the 2D graph's card menu
52
+ '.explorer-ctx-menu', '.as-context-menu', // the Explorer's and the Automation Studio's menus
53
+ '.browser-canvas', // the SynaBun browser's view of another site (Back / Reload here would act on SynaBun)
54
+ '#loading-overlay', // the loading / restart screen, above the menu
55
+ ];
56
+ const OPT_OUT = NATIVE_CONTEXTMENU_SELECTORS.join(', ');
57
+ const SEARCH_MAX = 500; // a search for the selection takes its first 500 characters
58
+ const KEY_ECHO_MS = 800; // the contextmenu event a menu key sends after its keydown already opened the menu
59
+
60
+ let _installed = false;
61
+ let _keyboardOpenedAt = -Infinity;
62
+
63
+ // ═══════════════════════════════════════════
64
+ // AREAS (context-menu-areas.js; re-exported here for the pages that already import this module)
65
+ // ═══════════════════════════════════════════
66
+
67
+ export { registerContextMenuArea };
68
+
69
+ // A row of the memory Explorer.
70
+ const explorerArea = {
71
+ id: 'memory-explorer',
72
+ match(el) {
73
+ const row = el?.closest?.('.explorer-memory[data-id]');
74
+ return row ? { kind: 'memory', memory: { id: row.dataset.id } } : null;
75
+ },
76
+ };
77
+
78
+ // A memory card (ui-detail.js names its element after the memory's first 8 characters).
79
+ const cardArea = {
80
+ id: 'memory-card',
81
+ match(el) {
82
+ const card = el?.closest?.('.detail-card');
83
+ if (!card?.id) return null;
84
+ const open = getOpenCardsSnapshot().find((c) => card.id === `detail-card-${String(c.memoryId).slice(0, 8)}`);
85
+ return open ? { kind: 'memory', memory: { id: open.memoryId, card: true } } : null;
86
+ },
87
+ };
88
+
89
+ // ═══════════════════════════════════════════
90
+ // WHAT WAS CLICKED
91
+ // ═══════════════════════════════════════════
92
+
93
+ const elementOf = (node) => (node && node.nodeType !== 1 ? node.parentElement : node) || null;
94
+
95
+ // The selected text, when the right-click is on it (or the keyboard opened the menu while something is selected).
96
+ function selectionAt(el) {
97
+ const sel = window.getSelection?.();
98
+ if (!sel || sel.isCollapsed || !sel.rangeCount) return '';
99
+ const text = selectionPayload(sel.toString());
100
+ if (!text) return '';
101
+ if (!el || el === document.body || el === document.documentElement) return text;
102
+ for (let i = 0; i < sel.rangeCount; i++) {
103
+ try { if (sel.getRangeAt(i).intersectsNode(el)) return text; } catch { /* a node from another document */ }
104
+ }
105
+ return '';
106
+ }
107
+
108
+ function linkAt(el) {
109
+ const a = el?.closest?.('a[href]');
110
+ if (!a) return null;
111
+ const raw = a.getAttribute('href');
112
+ let resolved = null;
113
+ try { resolved = new URL(raw, document.baseURI).href; } catch { /* not an address */ }
114
+ return usableLink(raw, resolved);
115
+ }
116
+
117
+ function imageAt(el) {
118
+ const img = el?.closest?.('img');
119
+ return img ? usableImage(img.currentSrc || img.src) : null;
120
+ }
121
+
122
+ /** What the menu is about for an element (null: the page itself). */
123
+ export function contextAt(el) {
124
+ return { selection: selectionAt(el), link: linkAt(el), image: imageAt(el), area: areaAt(el) };
125
+ }
126
+
127
+ // ═══════════════════════════════════════════
128
+ // WHAT THE MENU CAN DO (the app's own functions)
129
+ // ═══════════════════════════════════════════
130
+
131
+ async function copyText(text) {
132
+ const value = String(text ?? '');
133
+ try {
134
+ if (navigator.clipboard?.writeText) { await navigator.clipboard.writeText(value); return true; }
135
+ } catch { /* not allowed here (an address that is not secure): the fallback below */ }
136
+ const area = document.createElement('textarea');
137
+ area.value = value;
138
+ area.setAttribute('readonly', '');
139
+ area.style.cssText = 'position:fixed;top:-1000px;left:0;opacity:0;';
140
+ document.body.appendChild(area);
141
+ area.select();
142
+ let ok = false;
143
+ try { ok = document.execCommand('copy'); } catch { /* nothing more to try */ }
144
+ area.remove();
145
+ return ok;
146
+ }
147
+
148
+ function toggleFullscreen() {
149
+ if (document.fullscreenElement) return document.exitFullscreen?.();
150
+ return document.documentElement.requestFullscreen?.();
151
+ }
152
+
153
+ // The search bar's own path: its input event shows "Searching…", waits its debounce and searches.
154
+ function searchMemories(text) {
155
+ const query = selectionPayload(text, SEARCH_MAX);
156
+ const input = document.getElementById('search-input');
157
+ if (!input || !query) return;
158
+ input.value = query;
159
+ input.dispatchEvent(new Event('input', { bubbles: true }));
160
+ }
161
+
162
+ const findNode = (id) => state.allNodes?.find((n) => n.id === id) || null;
163
+
164
+ // A memory the page has (the slim graph copy is enough to open it), else the one the server has.
165
+ async function withMemory(id, fn) {
166
+ const node = findNode(id);
167
+ if (node) return fn(node);
168
+ const full = await fetchMemory(id).catch(() => null);
169
+ if (full?.payload) return fn({ id, payload: full.payload });
170
+ return undefined;
171
+ }
172
+
173
+ // The AI panel gets the whole memory (the graph's copy of its content is cut at 500 characters).
174
+ async function sendMemory(id) {
175
+ const full = await fetchMemory(id).catch(() => null);
176
+ const node = full?.payload ? { id, payload: full.payload } : findNode(id);
177
+ if (node) await sendToPanel(formatMemoryForCLI(node));
178
+ }
179
+
180
+ export const ACTIONS = {
181
+ back: () => history.back(),
182
+ forward: () => history.forward(),
183
+ reload: () => location.reload(),
184
+ copyText,
185
+ toggleFullscreen,
186
+ openInNewTab: (href) => { window.open(href, '_blank', 'noopener,noreferrer'); },
187
+ searchMemories,
188
+ sendText: (text) => sendToPanel(text),
189
+ runAction: (actionId) => runAction(actionId),
190
+ press: (id) => document.getElementById(id)?.click(),
191
+ emit: (name, payload) => emit(name, payload),
192
+ openMemory: (id) => withMemory(id, (node) => emit('node-selected', node)),
193
+ showLinked: (id) => withMemory(id, (node) => { emit('node-selected', node); focusLinkedMemories(node.id); }),
194
+ sendMemory,
195
+ closeCard: (id) => closeMemoryCard(id),
196
+ };
197
+
198
+ function canGoBack() {
199
+ const nav = window.navigation;
200
+ return typeof nav?.canGoBack === 'boolean' ? nav.canGoBack : history.length > 1;
201
+ }
202
+
203
+ function canGoForward() {
204
+ const nav = window.navigation;
205
+ return typeof nav?.canGoForward === 'boolean' ? nav.canGoForward : true; // unknown without the Navigation API
206
+ }
207
+
208
+ /** The menu model's environment as the page is now (labels, keys and states are read at every open). */
209
+ export function menuEnv() {
210
+ return {
211
+ t,
212
+ shortcut: (actionId) => getShortcutLabel(actionId),
213
+ hasAction,
214
+ hasElement: (id) => !!document.getElementById(id),
215
+ isActive: (id) => !!document.getElementById(id)?.classList.contains('active'),
216
+ allowed: (perm) => !isGuest() || hasPermission(perm),
217
+ appIcon: (id) => (id && document.getElementById(id)?.querySelector('.menu-icon')?.innerHTML) || '',
218
+ page: {
219
+ url: location.href,
220
+ canGoBack: canGoBack(),
221
+ canGoForward: canGoForward(),
222
+ fullscreen: !!document.fullscreenElement,
223
+ fullscreenEnabled: document.fullscreenEnabled !== false && typeof document.documentElement.requestFullscreen === 'function',
224
+ },
225
+ act: ACTIONS,
226
+ };
227
+ }
228
+
229
+ // ═══════════════════════════════════════════
230
+ // OPENING
231
+ // ═══════════════════════════════════════════
232
+
233
+ // One menu at a time: the menubar, the dropdowns that listen for it, and the menus that only close on a click.
234
+ function closeOtherMenus() {
235
+ emit('panel:close-all-dropdowns');
236
+ document.getElementById('term-context-menu')?.classList.remove('open');
237
+ document.getElementById('context-menu')?.classList.remove('open');
238
+ document.querySelectorAll('.as-context-menu, .explorer-ctx-menu').forEach((el) => el.remove());
239
+ }
240
+
241
+ function open(ctx, placement) {
242
+ const items = buildAppMenu(ctx, menuEnv());
243
+ closeOtherMenus();
244
+ return openContextMenu({ items, label: t('contextMenu.label'), ...placement });
245
+ }
246
+
247
+ /**
248
+ * Open the app's menu from an area that detects its own right-click (the memory map, where a right-drag pans):
249
+ * what is at `target`, with `area` in place of what the registered areas would say.
250
+ * @param {{ x?: number, y?: number, target?: Element | null, area?: object | null, keyboard?: boolean,
251
+ * anchorRect?: DOMRect | null, returnFocus?: Element | null }} o
252
+ */
253
+ export function openAppContextMenu({ x, y, target = null, area = null, keyboard = false, anchorRect = null, returnFocus } = {}) {
254
+ const el = elementOf(target);
255
+ const ctx = contextAt(el);
256
+ if (area) ctx.area = area;
257
+ return open(ctx, { x, y, anchorRect, keyboard, returnFocus: returnFocus === undefined ? document.activeElement : returnFocus });
258
+ }
259
+
260
+ function onContextMenu(event) {
261
+ // The menu key's own contextmenu event, after its keydown opened the menu.
262
+ if (isContextMenuOpen() && performance.now() - _keyboardOpenedAt < KEY_ECHO_MS) { event.preventDefault(); return; }
263
+ const el = elementOf(event.target);
264
+ const reason = nativeMenuReason(event, {
265
+ inOwnMenu: !!el?.closest?.('.app-ctx-menu'),
266
+ editable: isEditableTarget(el),
267
+ optedOut: !!el?.closest?.(OPT_OUT),
268
+ });
269
+ if (reason === 'own-menu') { event.preventDefault(); return; }
270
+ if (reason) return;
271
+ event.preventDefault();
272
+ open(contextAt(el), { x: event.clientX, y: event.clientY, keyboard: false, returnFocus: document.activeElement });
273
+ }
274
+
275
+ function onKeyDown(event) {
276
+ if (event.defaultPrevented || !isMenuKey(event) || isContextMenuOpen() || actionForKey(event)) return;
277
+ const active = document.activeElement;
278
+ const el = active && active !== document.body && active !== document.documentElement ? active : null;
279
+ if (el && (isEditableTarget(el) || el.closest(OPT_OUT) || el.closest('.app-ctx-menu'))) return;
280
+ event.preventDefault();
281
+ _keyboardOpenedAt = performance.now();
282
+ open(contextAt(el), { anchorRect: el?.getBoundingClientRect() || null, keyboard: true, returnFocus: el });
283
+ }
284
+
285
+ /** Install the app's right-click menu (once per page). */
286
+ export function initAppContextMenu() {
287
+ if (_installed) return;
288
+ _installed = true;
289
+ registerContextMenuArea(explorerArea);
290
+ registerContextMenuArea(cardArea);
291
+ // Bubble phase at the window: every handler of the page has had the event first.
292
+ window.addEventListener('contextmenu', onContextMenu);
293
+ // A menu key the user bound to an action stays that action (actionForKey), whichever listener runs first.
294
+ document.addEventListener('keydown', onKeyDown);
295
+ }