synabun 2.0.10 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (656) hide show
  1. package/CHANGELOG.md +207 -0
  2. package/README.md +25 -2
  3. package/THIRD-PARTY-LICENSES.md +22 -0
  4. package/bin/synabun.js +71 -24
  5. package/docs/whatsapp.md +13 -13
  6. package/hooks/claude-code/pre-websearch.mjs +12 -1
  7. package/hooks/claude-code/shared.mjs +5 -0
  8. package/hooks/claude-code/stop.mjs +1 -1
  9. package/lib/claude-hooks.js +172 -18
  10. package/lib/client-config-repair.js +30 -17
  11. package/lib/desktop-app.js +7 -1
  12. package/lib/external-tools.js +7 -6
  13. package/lib/first-launch-protection.js +57 -12
  14. package/lib/mcp-dist.js +176 -0
  15. package/lib/release-npm-ci.mjs +138 -0
  16. package/lib/release-publish.mjs +91 -0
  17. package/lib/release-scan.mjs +50 -0
  18. package/lib/server-crash-record.js +123 -0
  19. package/lib/server-exit.js +318 -0
  20. package/lib/server-supervisor.js +508 -0
  21. package/lib/start-launcher.js +37 -4
  22. package/lib/tools-cli.js +45 -0
  23. package/lib/update-snapshot.js +302 -0
  24. package/lib/virustotal.mjs +203 -0
  25. package/lib/windows-crash-event.js +269 -0
  26. package/mcp-server/dist/http.d.ts +20 -1
  27. package/mcp-server/dist/http.d.ts.map +1 -1
  28. package/mcp-server/dist/http.js +59 -12
  29. package/mcp-server/dist/http.js.map +1 -1
  30. package/mcp-server/dist/index.d.ts +33 -27
  31. package/mcp-server/dist/index.d.ts.map +1 -1
  32. package/mcp-server/dist/index.js +128 -143
  33. package/mcp-server/dist/index.js.map +1 -1
  34. package/mcp-server/dist/preload.js +1 -1
  35. package/mcp-server/dist/preload.js.map +1 -1
  36. package/mcp-server/dist/services/budget-judgments.d.ts +1 -1
  37. package/mcp-server/dist/services/budget-judgments.d.ts.map +1 -1
  38. package/mcp-server/dist/services/budget-judgments.js +5 -3
  39. package/mcp-server/dist/services/budget-judgments.js.map +1 -1
  40. package/mcp-server/dist/services/codex-config-heal.d.ts +6 -2
  41. package/mcp-server/dist/services/codex-config-heal.d.ts.map +1 -1
  42. package/mcp-server/dist/services/codex-config-heal.js +81 -28
  43. package/mcp-server/dist/services/codex-config-heal.js.map +1 -1
  44. package/mcp-server/dist/services/identity.d.ts +2 -2
  45. package/mcp-server/dist/services/identity.js +2 -2
  46. package/mcp-server/dist/services/memory-judge-backfill.d.ts +6 -0
  47. package/mcp-server/dist/services/memory-judge-backfill.d.ts.map +1 -1
  48. package/mcp-server/dist/services/memory-judge-backfill.js +7 -1
  49. package/mcp-server/dist/services/memory-judge-backfill.js.map +1 -1
  50. package/mcp-server/dist/services/memory-sessions.d.ts +1 -1
  51. package/mcp-server/dist/services/memory-sessions.d.ts.map +1 -1
  52. package/mcp-server/dist/services/memory-sessions.js +28 -2
  53. package/mcp-server/dist/services/memory-sessions.js.map +1 -1
  54. package/mcp-server/dist/services/neural-interface.d.ts +18 -11
  55. package/mcp-server/dist/services/neural-interface.d.ts.map +1 -1
  56. package/mcp-server/dist/services/neural-interface.js +67 -11
  57. package/mcp-server/dist/services/neural-interface.js.map +1 -1
  58. package/mcp-server/dist/services/server-instructions.d.ts +7 -2
  59. package/mcp-server/dist/services/server-instructions.d.ts.map +1 -1
  60. package/mcp-server/dist/services/server-instructions.js +22 -63
  61. package/mcp-server/dist/services/server-instructions.js.map +1 -1
  62. package/mcp-server/dist/services/tool-catalog.d.ts +120 -0
  63. package/mcp-server/dist/services/tool-catalog.d.ts.map +1 -0
  64. package/mcp-server/dist/services/tool-catalog.js +339 -0
  65. package/mcp-server/dist/services/tool-catalog.js.map +1 -0
  66. package/mcp-server/dist/services/tool-list-refresh-barrier.d.ts +12 -0
  67. package/mcp-server/dist/services/tool-list-refresh-barrier.d.ts.map +1 -0
  68. package/mcp-server/dist/services/tool-list-refresh-barrier.js +40 -0
  69. package/mcp-server/dist/services/tool-list-refresh-barrier.js.map +1 -0
  70. package/mcp-server/dist/services/tool-list.d.ts +108 -0
  71. package/mcp-server/dist/services/tool-list.d.ts.map +1 -0
  72. package/mcp-server/dist/services/tool-list.js +334 -0
  73. package/mcp-server/dist/services/tool-list.js.map +1 -0
  74. package/mcp-server/dist/services/tool-runtime.d.ts +161 -0
  75. package/mcp-server/dist/services/tool-runtime.d.ts.map +1 -0
  76. package/mcp-server/dist/services/tool-runtime.js +400 -0
  77. package/mcp-server/dist/services/tool-runtime.js.map +1 -0
  78. package/mcp-server/dist/services/typesafe-config.js +1 -1
  79. package/mcp-server/dist/services/typesafe-config.js.map +1 -1
  80. package/mcp-server/dist/services/whiteboard-geometry.d.ts +26 -2
  81. package/mcp-server/dist/services/whiteboard-geometry.d.ts.map +1 -1
  82. package/mcp-server/dist/services/whiteboard-geometry.js +91 -8
  83. package/mcp-server/dist/services/whiteboard-geometry.js.map +1 -1
  84. package/mcp-server/dist/tools/agents.d.ts +14 -14
  85. package/mcp-server/dist/tools/agents.d.ts.map +1 -1
  86. package/mcp-server/dist/tools/agents.js +29 -19
  87. package/mcp-server/dist/tools/agents.js.map +1 -1
  88. package/mcp-server/dist/tools/browser-batch.d.ts +3 -3
  89. package/mcp-server/dist/tools/choice.d.ts +6 -0
  90. package/mcp-server/dist/tools/choice.d.ts.map +1 -1
  91. package/mcp-server/dist/tools/choice.js +18 -13
  92. package/mcp-server/dist/tools/choice.js.map +1 -1
  93. package/mcp-server/dist/tools/git-tools.js +2 -2
  94. package/mcp-server/dist/tools/git-tools.js.map +1 -1
  95. package/mcp-server/dist/tools/image-tools.d.ts +1 -1
  96. package/mcp-server/dist/tools/image-tools.js +1 -1
  97. package/mcp-server/dist/tools/morelogin.d.ts.map +1 -1
  98. package/mcp-server/dist/tools/morelogin.js +9 -6
  99. package/mcp-server/dist/tools/morelogin.js.map +1 -1
  100. package/mcp-server/dist/tools/skill-tools.d.ts +505 -0
  101. package/mcp-server/dist/tools/skill-tools.d.ts.map +1 -0
  102. package/mcp-server/dist/tools/skill-tools.js +642 -0
  103. package/mcp-server/dist/tools/skill-tools.js.map +1 -0
  104. package/mcp-server/dist/tools/skill.d.ts +7 -0
  105. package/mcp-server/dist/tools/skill.d.ts.map +1 -0
  106. package/mcp-server/dist/tools/skill.js +11 -0
  107. package/mcp-server/dist/tools/skill.js.map +1 -0
  108. package/mcp-server/dist/tools/tool-groups.d.ts +68 -0
  109. package/mcp-server/dist/tools/tool-groups.d.ts.map +1 -0
  110. package/mcp-server/dist/tools/tool-groups.js +147 -0
  111. package/mcp-server/dist/tools/tool-groups.js.map +1 -0
  112. package/mcp-server/dist/tools/whiteboard-format.d.ts.map +1 -1
  113. package/mcp-server/dist/tools/whiteboard-format.js +7 -4
  114. package/mcp-server/dist/tools/whiteboard-format.js.map +1 -1
  115. package/mcp-server/dist/tools/whiteboard-tools.d.ts +64 -13
  116. package/mcp-server/dist/tools/whiteboard-tools.d.ts.map +1 -1
  117. package/mcp-server/dist/tools/whiteboard-tools.js +30 -5
  118. package/mcp-server/dist/tools/whiteboard-tools.js.map +1 -1
  119. package/mcp-server/package-lock.json +2 -2
  120. package/mcp-server/package.json +1 -1
  121. package/mcp-server/src/http.ts +75 -12
  122. package/mcp-server/src/index.ts +147 -154
  123. package/mcp-server/src/preload.ts +12 -12
  124. package/mcp-server/src/services/budget-judgments.ts +5 -3
  125. package/mcp-server/src/services/codex-config-heal.ts +80 -29
  126. package/mcp-server/src/services/identity.ts +2 -2
  127. package/mcp-server/src/services/memory-judge-backfill.ts +7 -1
  128. package/mcp-server/src/services/memory-sessions.ts +24 -3
  129. package/mcp-server/src/services/neural-interface.ts +81 -21
  130. package/mcp-server/src/services/server-instructions.ts +29 -64
  131. package/mcp-server/src/services/tool-catalog.ts +403 -0
  132. package/mcp-server/src/services/tool-list-refresh-barrier.ts +33 -0
  133. package/mcp-server/src/services/tool-list.ts +410 -0
  134. package/mcp-server/src/services/tool-runtime.ts +457 -0
  135. package/mcp-server/src/services/typesafe-config.ts +1 -1
  136. package/mcp-server/src/services/whiteboard-geometry.ts +94 -9
  137. package/mcp-server/src/tools/agents.ts +29 -20
  138. package/mcp-server/src/tools/choice.ts +17 -12
  139. package/mcp-server/src/tools/git-tools.ts +2 -2
  140. package/mcp-server/src/tools/image-tools.ts +1 -1
  141. package/mcp-server/src/tools/morelogin.ts +6 -4
  142. package/mcp-server/src/tools/skill-tools.ts +592 -0
  143. package/mcp-server/src/tools/skill.ts +13 -0
  144. package/mcp-server/src/tools/tool-groups.ts +164 -0
  145. package/mcp-server/src/tools/whiteboard-format.ts +9 -3
  146. package/mcp-server/src/tools/whiteboard-tools.ts +39 -5
  147. package/neural-interface/i18n/en.json +3953 -228
  148. package/neural-interface/i18n/pt-BR.json +3901 -179
  149. package/neural-interface/lib/agent-sandbox-elevation.js +6 -0
  150. package/neural-interface/lib/antigravity/acp-client-host.js +554 -0
  151. package/neural-interface/lib/antigravity/acp-connection.js +299 -0
  152. package/neural-interface/lib/antigravity/bypass.js +100 -0
  153. package/neural-interface/lib/antigravity/catalog.js +273 -0
  154. package/neural-interface/lib/antigravity/home.js +260 -0
  155. package/neural-interface/lib/antigravity/migrate-gemini.js +139 -0
  156. package/neural-interface/lib/antigravity/panel-bridge.js +1058 -0
  157. package/neural-interface/lib/antigravity/policy-hook.mjs +78 -0
  158. package/neural-interface/lib/antigravity/policy.js +74 -0
  159. package/neural-interface/lib/antigravity/tool-call.js +178 -0
  160. package/neural-interface/lib/antigravity/transcripts.js +252 -0
  161. package/neural-interface/lib/antigravity/usage.js +43 -0
  162. package/neural-interface/lib/assistant-api.js +128 -28
  163. package/neural-interface/lib/assistant-brains/antigravity.js +423 -0
  164. package/neural-interface/lib/assistant-brains/claude.js +4 -3
  165. package/neural-interface/lib/assistant-brains/codex-browser-policy-hook.mjs +12 -2
  166. package/neural-interface/lib/assistant-brains/codex-route-gate-hook.mjs +32 -9
  167. package/neural-interface/lib/assistant-brains/codex.js +9 -5
  168. package/neural-interface/lib/assistant-brains/opencode.js +120 -54
  169. package/neural-interface/lib/assistant-brains/opencode2-browser-policy/index.js +28 -13
  170. package/neural-interface/lib/assistant-brains/opencode2-route-gate/index.js +59 -19
  171. package/neural-interface/lib/assistant-budget-planner.js +7 -3
  172. package/neural-interface/lib/assistant-budget-split.js +42 -15
  173. package/neural-interface/lib/assistant-catalog.js +81 -15
  174. package/neural-interface/lib/assistant-config.js +6 -3
  175. package/neural-interface/lib/assistant-dispatch.js +1073 -200
  176. package/neural-interface/lib/assistant-envelope.js +156 -2
  177. package/neural-interface/lib/assistant-evidence.js +80 -0
  178. package/neural-interface/lib/assistant-hidden-models.js +7 -5
  179. package/neural-interface/lib/assistant-persona.js +93 -19
  180. package/neural-interface/lib/assistant-plan-permissions.js +25 -9
  181. package/neural-interface/lib/assistant-route-gate-codex.js +3 -0
  182. package/neural-interface/lib/assistant-route-gate.js +6 -4
  183. package/neural-interface/lib/assistant-router.js +245 -38
  184. package/neural-interface/lib/assistant-runtime.js +214 -30
  185. package/neural-interface/lib/assistant-task-prompt.js +87 -21
  186. package/neural-interface/lib/assistant-tools.js +51 -0
  187. package/neural-interface/lib/assistant-usage.js +29 -0
  188. package/neural-interface/lib/backup-service.js +626 -4
  189. package/neural-interface/lib/backup-zip-reader.js +10 -5
  190. package/neural-interface/lib/backup-zip-writer.js +257 -0
  191. package/neural-interface/lib/browser-execution.js +10 -2
  192. package/neural-interface/lib/browser-guard-cdp.js +84 -0
  193. package/neural-interface/lib/browser-network-guard.js +476 -0
  194. package/neural-interface/lib/browser-policy-roots.js +64 -0
  195. package/neural-interface/lib/browser-tool-policy.js +198 -38
  196. package/neural-interface/lib/claude-agent-bridge.js +11 -2
  197. package/neural-interface/lib/claude-history-cache.js +210 -0
  198. package/neural-interface/lib/claude-hooks-status.js +103 -0
  199. package/neural-interface/lib/claude-model-catalog.js +5 -1
  200. package/neural-interface/lib/claude-temporary.js +5 -11
  201. package/neural-interface/lib/cli-install-api.js +1 -1
  202. package/neural-interface/lib/cli-install.js +163 -154
  203. package/neural-interface/lib/cli-resolver.js +13 -3
  204. package/neural-interface/lib/cli-update-planner.js +52 -41
  205. package/neural-interface/lib/cloudflared/tunnel.js +42 -2
  206. package/neural-interface/lib/codex-mcp-approvals.js +11 -0
  207. package/neural-interface/lib/codex-rollout-reader.js +52 -0
  208. package/neural-interface/lib/codex-worker-app-server.js +191 -0
  209. package/neural-interface/lib/confined-fs.js +30 -3
  210. package/neural-interface/lib/crash-notice-api.js +98 -0
  211. package/neural-interface/lib/editor-completion-opencode.js +68 -68
  212. package/neural-interface/lib/editor-git-api.js +3 -20
  213. package/neural-interface/lib/exec-loop-command.js +13 -10
  214. package/neural-interface/lib/file-explorer-api.js +74 -40
  215. package/neural-interface/lib/file-explorer-watch.js +9 -3
  216. package/neural-interface/lib/git-bash/install.js +52 -6
  217. package/neural-interface/lib/git-bash/manager.js +59 -17
  218. package/neural-interface/lib/git-bash/pins.js +12 -0
  219. package/neural-interface/lib/git-read.js +2 -2
  220. package/neural-interface/lib/git-status-runner.js +390 -0
  221. package/neural-interface/lib/git-status-watchdog.js +40 -0
  222. package/neural-interface/lib/greeting/budgets.js +1 -0
  223. package/neural-interface/lib/greeting/engine.js +2 -2
  224. package/neural-interface/lib/greeting/sources.js +10 -12
  225. package/neural-interface/lib/greeting/writer.js +1 -1
  226. package/neural-interface/lib/http-guards.js +8 -2
  227. package/neural-interface/lib/install-details.js +4 -1
  228. package/neural-interface/lib/mcp-agent-servers.js +67 -0
  229. package/neural-interface/lib/mcp-client-config.js +35 -33
  230. package/neural-interface/lib/mcp-external-servers.js +332 -0
  231. package/neural-interface/lib/mcp-installer.js +2 -1
  232. package/neural-interface/lib/{mcp-profile-refresh-coordinator.js → mcp-tools-refresh-coordinator.js} +4 -4
  233. package/neural-interface/lib/memory-session-capture.js +17 -3
  234. package/neural-interface/lib/morelogin.js +177 -25
  235. package/neural-interface/lib/native-loop-providers.js +965 -66
  236. package/neural-interface/lib/native-loop-runtime.js +290 -42
  237. package/neural-interface/lib/opencode-config.js +557 -0
  238. package/neural-interface/lib/opencode-db-schema.js +17 -34
  239. package/neural-interface/lib/opencode-history.js +48 -218
  240. package/neural-interface/lib/opencode-mcp-ready.js +108 -0
  241. package/neural-interface/lib/opencode-native-boundary.js +53 -0
  242. package/neural-interface/lib/opencode-protocol.js +249 -112
  243. package/neural-interface/lib/opencode-runtime-config.js +32 -22
  244. package/neural-interface/lib/opencode-serve-records.js +39 -21
  245. package/neural-interface/lib/opencode-v2-client.js +48 -153
  246. package/neural-interface/lib/opencode-v2-ws-requests.js +36 -210
  247. package/neural-interface/lib/opencode-worker-data.js +27 -0
  248. package/neural-interface/lib/opencode2-client.js +73 -37
  249. package/neural-interface/lib/opencode2-proxy.js +23 -63
  250. package/neural-interface/lib/opencode2-translate.js +51 -2
  251. package/neural-interface/lib/owner-authority.js +249 -0
  252. package/neural-interface/lib/page-session.js +275 -0
  253. package/neural-interface/lib/path-confine.js +12 -9
  254. package/neural-interface/lib/peer-identity.js +793 -0
  255. package/neural-interface/lib/pty-host/core.js +28 -1
  256. package/neural-interface/lib/pty-host/lifetime.js +12 -0
  257. package/neural-interface/lib/pty-host/manager.js +12 -1
  258. package/neural-interface/lib/remote-policy.js +1 -1
  259. package/neural-interface/lib/request-gate.js +20 -2
  260. package/neural-interface/lib/rulesets/api.js +7 -6
  261. package/neural-interface/lib/rulesets/fs-safe.js +1 -1
  262. package/neural-interface/lib/rulesets/installer.js +180 -36
  263. package/neural-interface/lib/rulesets/json-edit.js +1 -1
  264. package/neural-interface/lib/rulesets/render.js +1 -1
  265. package/neural-interface/lib/session-cache-builder.js +81 -31
  266. package/neural-interface/lib/session-title-generator.js +58 -36
  267. package/neural-interface/lib/skills/api-v2.js +495 -0
  268. package/neural-interface/lib/skills/bundle.js +418 -0
  269. package/neural-interface/lib/skills/catalog.js +298 -0
  270. package/neural-interface/lib/skills/creation-api.js +191 -0
  271. package/neural-interface/lib/skills/creation-brief.js +247 -0
  272. package/neural-interface/lib/skills/creation-sources.js +285 -0
  273. package/neural-interface/lib/skills/creation.js +843 -0
  274. package/neural-interface/lib/skills/deploy.js +569 -0
  275. package/neural-interface/lib/skills/digest.js +119 -0
  276. package/neural-interface/lib/skills/discover.js +111 -0
  277. package/neural-interface/lib/skills/draft-confinement.js +216 -0
  278. package/neural-interface/lib/skills/eval-confinement.js +399 -0
  279. package/neural-interface/lib/skills/eval-sandbox.js +280 -0
  280. package/neural-interface/lib/skills/eval-trace.js +135 -0
  281. package/neural-interface/lib/skills/evals-api.js +212 -0
  282. package/neural-interface/lib/skills/evals.js +1573 -0
  283. package/neural-interface/lib/skills/export.js +203 -0
  284. package/neural-interface/lib/skills/frontmatter.js +64 -0
  285. package/neural-interface/lib/skills/health.js +75 -0
  286. package/neural-interface/lib/skills/json-edit.js +165 -0
  287. package/neural-interface/lib/skills/known-bridge-digests.json +441 -0
  288. package/neural-interface/lib/skills/known-bridges.js +96 -0
  289. package/neural-interface/lib/skills/library.js +823 -0
  290. package/neural-interface/lib/skills/local-store.js +21 -0
  291. package/neural-interface/lib/skills/migration.js +433 -0
  292. package/neural-interface/lib/skills/operations.js +45 -0
  293. package/neural-interface/lib/skills/ownership.js +427 -0
  294. package/neural-interface/lib/skills/packages.js +88 -0
  295. package/neural-interface/lib/skills/reviews.js +212 -0
  296. package/neural-interface/lib/skills/revision.js +80 -0
  297. package/neural-interface/lib/skills/roots.js +269 -0
  298. package/neural-interface/lib/skills/runtime-checks.js +358 -0
  299. package/neural-interface/lib/skills/scan-assets.js +252 -0
  300. package/neural-interface/lib/skills/scan-context.js +26 -0
  301. package/neural-interface/lib/skills/scan-shell.js +324 -0
  302. package/neural-interface/lib/skills/scan.js +364 -0
  303. package/neural-interface/lib/skills/scanners.js +54 -0
  304. package/neural-interface/lib/skills/service.js +530 -0
  305. package/neural-interface/lib/skills/telemetry.js +119 -0
  306. package/neural-interface/lib/sqlite-integrity-worker.js +22 -0
  307. package/neural-interface/lib/synabun-version.js +1 -1
  308. package/neural-interface/lib/system-activity.js +1 -1
  309. package/neural-interface/lib/tool-lists.js +124 -0
  310. package/neural-interface/lib/whatsapp/brain.js +7 -3
  311. package/neural-interface/lib/whatsapp/bridge.js +6 -3
  312. package/neural-interface/lib/whatsapp/cards.js +22 -9
  313. package/neural-interface/lib/whatsapp/config.js +1 -1
  314. package/neural-interface/lib/worker-confinement.js +1268 -0
  315. package/neural-interface/lib/worker-guard-setting.js +56 -0
  316. package/neural-interface/lib/worker-mcp-channel.js +175 -0
  317. package/neural-interface/lib/worker-question.js +74 -0
  318. package/neural-interface/lib/worker-relay-ports.js +227 -0
  319. package/neural-interface/lib/worker-resume.js +238 -0
  320. package/neural-interface/lib/worker-sandbox.js +329 -0
  321. package/neural-interface/package-lock.json +34 -12
  322. package/neural-interface/package.json +3 -2
  323. package/neural-interface/public/index.html +3 -1
  324. package/neural-interface/public/index2d.html +19 -11
  325. package/neural-interface/public/onboarding.html +3 -3
  326. package/neural-interface/public/shared/account-menu.js +8 -5
  327. package/neural-interface/public/shared/agent-runtime-options.js +125 -31
  328. package/neural-interface/public/shared/agy/agy-bypass.js +47 -0
  329. package/neural-interface/public/shared/agy/agy-client.js +266 -0
  330. package/neural-interface/public/shared/agy/agy-commands.js +120 -0
  331. package/neural-interface/public/shared/agy/agy-copy.js +326 -0
  332. package/neural-interface/public/shared/agy/agy-diff.js +161 -0
  333. package/neural-interface/public/shared/agy/agy-events.js +469 -0
  334. package/neural-interface/public/shared/agy/agy-greeting.js +26 -0
  335. package/neural-interface/public/shared/agy/agy-options.js +232 -0
  336. package/neural-interface/public/shared/agy/agy-panel.js +2543 -0
  337. package/neural-interface/public/shared/agy/agy-render.js +392 -0
  338. package/neural-interface/public/shared/agy/agy-setup.js +149 -0
  339. package/neural-interface/public/shared/agy/agy-styles.js +604 -0
  340. package/neural-interface/public/shared/agy/agy-tabs-logic.js +181 -0
  341. package/neural-interface/public/shared/api.js +1527 -1336
  342. package/neural-interface/public/shared/app-frame.js +192 -0
  343. package/neural-interface/public/shared/assistant/asst-agents-dock.js +36 -6
  344. package/neural-interface/public/shared/assistant/asst-api.js +1 -1
  345. package/neural-interface/public/shared/assistant/asst-ask-styles.js +270 -0
  346. package/neural-interface/public/shared/assistant/asst-ask-tail.js +118 -0
  347. package/neural-interface/public/shared/assistant/asst-ask.js +397 -0
  348. package/neural-interface/public/shared/assistant/asst-brain-picker.js +105 -44
  349. package/neural-interface/public/shared/assistant/asst-budget.js +5 -4
  350. package/neural-interface/public/shared/assistant/asst-control.js +205 -26
  351. package/neural-interface/public/shared/assistant/asst-followups-card.js +383 -0
  352. package/neural-interface/public/shared/assistant/asst-followups.js +417 -0
  353. package/neural-interface/public/shared/assistant/asst-hosts.js +16 -7
  354. package/neural-interface/public/shared/assistant/asst-limit-dock.js +45 -0
  355. package/neural-interface/public/shared/assistant/asst-limit-wait.js +327 -0
  356. package/neural-interface/public/shared/assistant/asst-limit.js +168 -0
  357. package/neural-interface/public/shared/assistant/asst-mascot.js +49 -12
  358. package/neural-interface/public/shared/assistant/asst-menu.js +7 -6
  359. package/neural-interface/public/shared/assistant/asst-panel.js +151 -19
  360. package/neural-interface/public/shared/assistant/asst-rack-styles.js +66 -49
  361. package/neural-interface/public/shared/assistant/asst-render.js +445 -82
  362. package/neural-interface/public/shared/assistant/asst-route.js +304 -53
  363. package/neural-interface/public/shared/assistant/asst-routes-editor.js +9 -8
  364. package/neural-interface/public/shared/assistant/asst-scenes.js +56 -1
  365. package/neural-interface/public/shared/assistant/asst-sidepanel.js +117 -10
  366. package/neural-interface/public/shared/assistant/asst-slash.js +17 -9
  367. package/neural-interface/public/shared/assistant/asst-state.js +87 -24
  368. package/neural-interface/public/shared/assistant/asst-stop.js +127 -0
  369. package/neural-interface/public/shared/assistant/asst-styles.js +93 -21
  370. package/neural-interface/public/shared/assistant/asst-tool-kinds.js +190 -23
  371. package/neural-interface/public/shared/assistant/asst-usage.js +2 -1
  372. package/neural-interface/public/shared/automation-context.js +5 -2
  373. package/neural-interface/public/shared/cc-dropdown.js +89 -19
  374. package/neural-interface/public/shared/cdx/cdx-context-menu.js +10 -9
  375. package/neural-interface/public/shared/cdx/cdx-copy.js +16 -0
  376. package/neural-interface/public/shared/cdx/cdx-output-model.js +22 -1
  377. package/neural-interface/public/shared/cdx/cdx-output.js +34 -10
  378. package/neural-interface/public/shared/cdx/cdx-panel.js +59 -151
  379. package/neural-interface/public/shared/cdx/cdx-preview.js +12 -0
  380. package/neural-interface/public/shared/cdx/cdx-protocol.js +39 -11
  381. package/neural-interface/public/shared/cdx/cdx-render.js +57 -38
  382. package/neural-interface/public/shared/cdx/cdx-requests.js +14 -4
  383. package/neural-interface/public/shared/cdx/cdx-skill-hints.js +54 -0
  384. package/neural-interface/public/shared/cdx/cdx-styles.js +15 -3
  385. package/neural-interface/public/shared/cdx/cdx-tabs.js +127 -44
  386. package/neural-interface/public/shared/cdx/cdx-ws.js +0 -1
  387. package/neural-interface/public/shared/cli-install-controller.js +218 -0
  388. package/neural-interface/public/shared/cli-install-view.js +11 -12
  389. package/neural-interface/public/shared/cli-status.js +11 -10
  390. package/neural-interface/public/shared/constants.js +5 -4
  391. package/neural-interface/public/shared/context-menu-areas.js +34 -0
  392. package/neural-interface/public/shared/context-menu-logic.js +243 -0
  393. package/neural-interface/public/shared/context-menu-model.js +367 -0
  394. package/neural-interface/public/shared/context-menu.js +372 -0
  395. package/neural-interface/public/shared/cp/cp-context-menu.js +10 -9
  396. package/neural-interface/public/shared/cp/cp-restore.js +162 -0
  397. package/neural-interface/public/shared/cp/cp-tool-cards.js +10 -3
  398. package/neural-interface/public/shared/crash-notice-view.js +168 -0
  399. package/neural-interface/public/shared/desktop-bridge.js +17 -0
  400. package/neural-interface/public/shared/desktop-titlebar-view.js +12 -0
  401. package/neural-interface/public/shared/desktop-titlebar.js +13 -4
  402. package/neural-interface/public/shared/desktop-update-view.js +21 -0
  403. package/neural-interface/public/shared/editor/editor-panel-logic.js +2 -2
  404. package/neural-interface/public/shared/explorer/fx-api.js +4 -4
  405. package/neural-interface/public/shared/explorer/fx-links.js +3 -3
  406. package/neural-interface/public/shared/explorer/fx-logic.js +1 -1
  407. package/neural-interface/public/shared/explorer/fx-main.js +48 -16
  408. package/neural-interface/public/shared/explorer/fx-tree.js +1 -0
  409. package/neural-interface/public/shared/greeting/greeting-card.js +2 -2
  410. package/neural-interface/public/shared/greeting/greeting-view.js +1 -0
  411. package/neural-interface/public/shared/html-shell.js +30 -15
  412. package/neural-interface/public/shared/i18n.js +2 -0
  413. package/neural-interface/public/shared/ocp-v2/ocp-v2-approvals.js +7 -7
  414. package/neural-interface/public/shared/ocp-v2/ocp-v2-binding.js +4 -4
  415. package/neural-interface/public/shared/ocp-v2/ocp-v2-changes-logic.js +3 -101
  416. package/neural-interface/public/shared/ocp-v2/ocp-v2-childpanel.js +2 -0
  417. package/neural-interface/public/shared/ocp-v2/ocp-v2-compact-button.js +1 -3
  418. package/neural-interface/public/shared/ocp-v2/ocp-v2-composer-logic.js +2 -6
  419. package/neural-interface/public/shared/ocp-v2/ocp-v2-context-menu.js +11 -11
  420. package/neural-interface/public/shared/ocp-v2/ocp-v2-context-model.js +0 -3
  421. package/neural-interface/public/shared/ocp-v2/ocp-v2-events.js +8 -4
  422. package/neural-interface/public/shared/ocp-v2/ocp-v2-manager.js +7 -7
  423. package/neural-interface/public/shared/ocp-v2/ocp-v2-outcome-notifications.js +16 -0
  424. package/neural-interface/public/shared/ocp-v2/ocp-v2-panel.js +74 -259
  425. package/neural-interface/public/shared/ocp-v2/ocp-v2-plan.js +1 -2
  426. package/neural-interface/public/shared/ocp-v2/ocp-v2-projectbar.js +95 -202
  427. package/neural-interface/public/shared/ocp-v2/ocp-v2-rehydrate.js +13 -4
  428. package/neural-interface/public/shared/ocp-v2/ocp-v2-render.js +13 -22
  429. package/neural-interface/public/shared/ocp-v2/ocp-v2-send.js +4 -4
  430. package/neural-interface/public/shared/ocp-v2/ocp-v2-session-actions.js +8 -61
  431. package/neural-interface/public/shared/ocp-v2/ocp-v2-sessions-logic.js +2 -91
  432. package/neural-interface/public/shared/ocp-v2/ocp-v2-slash-hints.js +16 -15
  433. package/neural-interface/public/shared/ocp-v2/ocp-v2-state.js +8 -21
  434. package/neural-interface/public/shared/ocp-v2/ocp-v2-status-logic.js +1 -99
  435. package/neural-interface/public/shared/ocp-v2/ocp-v2-status.js +5 -35
  436. package/neural-interface/public/shared/ocp-v2/ocp-v2-styles.js +17 -21
  437. package/neural-interface/public/shared/ocp-v2/{ocp-v2-profile-inheritance.js → ocp-v2-tools-inheritance.js} +16 -16
  438. package/neural-interface/public/shared/ocp-v2/ocp-v2-ws.js +60 -50
  439. package/neural-interface/public/shared/page-session.js +96 -0
  440. package/neural-interface/public/shared/provider-icons.js +4 -2
  441. package/neural-interface/public/shared/registry.js +5 -3
  442. package/neural-interface/public/shared/retired-2d.js +3 -0
  443. package/neural-interface/public/shared/schedules-view.js +195 -61
  444. package/neural-interface/public/shared/settings/settings-claude-hooks.js +135 -0
  445. package/neural-interface/public/shared/settings/settings-data.js +3 -1
  446. package/neural-interface/public/shared/settings/settings-ia.js +6 -6
  447. package/neural-interface/public/shared/settings/settings-opencode.js +89 -0
  448. package/neural-interface/public/shared/settings/settings-rules.js +2 -2
  449. package/neural-interface/public/shared/settings/settings-skill-folders-pane.js +265 -0
  450. package/neural-interface/public/shared/settings/settings-skill-folders.js +130 -0
  451. package/neural-interface/public/shared/settings/settings-worker-guard.js +72 -0
  452. package/neural-interface/public/shared/showcase-privacy.js +6 -1
  453. package/neural-interface/public/shared/sidepanel-session-status.js +3 -3
  454. package/neural-interface/public/shared/skills/ss-args.js +96 -0
  455. package/neural-interface/public/shared/skills/ss-creation.js +222 -0
  456. package/neural-interface/public/shared/skills/ss-dialog.js +133 -0
  457. package/neural-interface/public/shared/skills/ss-doc.js +173 -0
  458. package/neural-interface/public/shared/skills/ss-eval-adapters.js +269 -0
  459. package/neural-interface/public/shared/skills/ss-eval-grade.js +359 -0
  460. package/neural-interface/public/shared/skills/ss-eval-optimise.js +153 -0
  461. package/neural-interface/public/shared/skills/ss-eval-plan.js +315 -0
  462. package/neural-interface/public/shared/skills/ss-evals.js +417 -0
  463. package/neural-interface/public/shared/skills/ss-form.js +159 -0
  464. package/neural-interface/public/shared/skills/ss-frontmatter.js +376 -0
  465. package/neural-interface/public/shared/skills/ss-ids.js +32 -0
  466. package/neural-interface/public/shared/skills/ss-lint.js +149 -0
  467. package/neural-interface/public/shared/skills/ss-presets.js +117 -0
  468. package/neural-interface/public/shared/skills/ss-profiles.js +513 -0
  469. package/neural-interface/public/shared/skills/ss-resources.js +165 -0
  470. package/neural-interface/public/shared/skills/ss-review-view.js +190 -0
  471. package/neural-interface/public/shared/skills/ss-tabs.js +79 -0
  472. package/neural-interface/public/shared/skills/ss-unicode.js +135 -0
  473. package/neural-interface/public/shared/skills/studio/sx-actions.js +222 -0
  474. package/neural-interface/public/shared/skills/studio/sx-cm.js +101 -0
  475. package/neural-interface/public/shared/skills/studio/sx-create-ai-view.js +749 -0
  476. package/neural-interface/public/shared/skills/studio/sx-create-ai.js +237 -0
  477. package/neural-interface/public/shared/skills/studio/sx-create-view.js +254 -0
  478. package/neural-interface/public/shared/skills/studio/sx-create.js +126 -0
  479. package/neural-interface/public/shared/skills/studio/sx-diff-view.js +43 -0
  480. package/neural-interface/public/shared/skills/studio/sx-diff.js +133 -0
  481. package/neural-interface/public/shared/skills/studio/sx-docs.js +480 -0
  482. package/neural-interface/public/shared/skills/studio/sx-dom.js +230 -0
  483. package/neural-interface/public/shared/skills/studio/sx-edit-view.js +848 -0
  484. package/neural-interface/public/shared/skills/studio/sx-editor-model.js +193 -0
  485. package/neural-interface/public/shared/skills/studio/sx-errors.js +22 -0
  486. package/neural-interface/public/shared/skills/studio/sx-fixes-view.js +359 -0
  487. package/neural-interface/public/shared/skills/studio/sx-fixes.js +327 -0
  488. package/neural-interface/public/shared/skills/studio/sx-geometry.js +82 -0
  489. package/neural-interface/public/shared/skills/studio/sx-import.js +262 -0
  490. package/neural-interface/public/shared/skills/studio/sx-inspector.js +308 -0
  491. package/neural-interface/public/shared/skills/studio/sx-install-flow.js +282 -0
  492. package/neural-interface/public/shared/skills/studio/sx-install.js +313 -0
  493. package/neural-interface/public/shared/skills/studio/sx-library-view.js +748 -0
  494. package/neural-interface/public/shared/skills/studio/sx-library.js +479 -0
  495. package/neural-interface/public/shared/skills/studio/sx-main.js +690 -0
  496. package/neural-interface/public/shared/skills/studio/sx-operations-view.js +98 -0
  497. package/neural-interface/public/shared/skills/studio/sx-operations.js +11 -0
  498. package/neural-interface/public/shared/skills/studio/sx-plan.js +158 -0
  499. package/neural-interface/public/shared/skills/studio/sx-publish-view.js +621 -0
  500. package/neural-interface/public/shared/skills/studio/sx-review-view.js +369 -0
  501. package/neural-interface/public/shared/skills/studio/sx-review.js +148 -0
  502. package/neural-interface/public/shared/skills/studio/sx-scan.js +35 -0
  503. package/neural-interface/public/shared/skills/studio/sx-snippets.js +96 -0
  504. package/neural-interface/public/shared/skills/studio/sx-subject.js +249 -0
  505. package/neural-interface/public/shared/skills/studio/sx-test-view.js +994 -0
  506. package/neural-interface/public/shared/skills/studio/sx-test.js +328 -0
  507. package/neural-interface/public/shared/skills/studio/sx-versions-view.js +241 -0
  508. package/neural-interface/public/shared/skills/studio/sx-workspace-view.js +426 -0
  509. package/neural-interface/public/shared/state.js +1 -1
  510. package/neural-interface/public/shared/streaming-markdown.js +58 -0
  511. package/neural-interface/public/shared/styleguide/sg-panel.js +4 -2
  512. package/neural-interface/public/shared/styles.css +1822 -1756
  513. package/neural-interface/public/shared/synabun-mascot.js +1115 -9
  514. package/neural-interface/public/shared/text-cache.js +29 -0
  515. package/neural-interface/public/shared/tool-list-picker.js +55 -0
  516. package/neural-interface/public/shared/tool-list-storage.js +24 -0
  517. package/neural-interface/public/shared/tool-list-view.js +112 -0
  518. package/neural-interface/public/shared/topright-overflow-logic.js +54 -0
  519. package/neural-interface/public/shared/tour/tour-actor.js +268 -0
  520. package/neural-interface/public/shared/tour/tour-beats.js +336 -0
  521. package/neural-interface/public/shared/tour/tour-engine.js +884 -0
  522. package/neural-interface/public/shared/tour/tour-ink.js +390 -0
  523. package/neural-interface/public/shared/tour/tour-stage.js +440 -0
  524. package/neural-interface/public/shared/tour/tour-state.js +40 -0
  525. package/neural-interface/public/shared/tour/tour-tips.js +99 -0
  526. package/neural-interface/public/shared/tour/tour.css +144 -0
  527. package/neural-interface/public/shared/ui-antigravity-panel.js +19 -0
  528. package/neural-interface/public/shared/ui-assistant.js +2 -0
  529. package/neural-interface/public/shared/ui-automation-studio.js +111 -140
  530. package/neural-interface/public/shared/ui-claude-panel.js +376 -82
  531. package/neural-interface/public/shared/ui-cli-banner.js +23 -167
  532. package/neural-interface/public/shared/ui-command-runner.js +6 -3
  533. package/neural-interface/public/shared/ui-context-menu.js +295 -0
  534. package/neural-interface/public/shared/ui-cost-widget.js +57 -59
  535. package/neural-interface/public/shared/ui-crash-notice.js +187 -0
  536. package/neural-interface/public/shared/ui-detail.js +15 -3
  537. package/neural-interface/public/shared/ui-file-explorer.js +48 -6
  538. package/neural-interface/public/shared/ui-file-links.js +2 -2
  539. package/neural-interface/public/shared/ui-games.js +2 -2
  540. package/neural-interface/public/shared/ui-image-gallery.js +50 -47
  541. package/neural-interface/public/shared/ui-judgments.js +1 -1
  542. package/neural-interface/public/shared/ui-keybinds.js +33 -2
  543. package/neural-interface/public/shared/ui-link.js +3 -3
  544. package/neural-interface/public/shared/ui-menubar.js +10 -20
  545. package/neural-interface/public/shared/ui-native-loop-router-state.js +5 -0
  546. package/neural-interface/public/shared/ui-native-loop-router.js +11 -1
  547. package/neural-interface/public/shared/ui-navbar.js +49 -24
  548. package/neural-interface/public/shared/ui-notifications.js +1 -0
  549. package/neural-interface/public/shared/ui-panels.js +96 -65
  550. package/neural-interface/public/shared/ui-resume.js +9 -7
  551. package/neural-interface/public/shared/ui-schedules-studio.js +546 -431
  552. package/neural-interface/public/shared/ui-scroll-follow.js +16 -5
  553. package/neural-interface/public/shared/ui-sessions.js +27 -15
  554. package/neural-interface/public/shared/ui-settings.js +683 -526
  555. package/neural-interface/public/shared/ui-sidepanel-session-entry.js +9 -2
  556. package/neural-interface/public/shared/ui-sidepanel-sessions.js +4 -4
  557. package/neural-interface/public/shared/ui-sidepanel-state.js +23 -12
  558. package/neural-interface/public/shared/ui-sidepanel-tray.js +48 -7
  559. package/neural-interface/public/shared/ui-sidepanel-windows.js +18 -13
  560. package/neural-interface/public/shared/ui-skills.js +33 -2830
  561. package/neural-interface/public/shared/ui-styleguide.js +5 -2
  562. package/neural-interface/public/shared/ui-sync.js +15 -5
  563. package/neural-interface/public/shared/ui-terminal.js +270 -190
  564. package/neural-interface/public/shared/ui-tool-updates.js +6 -4
  565. package/neural-interface/public/shared/ui-tooltip.js +81 -51
  566. package/neural-interface/public/shared/ui-topright-overflow.js +233 -0
  567. package/neural-interface/public/shared/ui-trash.js +6 -4
  568. package/neural-interface/public/shared/ui-tutorial-layout.js +3 -117
  569. package/neural-interface/public/shared/ui-tutorial-preview.js +103 -0
  570. package/neural-interface/public/shared/ui-tutorial-steps.js +3 -65
  571. package/neural-interface/public/shared/ui-tutorial.css +47 -100
  572. package/neural-interface/public/shared/ui-tutorial.js +285 -509
  573. package/neural-interface/public/shared/ui-update.js +38 -2
  574. package/neural-interface/public/shared/ui-whiteboard.js +312 -59
  575. package/neural-interface/public/shared/ui-worker-end.js +5 -1
  576. package/neural-interface/public/shared/ui-workspaces.js +3 -2
  577. package/neural-interface/public/shared/view-variant.js +66 -0
  578. package/neural-interface/public/shared/whatsapp/wa-view.js +3 -3
  579. package/neural-interface/public/shared/whiteboard-list.js +172 -0
  580. package/neural-interface/public/shared/worker-end.js +10 -3
  581. package/neural-interface/public/shared/worker-questions.js +34 -0
  582. package/neural-interface/public/shared/worker-restart.js +12 -0
  583. package/neural-interface/public/sidepanel-session.html +2 -2
  584. package/neural-interface/public/variant/2d/background.js +2 -1
  585. package/neural-interface/public/variant/2d/context-menu.js +8 -2
  586. package/neural-interface/public/variant/2d/graph.js +42 -20
  587. package/neural-interface/public/variant/2d/hulls.js +14 -9
  588. package/neural-interface/public/variant/2d/lasso.js +11 -7
  589. package/neural-interface/public/variant/2d/main.js +32 -1
  590. package/neural-interface/public/variant/2d/minimap.js +11 -13
  591. package/neural-interface/public/variant/3d/main.js +69 -6
  592. package/neural-interface/public/variant/3d/map-controls.js +24 -9
  593. package/neural-interface/public/vendor/caveat/OFL.txt +93 -0
  594. package/neural-interface/public/vendor/caveat/caveat-latin-400-normal.woff2 +0 -0
  595. package/neural-interface/public/vendor/caveat/caveat-latin-700-normal.woff2 +0 -0
  596. package/neural-interface/public/vendor/caveat/caveat.css +17 -0
  597. package/neural-interface/public/vendor/caveat/manifest.json +12 -0
  598. package/neural-interface/public/vendor/yaml/LICENSE +13 -0
  599. package/neural-interface/public/vendor/yaml/manifest.json +4 -0
  600. package/neural-interface/public/vendor/yaml/yaml-2.9.1.min.js +137 -0
  601. package/neural-interface/scripts/build-vendor.mjs +32 -0
  602. package/neural-interface/server.js +4553 -2855
  603. package/neural-interface/templates/rulesets/README.md +1 -1
  604. package/neural-interface/templates/rulesets/core.md +1 -1
  605. package/neural-interface/templates/rulesets/legacy-hashes.json +23 -5
  606. package/neural-interface/templates/rulesets/manifest.json +8 -8
  607. package/npm-shrinkwrap.json +34 -12
  608. package/package.json +17 -3
  609. package/postinstall.js +9 -4
  610. package/preuninstall.js +1 -1
  611. package/setup.js +97 -322
  612. package/skills/skill-forge/SKILL.md +177 -0
  613. package/skills/skill-forge/evals/evals.json +54 -0
  614. package/skills/skill-forge/references/package.md +105 -0
  615. package/skills/skill-forge/references/review-and-recovery.md +63 -0
  616. package/skills/skill-forge/references/runtime-profiles.md +20 -0
  617. package/skills/skill-forge/references/sources-and-capabilities.md +51 -0
  618. package/skills/synabun/SKILL.md +10 -7
  619. package/skills/synabun/modules/audit.md +1 -5
  620. package/skills/synabun/modules/changelog.md +1 -5
  621. package/skills/synabun/modules/idea.md +1 -1
  622. package/skills/synabun/modules/memorize.md +6 -9
  623. package/skills/synabun/modules/schedule.md +6 -6
  624. package/mcp-server/dist/services/profiles.d.ts +0 -120
  625. package/mcp-server/dist/services/profiles.d.ts.map +0 -1
  626. package/mcp-server/dist/services/profiles.js +0 -387
  627. package/mcp-server/dist/services/profiles.js.map +0 -1
  628. package/mcp-server/dist/tools/leonardo-browser-tools.d.ts +0 -97
  629. package/mcp-server/dist/tools/leonardo-browser-tools.d.ts.map +0 -1
  630. package/mcp-server/dist/tools/leonardo-browser-tools.js +0 -228
  631. package/mcp-server/dist/tools/leonardo-browser-tools.js.map +0 -1
  632. package/mcp-server/dist/tools/leonardo.d.ts +0 -13
  633. package/mcp-server/dist/tools/leonardo.d.ts.map +0 -1
  634. package/mcp-server/dist/tools/leonardo.js +0 -21
  635. package/mcp-server/dist/tools/leonardo.js.map +0 -1
  636. package/mcp-server/dist/tools/profile.d.ts +0 -17
  637. package/mcp-server/dist/tools/profile.d.ts.map +0 -1
  638. package/mcp-server/dist/tools/profile.js +0 -114
  639. package/mcp-server/dist/tools/profile.js.map +0 -1
  640. package/mcp-server/src/services/profiles.ts +0 -428
  641. package/mcp-server/src/tools/leonardo-browser-tools.ts +0 -291
  642. package/mcp-server/src/tools/leonardo.ts +0 -30
  643. package/mcp-server/src/tools/profile.ts +0 -122
  644. package/neural-interface/lib/assistant-brains/opencode-browser-policy.js +0 -47
  645. package/neural-interface/lib/assistant-brains/opencode-route-gate.js +0 -62
  646. package/neural-interface/lib/mcp-profile-servers.js +0 -120
  647. package/neural-interface/public/shared/ui-tutorial-draw.js +0 -311
  648. package/skills/leonardo/SKILL.md +0 -168
  649. package/skills/leonardo/icon.svg +0 -1
  650. package/skills/leonardo/modules/browser-guide.md +0 -378
  651. package/skills/leonardo/modules/image-prompter.md +0 -283
  652. package/skills/leonardo/modules/model-advisor.md +0 -100
  653. package/skills/leonardo/modules/prompt-library.md +0 -110
  654. package/skills/leonardo/modules/style-guide.md +0 -186
  655. package/skills/leonardo/modules/video-prompter.md +0 -317
  656. /package/neural-interface/templates/rulesets/{gemini.md → antigravity.md} +0 -0
@@ -0,0 +1,168 @@
1
+ // ═══════════════════════════════════════════
2
+ // SynaBun Neural Interface — the notice after an automatic restart: what it says
3
+ // ═══════════════════════════════════════════
4
+ //
5
+ // When SynaBun's server crashes after it was up, its supervisor starts it again
6
+ // and leaves the new server a record of the crash (lib/server-crash-record.js,
7
+ // GET /api/system/crash-notice). The owner's pages say so until it is dismissed:
8
+ // that the server stopped unexpectedly and was restarted, when and how it ended,
9
+ // and what the restart ended. This module decides the words; ui-crash-notice.js
10
+ // asks the server and draws them.
11
+ //
12
+ // What the restart ends is what the code does when the server process dies and
13
+ // a new one starts, nothing more:
14
+ // - terminals: the pty host ends with the server and kills its shells
15
+ // (lib/pty-host/host.js on 'disconnect'); a new host has none of them
16
+ // - runs: dispatched worker runs and native loops that were running are marked
17
+ // interrupted at boot (lib/assistant-dispatch.js, lib/native-loop-runtime.js);
18
+ // Quick Timers, schedule timers set for later and the schedule queue live in
19
+ // memory; saved schedules keep firing. The program a run had started is not
20
+ // always ended with the server: on macOS and Linux a CLI whose input is not
21
+ // the server's (`claude -p`, `codex exec`) ends at its next write to the
22
+ // server, and on Windows one started through a shell is not in the server's
23
+ // job: hence "a step already under way may still finish"
24
+ // - replies: a Claude Code, Codex or Assistant turn in progress is gone, the
25
+ // conversation stays and the next message resumes it (an OpenCode serve that
26
+ // outlived the server may be adopted and go on: hence "may have been")
27
+ // - browser: the sessions SynaBun drove live in memory; their profiles stay
28
+ // - public address: cloudflared is not started again, a new start gets a new
29
+ // one. Windows ends it with the server (its job); on macOS and Linux it
30
+ // outlives a crash, and the new server ends it by its record at start
31
+ // (server.js sweepLeftoverTunnels). One it could not end is `tunnel:
32
+ // 'unknown'` in the notice, and the notice says the address may still be open
33
+ //
34
+ // No imports and no DOM: `node --test` loads this file as it is
35
+ // (tests/crash-notice-view.test.mjs). CRASH_NOTICE_COPY is the English of every
36
+ // sentence; `crashNotice.*` in i18n/en.json must equal it and i18n/pt-BR.json
37
+ // must have the same keys.
38
+
39
+ export const CRASH_NOTICE_COPY = Object.freeze({
40
+ title: 'SynaBun\'s server stopped unexpectedly and was restarted automatically.',
41
+ whenToday: 'It happened at {time}.',
42
+ whenEarlier: 'It happened on {date} at {time}.',
43
+ whenManyToday: 'It happened {count} times, the last at {time}.',
44
+ whenManyEarlier: 'It happened {count} times, the last on {date} at {time}.',
45
+ how: 'How it ended: {exit}.',
46
+ lostTitle: 'What the restart ended',
47
+ lostTerminals: 'Open terminals were closed.',
48
+ lostRuns: 'Agent runs and loops that were running were interrupted, though a step already under way may still finish on its own. Timers and queued runs were cleared. Saved schedules keep running.',
49
+ lostReplies: 'Replies being written in the side panels or the Assistant may have been cut off. The conversations are kept: send again what did not finish.',
50
+ lostBrowser: 'Browser sessions SynaBun was driving ended. Their saved sign-ins are kept.',
51
+ lostTunnel: 'The public address, if it was on, is off. Turning it on again gives a new address.',
52
+ lostTunnelUnknown: 'The public address, if it was on, may still be open: SynaBun could not end the cloudflared that served it. Ending that process, or restarting the computer, closes it.',
53
+ openLogs: 'Open logs',
54
+ openLogsFailed: 'The logs folder could not be opened.',
55
+ dismiss: 'Dismiss',
56
+ label: 'Server restarted after a crash',
57
+ exitCode: 'exit code {code}',
58
+ exitText: '{status}, {kind}',
59
+ kindNativeCrash: 'native crash',
60
+ kindOutOfMemory: 'out of memory',
61
+ kindNodeFatal: 'Node.js fatal error',
62
+ kindError: 'stopped by an error',
63
+ kindKilled: 'ended by force',
64
+ kindInterrupted: 'interrupted',
65
+ });
66
+
67
+ /** The order the notice lists what the restart ended (the last: lostTunnelUnknown for a notice whose `tunnel` is 'unknown'). */
68
+ export const CRASH_NOTICE_LOST = Object.freeze(['lostTerminals', 'lostRuns', 'lostReplies', 'lostBrowser', 'lostTunnel']);
69
+
70
+ /** The word for each kind lib/server-exit.js names; a kind without one shows the status alone. */
71
+ export const CRASH_KIND_KEYS = Object.freeze({
72
+ 'native-crash': 'kindNativeCrash',
73
+ 'out-of-memory': 'kindOutOfMemory',
74
+ 'node-fatal': 'kindNodeFatal',
75
+ error: 'kindError',
76
+ killed: 'kindKilled',
77
+ interrupted: 'kindInterrupted',
78
+ });
79
+
80
+ /** A sentence of CRASH_NOTICE_COPY in English with its {values} filled; an unknown key is itself. */
81
+ export function fillCrashNoticeCopy(key, params = {}) {
82
+ const text = Object.prototype.hasOwnProperty.call(CRASH_NOTICE_COPY, key) ? CRASH_NOTICE_COPY[key] : key;
83
+ return text.replace(/\{(\w+)\}/g, (whole, name) => (params[name] != null ? String(params[name]) : whole));
84
+ }
85
+
86
+ const ID = /^[0-9a-f]{16}$/;
87
+
88
+ /**
89
+ * The notice in an answer of GET /api/system/crash-notice (or a `crash-notice:changed`
90
+ * message: both carry `notice`), checked field by field; null when there is none.
91
+ * `tunnel: 'unknown'` is there only when the server could not end the crashed
92
+ * server's cloudflared.
93
+ */
94
+ export function readCrashNotice(answer) {
95
+ const notice = answer && typeof answer === 'object' ? answer.notice : null;
96
+ if (!notice || typeof notice !== 'object' || Array.isArray(notice)) return null;
97
+ if (typeof notice.id !== 'string' || !ID.test(notice.id)) return null;
98
+ const at = Number(notice.at);
99
+ if (!Number.isFinite(at) || at <= 0) return null;
100
+ const exit = notice.exit && typeof notice.exit === 'object' && !Array.isArray(notice.exit) ? notice.exit : {};
101
+ return {
102
+ id: notice.id,
103
+ at,
104
+ count: Number.isInteger(notice.count) && notice.count > 0 ? Math.min(notice.count, 999) : 1,
105
+ exit: {
106
+ hex: typeof exit.hex === 'string' && /^0x[0-9a-f]{8}$/i.test(exit.hex) ? `0x${exit.hex.slice(2).toUpperCase()}` : '',
107
+ signal: typeof exit.signal === 'string' && /^SIG[A-Z0-9]{1,10}$/.test(exit.signal) ? exit.signal : '',
108
+ code: Number.isInteger(exit.code) ? exit.code : null,
109
+ kind: typeof exit.kind === 'string' && /^[a-z][a-z-]{0,23}$/.test(exit.kind) ? exit.kind : '',
110
+ },
111
+ ...(notice.tunnel === 'unknown' ? { tunnel: 'unknown' } : {}),
112
+ };
113
+ }
114
+
115
+ /** How it ended in the reader's words ("0xC0000409, native crash"), or '' when the record names nothing. */
116
+ export function crashExitWords(exit, t = fillCrashNoticeCopy) {
117
+ if (!exit || typeof exit !== 'object') return '';
118
+ const status = exit.hex || exit.signal || (Number.isInteger(exit.code) ? t('exitCode', { code: exit.code }) : '');
119
+ if (!status) return '';
120
+ const key = CRASH_KIND_KEYS[exit.kind];
121
+ return key ? t('exitText', { status, kind: t(key) }) : status;
122
+ }
123
+
124
+ /** When it happened, in the reader's locale: { today, date, time } (the date is for another day). */
125
+ export function crashTimeParts(at, { now = Date.now(), locale = undefined } = {}) {
126
+ const when = new Date(at);
127
+ if (!Number.isFinite(when.getTime())) return null;
128
+ const day = new Date(now);
129
+ const today = when.getFullYear() === day.getFullYear() && when.getMonth() === day.getMonth() && when.getDate() === day.getDate();
130
+ const format = (fn, options, fallback) => { try { return fn.call(when, locale, options); } catch { return fallback; } };
131
+ return {
132
+ today,
133
+ date: format(Date.prototype.toLocaleDateString, { dateStyle: 'medium' }, when.toISOString().slice(0, 10)),
134
+ time: format(Date.prototype.toLocaleTimeString, { hour: '2-digit', minute: '2-digit' }, when.toISOString().slice(11, 16)),
135
+ };
136
+ }
137
+
138
+ /**
139
+ * What the notice shows, or null: { id, label, title, when, how, lostTitle, lost[], actions[] }.
140
+ * `t(key, params)` is a sentence of CRASH_NOTICE_COPY in the page's language; `canOpenLogs`
141
+ * says whether this page can open the logs folder (the desktop app, or a page on this computer).
142
+ */
143
+ export function crashNoticeView(notice, { t = fillCrashNoticeCopy, now = Date.now(), locale = undefined, canOpenLogs = false } = {}) {
144
+ if (!notice || typeof notice !== 'object' || !notice.id) return null;
145
+ const parts = crashTimeParts(notice.at, { now, locale }) || { today: true, date: '', time: '' };
146
+ const many = notice.count > 1;
147
+ const whenKey = `${many ? 'whenMany' : 'when'}${parts.today ? 'Today' : 'Earlier'}`;
148
+ const exit = crashExitWords(notice.exit, t);
149
+ return {
150
+ id: notice.id,
151
+ label: t('label'),
152
+ title: t('title'),
153
+ when: t(whenKey, { count: notice.count, date: parts.date, time: parts.time }),
154
+ how: exit ? t('how', { exit }) : '',
155
+ lostTitle: t('lostTitle'),
156
+ lost: CRASH_NOTICE_LOST.map((key) => t(key === 'lostTunnel' && notice.tunnel === 'unknown' ? 'lostTunnelUnknown' : key)),
157
+ actions: [
158
+ ...(canOpenLogs ? [{ id: 'logs', label: t('openLogs') }] : []),
159
+ { id: 'dismiss', label: t('dismiss') },
160
+ ],
161
+ };
162
+ }
163
+
164
+ /** True for a page served from this computer's loopback address: the only one the logs folder opens for. */
165
+ export function isLoopbackHost(hostname) {
166
+ const host = String(hostname || '').toLowerCase().replace(/^\[|\]$/g, '');
167
+ return host === 'localhost' || host === '::1' || /^127(?:\.\d{1,3}){3}$/.test(host);
168
+ }
@@ -48,3 +48,20 @@ export function desktopWindow(win = globalThis.window) {
48
48
  if (!facts || facts.style !== 'overlay' || !['darwin', 'win32', 'linux'].includes(facts.platform)) return null;
49
49
  return api;
50
50
  }
51
+
52
+ /** True on Windows (desktop bridge platform `'win32'`, or Windows browser/window navigator). */
53
+ export function isWindowsPlatform(win = globalThis.window) {
54
+ const platform = desktopBridge(win)?.platform;
55
+ if (typeof platform === 'string' && platform) return platform === 'win32';
56
+ try {
57
+ const nav = win?.navigator ?? globalThis.navigator;
58
+ if (!nav || typeof nav !== 'object') return false;
59
+ const uaPlatform = nav.userAgentData?.platform;
60
+ if (typeof uaPlatform === 'string' && uaPlatform) return /^win/i.test(uaPlatform);
61
+ if (typeof nav.platform === 'string' && nav.platform) return /^win/i.test(nav.platform);
62
+ if (typeof nav.userAgent === 'string' && nav.userAgent) return /\bwindows\b/i.test(nav.userAgent);
63
+ } catch {
64
+ return false;
65
+ }
66
+ return false;
67
+ }
@@ -197,3 +197,15 @@ export function drawnUnderBar(style, barLevel) {
197
197
  const level = Number.isFinite(z) ? (positioned ? z : Math.max(z, 0)) : 0;
198
198
  return level < barLevel;
199
199
  }
200
+
201
+ /**
202
+ * True for a body-level overlay that never receives pointer events on itself or any child (such as `.ui-tooltip` or
203
+ * `#synabun-desktop-drag-strip`), so its hover/move mutations can never cover the bar's drag region.
204
+ */
205
+ export function isPassiveOverlay(node) {
206
+ if (!node || typeof node !== 'object') return false;
207
+ if (node.id === 'synabun-desktop-drag-strip') return true;
208
+ if (typeof node.classList?.contains === 'function' && node.classList.contains('ui-tooltip')) return true;
209
+ const cls = typeof node.className === 'string' ? node.className : '';
210
+ return /(?:^|\s)ui-tooltip(?:\s|$)/.test(cls);
211
+ }
@@ -27,7 +27,7 @@
27
27
 
28
28
  import { desktopWindow } from './desktop-bridge.js';
29
29
  import { colorSender, textTone } from './desktop-titlebar-page.js';
30
- import { barCovered, changedClasses, drawnUnderBar, fallbackTitlebarArea, overlayColorsFor, stackLevel, styleChange, titleBarActive } from './desktop-titlebar-view.js';
30
+ import { barCovered, changedClasses, drawnUnderBar, fallbackTitlebarArea, isPassiveOverlay, overlayColorsFor, stackLevel, styleChange, titleBarActive } from './desktop-titlebar-view.js';
31
31
  import { t } from './i18n.js';
32
32
 
33
33
  const MENU_ICON = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 7h16"/><path d="M4 12h16"/><path d="M4 17h16"/></svg>';
@@ -52,6 +52,7 @@ export function initDesktopTitleBar({ doc = document, view = window } = {}) {
52
52
  const facts = api.titleBar;
53
53
  const html = doc.documentElement;
54
54
  html.classList.add('desktop-titlebar', `desktop-titlebar--${facts.platform}`);
55
+ if (facts.platform === 'win32') html.classList.add('platform-win32');
55
56
  const wco = view.navigator?.windowControlsOverlay || null;
56
57
  let state = { maximized: false, fullScreen: false, focused: true };
57
58
  const send = colorSender(api, doc);
@@ -168,14 +169,22 @@ export function initDesktopTitleBar({ doc = document, view = window } = {}) {
168
169
  return null;
169
170
  };
170
171
  const hasElement = (nodes) => { for (const node of nodes || []) if (node?.nodeType === 1) return true; return false; };
172
+ const onlyPassiveElements = (nodes) => {
173
+ for (const node of nodes || []) if (node?.nodeType === 1 && !isPassiveOverlay(node)) return false;
174
+ return true;
175
+ };
171
176
  // Each change → [IGNORE | SOON | NOW, whether the bar has to be measured].
172
177
  const QUIET = [IGNORE, false];
173
178
  const childListChange = (record) => {
174
179
  if (!hasElement(record.addedNodes) && !hasElement(record.removedNodes)) return QUIET; // text
175
180
  const target = record.target;
176
- if (target === body) { judgeAgain(); return [NOW, true]; } // an overlay's root; a sibling selector may match anew
181
+ if (target === body) {
182
+ if (onlyPassiveElements(record.addedNodes) && onlyPassiveElements(record.removedNodes)) return QUIET;
183
+ judgeAgain();
184
+ return [NOW, true]; // an overlay's root; a sibling selector may match anew
185
+ }
177
186
  const part = partOf(target);
178
- if (!part || part === bar) return QUIET; // off the page, or what the bar holds: that counts as the bar
187
+ if (!part || part === bar || isPassiveOverlay(part)) return QUIET; // off the page, passive tooltip, or inside the bar
179
188
  toJudge.add(part);
180
189
  if (target === part) return [NOW, true]; // an overlay's root got or lost a child (:empty, :has() can show it)
181
190
  return [SOON, !underBar.has(part)];
@@ -189,7 +198,7 @@ export function initDesktopTitleBar({ doc = document, view = window } = {}) {
189
198
  return [NOW, true];
190
199
  }
191
200
  const part = partOf(target);
192
- if (!part) return QUIET;
201
+ if (!part || isPassiveOverlay(part)) return QUIET;
193
202
  if (part === bar) return target === bar ? [NOW, true] : QUIET;
194
203
  toJudge.add(part);
195
204
  // Shown, hidden or restacked: on the next frame; only moved, sized or repainted: at the throttled pace. Inside a
@@ -76,6 +76,10 @@ export const DESKTOP_COPY = Object.freeze({
76
76
  metaReadyOff: 'Ready to install',
77
77
  metaCountdown: 'Restarting to install it',
78
78
  metaPostponed: 'Postponed: installs on quit or later',
79
+ // The button at the top right while a downloaded update waits for a restart, as Discord's green one.
80
+ restartButton: 'Restart to update',
81
+ restartTooltip: 'SynaBun v{latest} is ready: restart to update',
82
+ restartSoon: 'Restarting soon',
79
83
  }),
80
84
  // What an update waits for (the app's server names it, GET /api/system/activity).
81
85
  busy: Object.freeze({
@@ -83,6 +87,7 @@ export const DESKTOP_COPY = Object.freeze({
83
87
  'claude-panel': 'a Claude Code panel reply',
84
88
  'codex-panel': 'a Codex panel reply',
85
89
  'opencode-panel': 'an OpenCode panel reply',
90
+ 'antigravity-panel': 'an Antigravity panel reply',
86
91
  'claude-cli': 'a Claude Code session in use',
87
92
  loop: 'a loop',
88
93
  schedule: 'a schedule',
@@ -422,6 +427,22 @@ export function desktopUpdateTooltip(state, { t = fillDesktopCopy } = {}) {
422
427
  return t('update.tooltip', params);
423
428
  }
424
429
 
430
+ /**
431
+ * The top right button while a downloaded update waits for a restart into it, or null: { label, tooltip, asked }.
432
+ * Only an update this copy installs by restarting (not one to move to Applications or to install by hand). After
433
+ * Restart to update, while something still runs, it says that the restart is coming (`asked`).
434
+ */
435
+ export function desktopRestartButton(state, { t = fillDesktopCopy } = {}) {
436
+ const s = readDesktopUpdateState(state);
437
+ if (desktopUpdateStep(s) !== 'downloaded' || s.install !== 'restart' || s.manualFile) return null;
438
+ const asked = s.auto?.now === true;
439
+ return {
440
+ label: t(asked ? 'update.restartSoon' : 'update.restartButton'),
441
+ tooltip: t('update.restartTooltip', { latest: s.latest || '', current: s.current }),
442
+ asked,
443
+ };
444
+ }
445
+
425
446
  /**
426
447
  * The notice at the bottom right, or null:
427
448
  * countdown SynaBun is idle and restarts into the update: the seconds left, and Later
@@ -80,9 +80,9 @@ export function matchesExpectedMarkdown(content, expected) {
80
80
  return String(content).replace(/\r\n/g, '\n') === expected.replace(/\r\n/g, '\n');
81
81
  }
82
82
 
83
- /** Whether a path is the user's OpenCode configuration file. */
83
+ /** Whether a path is the user's OpenCode configuration file (OpenCode 2's opencode.json or opencode.jsonc). */
84
84
  export function isOpencodeConfigPath(path) {
85
- return String(path || '').replace(/\\/g, '/').endsWith('/.config/opencode/config.json');
85
+ return /\/\.config\/opencode\/opencode\.jsonc?$/.test(String(path || '').replace(/\\/g, '/'));
86
86
  }
87
87
 
88
88
  const OUTSIDE_ROOTS = 'Path outside registered project roots';
@@ -96,15 +96,15 @@ export function createExplorerApi({ fetchImpl = (...args) => fetch(...args), Eve
96
96
  return old.ok ? fromLegacySearch(old) : old;
97
97
  }
98
98
 
99
- async function git(root) {
99
+ async function git(root, signal, refresh = false) {
100
100
  await capabilities();
101
- if (caps.explorer) return request(`/api/explorer/git?root=${encodeURIComponent(root)}`);
102
- const old = await request(`/api/git/status?path=${encodeURIComponent(root)}`);
101
+ if (caps.explorer) return request(`/api/explorer/git?root=${encodeURIComponent(root)}${refresh ? '&refresh=1' : ''}`, { signal });
102
+ const old = await request(`/api/git/status?path=${encodeURIComponent(root)}${refresh ? '&refresh=1' : ''}`, { signal });
103
103
  if (!old.ok) return old;
104
104
  if (!old.isGit) return { ok: true, isGit: false };
105
105
  const changes = {};
106
106
  for (const change of old.changes || []) if (change?.path) changes[change.path] = change.status;
107
- return { ok: true, isGit: true, branch: old.branch || '', changes, ignored: [], legacy: true };
107
+ return { ok: true, isGit: true, branch: old.branch || '', changes, ignored: [], legacy: true, ...(old.partial ? { partial: true, scanState: old.scanState } : {}) };
108
108
  }
109
109
 
110
110
  async function create(parent, name, type) {
@@ -110,13 +110,13 @@ export function createEditorLink({ openFile, save, tabs, repoint, subscribe, onC
110
110
 
111
111
  // ── The agents ──
112
112
 
113
- export const SEND_TARGETS = Object.freeze(['claude', 'codex', 'opencode', 'assistant']);
114
- const TARGET_NAMES = { claude: 'Claude Code', codex: 'Codex', opencode: 'OpenCode' };
113
+ export const SEND_TARGETS = Object.freeze(['claude', 'codex', 'opencode', 'antigravity', 'assistant']);
114
+ const TARGET_NAMES = { claude: 'Claude Code', codex: 'Codex', opencode: 'OpenCode', antigravity: 'Antigravity' };
115
115
 
116
116
  /**
117
117
  * @param {object} o
118
118
  * @param {object} o.deps what each panel offers: `sendToFocusedSession(kind, data)`, `claude(path)`, `codex(path)`,
119
- * `opencode(path)`, `assistant(path)`, and `lastActive()` (the panel used last)
119
+ * `opencode(path)`, `antigravity(path)`, `assistant(path)`, and `lastActive()` (the panel used last)
120
120
  * @param {(key: string, params?: object) => string} o.t
121
121
  */
122
122
  export function createSender({ deps, t }) {
@@ -56,7 +56,7 @@ export function sameListing(a, b) {
56
56
  if (!a || !b || a.length !== b.length) return false;
57
57
  for (let i = 0; i < a.length; i++) {
58
58
  const x = a[i]; const y = b[i];
59
- if (x.name !== y.name || x.type !== y.type || x.size !== y.size || x.mtime !== y.mtime || !!x.link !== !!y.link || !!x.outside !== !!y.outside || !!x.broken !== !!y.broken) return false;
59
+ if (x.name !== y.name || x.type !== y.type || x.size !== y.size || x.mtime !== y.mtime || !!x.link !== !!y.link || !!x.outside !== !!y.outside || !!x.broken !== !!y.broken || !!x.ignored !== !!y.ignored || (x.ignored === null) !== (y.ignored === null)) return false;
60
60
  }
61
61
  return true;
62
62
  }
@@ -48,7 +48,9 @@ const EXPAND_LEVEL_MAX = 200;
48
48
  * @param {object} host.send what each side panel offers for a path (fx-links.js createSender)
49
49
  * @param {(name: string) => object} host.fileIcon @param {string} host.folderSvg
50
50
  * @param {{ all: { hex: string, key: string }[], of: (path: string) => string | undefined, set: Function, move: Function }} host.colors
51
- * @param {(git: { isGit: boolean, branch: string, count: number }) => void} host.onGit
51
+ * @param {(git: { isGit: boolean, branch: string, count: number, scanState?: 'ready' | 'scanning' | 'timed-out' | 'failed',
52
+ * shown?: boolean, loud?: boolean }) => void} host.onGit `shown`: a result of this project is already on screen;
53
+ * `loud`: the scan is the project's first or one the owner asked for (Refresh), not a background one.
52
54
  * @param {() => void} host.addProject
53
55
  * @param {typeof fetch} [host.fetchImpl]
54
56
  */
@@ -77,7 +79,10 @@ export function createExplorer(host) {
77
79
  let watcher = null;
78
80
  let saidLimited = false; // this project was told once that not everything on disk is followed
79
81
  let loaded = Promise.resolve();
80
- let gitTimer = 0; let gitBusy = false; let gitAgain = false; let lastGitAt = 0;
82
+ let gitTimer = 0; let gitRequest = null; let gitRefresh = false; let gitAgain = false; let lastGitAt = 0;
83
+ // gitShown: a result of this project is on screen. gitLoud: the owner asked (Refresh), so a slow scan may say so.
84
+ // gitSettled: the last state a scan ended in, put back when a scan that said 'scanning' is called off.
85
+ let gitShown = false; let gitLoud = false; let gitSettled = 'ready';
81
86
  let diskTimer = 0; let lastDiskAt = 0; const diskDue = new Set();
82
87
  let filterTimer = 0; let searchAbort = null;
83
88
  let persistTimer = 0; let lastFocusRefresh = 0;
@@ -114,18 +119,20 @@ export function createExplorer(host) {
114
119
  const ed = editor.state();
115
120
  const status = item.missing ? 'deleted' : S.git.statusOf(below, isDir);
116
121
  const tone = item.missing ? 'deleted' : S.git.toneOf(below, isDir);
117
- const ignored = S.git.isIgnored(below);
122
+ const ignored = !!item.ignored || S.git.isIgnored(below);
123
+ const ignoreUnknown = item.ignored === null && !ignored;
118
124
  const open = !isDir && ed.open.has(path);
119
125
  const dirty = !isDir && ed.dirty.has(path);
120
126
  const cut = !!S.clipboard && S.clipboard.mode === 'cut' && S.clipboard.paths.some((held) => isWithin(held, path));
121
127
  const words = [];
122
128
  if (status) words.push(t(`fileExplorer.git.${status}`)); else if (tone) words.push(t('fileExplorer.git.contains'));
123
129
  if (ignored) words.push(t('fileExplorer.git.ignored'));
130
+ else if (ignoreUnknown) words.push(t('fileExplorer.git.ignoreUnknown'));
124
131
  if (dirty) words.push(t('fileExplorer.row.unsaved')); else if (open) words.push(t('fileExplorer.row.open'));
125
132
  if (item.outside) words.push(t('fileExplorer.row.linkOutside')); else if (item.broken) words.push(t('fileExplorer.row.linkBroken')); else if (item.link) words.push(t('fileExplorer.row.link'));
126
133
  if (cut) words.push(t('fileExplorer.row.cut'));
127
134
  return {
128
- tone, letter: status ? GIT_MARKS[status].letter : '', ignored, open, dirty, cut, words,
135
+ tone, letter: status ? GIT_MARKS[status].letter : '', ignored, ignoreUnknown, open, dirty, cut, words,
129
136
  active: !isDir && ed.active === path,
130
137
  missing: !!item.missing,
131
138
  faint: !!item.outside || !!item.broken,
@@ -296,24 +303,46 @@ export function createExplorer(host) {
296
303
 
297
304
  // ── Git ──
298
305
 
306
+ function cancelGit() {
307
+ clearTimeout(gitTimer);
308
+ gitRequest?.controller.abort();
309
+ gitRequest = null; gitAgain = false; gitRefresh = false; gitLoud = false;
310
+ }
299
311
  async function loadGit() {
300
- if (!S.root) return;
301
- if (gitBusy) { gitAgain = true; return; }
302
- gitBusy = true;
312
+ if (!S.root || !S.visible) return;
313
+ if (gitRequest?.root === S.root) { gitAgain = true; return; }
314
+ gitRequest?.controller.abort();
315
+ const request = { root: S.root, controller: new AbortController() };
316
+ gitRequest = request;
303
317
  const mine = epoch;
304
- const got = await api.git(S.root);
305
- gitBusy = false;
318
+ const refresh = gitRefresh; gitRefresh = false;
319
+ // A background scan (the watcher, focus, the popover) never puts words in the header while a result is shown:
320
+ // only the first scan of a project, or one the owner asked for, is loud.
321
+ const loud = gitLoud || !gitShown; gitLoud = false;
322
+ let said = '';
323
+ const say = (scanState) => { said = scanState; host.onGit({ ...gitState(scanState), loud }); };
324
+ const slow = setTimeout(() => { if (gitRequest === request && mine === epoch) say('scanning'); }, 1500);
325
+ const got = await api.git(request.root, request.controller.signal, refresh);
326
+ clearTimeout(slow);
327
+ if (gitRequest !== request) return;
328
+ gitRequest = null;
306
329
  if (mine === epoch && got.ok) {
307
- S.git = gitIndex(got);
308
- host.onGit({ isGit: S.git.isGit, branch: S.git.branch, count: S.git.count });
330
+ if (!got.partial || !S.git.isGit) S.git = gitIndex(got);
331
+ gitShown = true;
332
+ say(gitSettled = got.scanState || 'ready');
309
333
  if (S.changedOnly) { buildView(); tree.render(); } else tree.refreshRows();
310
334
  updateCount();
311
- }
335
+ } else if (mine === epoch && got.code !== 'aborted') say(gitSettled = 'failed');
336
+ else if (mine === epoch && said === 'scanning') say(gitSettled);
312
337
  if (gitAgain) { gitAgain = false; queueGit(); }
313
338
  }
339
+ function gitState(scanState) {
340
+ return { isGit: S.git.isGit, branch: S.git.branch, count: S.git.count, scanState, shown: gitShown };
341
+ }
314
342
  // Soon after the last sign of a change, and never more often than once in a while: a file that is written
315
343
  // without pause (a log, a database) does not make git run without pause.
316
344
  function queueGit() {
345
+ if (!S.root || !S.visible) return;
317
346
  clearTimeout(gitTimer);
318
347
  gitTimer = setTimeout(() => { lastGitAt = Date.now(); loadGit(); }, Math.max(GIT_DELAY_MS, lastGitAt + GIT_MIN_INTERVAL_MS - Date.now()));
319
348
  }
@@ -654,7 +683,7 @@ export function createExplorer(host) {
654
683
  case 'sortBy': return [back(), ...SORTS.map((mode) => ({ id: `sort:${mode}`, label: t(`fileExplorer.menu.sort.${mode}`), checked: S.sort === mode }))];
655
684
  case 'expandAll': expandLevel(); break;
656
685
  case 'collapseAll': collapseAll(); break;
657
- case 'refresh': refreshAll(); break;
686
+ case 'refresh': gitRefresh = true; gitLoud = true; refreshAll(); break;
658
687
  default:
659
688
  }
660
689
  return undefined;
@@ -739,7 +768,7 @@ export function createExplorer(host) {
739
768
  });
740
769
  on('fe-collapse-all', collapseAll);
741
770
  // Refresh also asks what the server has: one that was restarted since the page loaded is found out here.
742
- on('fe-refresh', async () => { await host.readServer?.(); await api.capabilities(); syncToolbar(); await refreshAll(); if (!watcher) startWatch(); });
771
+ on('fe-refresh', async () => { gitRefresh = true; gitLoud = true; await host.readServer?.(); await api.capabilities(); syncToolbar(); await refreshAll(); if (!watcher) startWatch(); });
743
772
  on('fe-more', (event) => { const box = event.currentTarget.getBoundingClientRect(); openMenu({ y: box.top + box.height / 2, keyboard: event.detail === 0 }); });
744
773
  on('fe-filter-clear', () => { clearFilter(); filterInput.focus(); });
745
774
  filterInput.addEventListener('input', () => setFilter(filterInput.value));
@@ -773,11 +802,13 @@ export function createExplorer(host) {
773
802
  function setProject(project) {
774
803
  persist();
775
804
  epoch++;
805
+ cancelGit();
776
806
  stopWatch();
777
807
  saidLimited = false;
778
808
  closeFlyout({ refocus: false });
779
809
  searchAbort?.abort();
780
810
  clearTimeout(gitTimer);
811
+ gitShown = false; gitSettled = 'ready';
781
812
  S.dirs = new Map(); S.git = gitIndex(null); S.view = null; S.viewOpen = new Set(); S.viewClosed = new Set();
782
813
  S.search = null; S.filter = ''; S.clipboard = null;
783
814
  reads.clear();
@@ -824,7 +855,7 @@ export function createExplorer(host) {
824
855
  /** The panel is shown or hidden: the disk is followed only while it is shown. */
825
856
  function setVisible(visible) {
826
857
  S.visible = !!visible;
827
- if (S.visible) { if (S.root) { startWatch(); if (S.dirs.size) refreshAll(); } } else { persist(); stopWatch(); closeFlyout({ refocus: false }); }
858
+ if (S.visible) { if (S.root) { startWatch(); if (S.dirs.size) refreshAll(); } } else { persist(); cancelGit(); host.onGit(gitState(gitSettled)); stopWatch(); closeFlyout({ refocus: false }); }
828
859
  }
829
860
 
830
861
  /** Show a file of the project in the tree: its folders open, its row is selected and marked. */
@@ -850,7 +881,8 @@ export function createExplorer(host) {
850
881
  setProject,
851
882
  setVisible,
852
883
  reveal,
853
- refresh: refreshAll,
884
+ /** Read the disk and git again. `quiet`: nobody asked for it in so many words (the git popover opened). */
885
+ refresh: ({ quiet = false } = {}) => { gitRefresh = true; if (!quiet) gitLoud = true; return refreshAll(); },
854
886
  collapseAll,
855
887
  /** The icons changed: every row is drawn again. */
856
888
  redraw() { if (S.root) { const now = tree.selection(); const top = tree.scrollTop(); tree.setRoot(S.root); tree.render(); tree.select(now.selected, { focus: now.focus, quiet: true, scroll: false }); tree.setScrollTop(top); } },
@@ -161,6 +161,7 @@ export function createTree({ el, mac, icons, hooks }) {
161
161
  node.classList.toggle('fe-node--selected', selected.has(path));
162
162
  node.classList.toggle('fe-node--focus', focus === path);
163
163
  node.classList.toggle('fe-node--ignored', !!info.ignored);
164
+ node.dataset.ignoreState = info.ignoreUnknown ? 'unknown' : info.ignored ? 'ignored' : 'known';
164
165
  node.classList.toggle('fe-node--cut', !!info.cut);
165
166
  node.classList.toggle('fe-node--open', !!info.open);
166
167
  node.classList.toggle('fe-node--active', !!info.active);
@@ -2,8 +2,8 @@
2
2
  // SynaBun — Greeting: the card every surface mounts
3
3
  // ═══════════════════════════════════════════
4
4
  //
5
- // One renderer for the greeting: the Assistant and the Claude Code, Codex and
6
- // OpenCode panels mount it inside the empty state they already have, Settings
5
+ // One renderer for the greeting: the Assistant and the Claude Code, Codex,
6
+ // OpenCode and Antigravity panels mount it inside the empty state they already have, Settings
7
7
  // shows the same card as its preview. greeting-view.js decides the words; this
8
8
  // file asks the server (`POST /api/greeting/open`) and draws.
9
9
  //
@@ -41,6 +41,7 @@ export const GREETING_COPY = Object.freeze({
41
41
  'agent.claude-code': 'Claude Code',
42
42
  'agent.codex': 'Codex',
43
43
  'agent.opencode': 'OpenCode',
44
+ 'agent.antigravity': 'Antigravity',
44
45
  open: 'Open memory',
45
46
  'source.writer': 'Written ahead by {model}',
46
47
  'source.fallback': 'Put together from the records, no model',