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
@@ -6,9 +6,11 @@
6
6
  // keeps an untouched copy current:
7
7
  //
8
8
  // claude owned file ~/.claude/rules/synabun.md (and each Claude account's config dir)
9
- // opencode owned file <opencode config dir>/synabun.md + one `instructions` entry in config.json
9
+ // opencode owned file <opencode config dir>/synabun.md + one `instructions` entry in opencode.json
10
10
  // codex block ~/.codex/AGENTS.md (account homes link to it, or get their own block)
11
- // gemini block ~/.gemini/GEMINI.md
11
+ // antigravity block ~/.gemini/config/GEMINI.md (Antigravity's global customization root; the block an
12
+ // older SynaBun wrote for Gemini CLI in ~/.gemini/GEMINI.md, which Antigravity also
13
+ // reads, is moved here so the rules are never loaded twice)
12
14
  // cursor none User Rules live inside the app: copy and paste ("manual")
13
15
  //
14
16
  // What it will not do: create the config directory of a CLI that is not
@@ -29,7 +31,7 @@
29
31
  // (the user opted out) or null (never asked). `created` lists the files and
30
32
  // directories install made, `links` the symlinks it made and where each
31
33
  // pointed. OpenCode's row also holds `instructionsEntry`, the exact string
32
- // SynaBun added to config.json. `removal` on a row is a removal that is not
34
+ // SynaBun added to opencode.json. `removal` on a row is a removal that is not
33
35
  // over: it is saved, with the paths it is about to take, before the first
34
36
  // copy goes, and it stays when a copy was refused (damaged markers, an
35
37
  // unreadable file). The next boot finishes it (reconcile), and the record is
@@ -74,6 +76,7 @@ import { loadLegacyHashes, normalise, renderRuleset, RULESET_HOSTS } from './ren
74
76
  import { findBlocks, findLegacy, isPristine, removeBlock, removeRange, replaceRange, upsertBlock, wrap } from './managed-text.js';
75
77
  import { backupFile, findBrokenLink, readBytes, readJsonStrict, unlinkIfUnchanged, writeTextAtomic } from './fs-safe.js';
76
78
  import { addToJsonList, countJsonKey, removeFromJsonList } from './json-edit.js';
79
+ import { mcpServersOf, mergedOpencodeConfig, opencodeConfigDir, opencodeConfigFilePath, readOpencodeConfigDocuments } from '../opencode-config.js';
77
80
  import { createWriterLock, DEFAULT_LOCK_TIMEOUT_MS, LOCK_FILE_NAME } from './lock.js';
78
81
 
79
82
  export const RULESET_STATES = Object.freeze(['not-installed', 'installed', 'newer', 'outdated', 'modified', 'conflict', 'shadowed', 'error', 'manual']);
@@ -82,11 +85,18 @@ const HOSTS = Object.freeze({
82
85
  claude: { label: 'Claude Code', carrier: 'file' },
83
86
  codex: { label: 'Codex CLI', carrier: 'block' },
84
87
  opencode: { label: 'OpenCode', carrier: 'file' },
85
- gemini: { label: 'Gemini CLI', carrier: 'block' },
88
+ // `legacyHosts`: the stamps an earlier SynaBun wrote for what this host replaced (Gemini CLI's rules, host=gemini).
89
+ antigravity: { label: 'Antigravity', carrier: 'block', legacyHosts: Object.freeze(['gemini']) },
86
90
  cursor: { label: 'Cursor', carrier: 'none' },
87
91
  });
88
92
  const MANAGED_HOSTS = Object.freeze(RULESET_HOSTS.filter((host) => HOSTS[host].carrier !== 'none'));
89
- const PROJECT_FILES = Object.freeze([['CLAUDE.md', 'claude'], ['AGENTS.md', 'codex'], ['GEMINI.md', 'gemini']]);
93
+ const PROJECT_FILES = Object.freeze([['CLAUDE.md', 'claude'], ['AGENTS.md', 'codex'], ['GEMINI.md', 'antigravity']]);
94
+ // State rows an earlier SynaBun kept under a host this one replaced: read as the new host's row (readState).
95
+ const RENAMED_HOSTS = Object.freeze({ gemini: 'antigravity' });
96
+ /** Whether a block's stamp is this host's own: its name, or one it replaced. */
97
+ function ownStamp(host, stamped) {
98
+ return stamped === host || (HOSTS[host]?.legacyHosts || []).includes(stamped);
99
+ }
90
100
  const RANK = Object.freeze({ missing: 0, current: 1, newer: 2, outdated: 3, modified: 4, conflict: 5, error: 6 });
91
101
  const MAX_SCAN_BYTES = 2 * 1024 * 1024;
92
102
 
@@ -190,7 +200,7 @@ export function createRulesetInstaller({
190
200
  // `hooks` are seams for tests, each a point where another program could act
191
201
  // (or where a test holds an operation still, inside the lock):
192
202
  // afterInspect(host, path, status) once a carrier was read and is about to be
193
- // written, beforeCommit(path) right before a file (a carrier, config.json,
203
+ // written, beforeCommit(path) right before a file (a carrier, opencode.json,
194
204
  // the state file) is checked against what was read and replaced or deleted,
195
205
  // afterCheck(path) between that check and a delete, afterSave(revision) once
196
206
  // the state file was saved.
@@ -258,6 +268,17 @@ export function createRulesetInstaller({
258
268
  return view();
259
269
  }
260
270
  if (!isPlainObject(saved)) return view();
271
+ // A row kept under a host this SynaBun replaced (Gemini CLI → Antigravity) is the new host's row, marked
272
+ // `movedFrom` until reconcile has put the rules where the new host reads them (see reconcileHosts).
273
+ for (const [old, now] of Object.entries(RENAMED_HOSTS)) {
274
+ const hosts = isPlainObject(saved.hosts) ? saved.hosts : null;
275
+ if (hosts && isPlainObject(hosts[old]) && !isPlainObject(hosts[now])) {
276
+ saved.hosts = { ...hosts, [now]: { ...hosts[old], ...(hosts[old].managed === true ? { movedFrom: old } : {}) } };
277
+ delete saved.hosts[old];
278
+ }
279
+ if (Array.isArray(saved.offerAcked)) saved.offerAcked = saved.offerAcked.map((host) => (host === old ? now : host));
280
+ if (isPlainObject(saved.notice) && Array.isArray(saved.notice.hosts)) saved.notice = { ...saved.notice, hosts: unique(saved.notice.hosts.map((host) => (host === old ? now : host))) };
281
+ }
261
282
  if (Number.isSafeInteger(saved.revision) && saved.revision > 0) state.revision = saved.revision;
262
283
  if (typeof saved.autoUpdate === 'boolean') state.autoUpdate = saved.autoUpdate;
263
284
  if (isPlainObject(saved.notice)) state.notice = saved.notice;
@@ -351,15 +372,20 @@ export function createRulesetInstaller({
351
372
 
352
373
  // ── Where things live ──────────────────────────────────────────────────────
353
374
  // Resolved the way the MCP toggle routes resolve them: Claude, Codex and
354
- // Gemini under the home directory, OpenCode under XDG_CONFIG_HOME when set.
375
+ // Antigravity under the home directory, OpenCode in its configuration folder
376
+ // (OPENCODE_CONFIG_DIR, else XDG_CONFIG_HOME/opencode, else ~/.config/opencode),
377
+ // whose opencode.json OpenCode 2 reads (lib/opencode-config.js).
355
378
  function layout() {
356
379
  // The server passes the resolver its /api/opencode/mcp toggle uses, so both always edit the same file.
357
380
  const opencodeConfig = opencodeConfigPath
358
381
  ? resolve(opencodeConfigPath())
359
- : join(env?.XDG_CONFIG_HOME ? join(env.XDG_CONFIG_HOME, 'opencode') : join(home, '.config', 'opencode'), 'config.json');
382
+ : opencodeConfigFilePath(opencodeConfigDir({ env: env || {}, home }));
360
383
  return {
361
384
  claudeDir: join(home, '.claude'),
362
385
  codexHome: join(home, '.codex'),
386
+ // Antigravity's global customization root (rules, skills, mcp_config.json), and the folder above it, where
387
+ // Gemini CLI's GEMINI.md lives (Antigravity reads that file too).
388
+ antigravityDir: join(home, '.gemini', 'config'),
363
389
  geminiDir: join(home, '.gemini'),
364
390
  opencodeDir: dirname(opencodeConfig),
365
391
  opencodeConfig,
@@ -413,7 +439,7 @@ export function createRulesetInstaller({
413
439
  ...codexAccounts().filter((account) => account.kind === 'file').map(({ path, dir }) => ({ path, dir })),
414
440
  ];
415
441
  }
416
- if (host === 'gemini') return [{ path: join(where.geminiDir, 'GEMINI.md'), dir: where.geminiDir }];
442
+ if (host === 'antigravity') return [{ path: join(where.antigravityDir, 'GEMINI.md'), dir: where.antigravityDir, legacyBlock: join(where.geminiDir, 'GEMINI.md') }];
417
443
  return [];
418
444
  }
419
445
  function projectPaths() {
@@ -425,9 +451,12 @@ export function createRulesetInstaller({
425
451
  const where = layout();
426
452
  try {
427
453
  if (host === 'claude') return !!JSON.parse(readFileSync(join(home, '.claude.json'), 'utf8'))?.mcpServers?.SynaBun;
428
- if (host === 'gemini') return !!JSON.parse(readFileSync(join(where.geminiDir, 'settings.json'), 'utf8'))?.mcpServers?.SynaBun;
454
+ if (host === 'antigravity') {
455
+ const text = readFileSync(join(where.antigravityDir, 'mcp_config.json'), 'utf8').replace(/^\uFEFF/, '');
456
+ return text.trim() ? !!JSON.parse(text)?.mcpServers?.SynaBun : false;
457
+ }
429
458
  if (host === 'codex') return /^\[mcp_servers\.SynaBun\]/m.test(readFileSync(join(where.codexHome, 'config.toml'), 'utf8'));
430
- if (host === 'opencode') return !!JSON.parse(readFileSync(where.opencodeConfig, 'utf8'))?.mcp?.SynaBun;
459
+ if (host === 'opencode') return !!mcpServersOf(mergedOpencodeConfig(readOpencodeConfigDocuments(where.opencodeDir))).SynaBun;
431
460
  } catch { /* no config, no registration */ }
432
461
  return false;
433
462
  }
@@ -478,7 +507,7 @@ export function createRulesetInstaller({
478
507
  }
479
508
  const block = blocks[0] || null;
480
509
  // A stamp for another tool is not this host's copy, however untouched it is: never updated, never removed.
481
- if (block && block.host !== host) return { status: 'conflict', text, bytes, detail: `${foreignBlock(host, block, target.path)} Replace does not apply here: take that block out by hand, then install again.` };
510
+ if (block && !ownStamp(host, block.host)) return { status: 'conflict', text, bytes, detail: `${foreignBlock(host, block, target.path)} Replace does not apply here: take that block out by hand, then install again.` };
482
511
  if (HOSTS[host].carrier === 'file') {
483
512
  if (normalise(text) === expected.block) return { status: 'current', text, bytes, block };
484
513
  if (!block) return { status: 'modified', text, bytes, block, detail: `${target.path} has no SynaBun markers, so SynaBun treats it as your own file and never replaces it. Move or delete it, then install again.` };
@@ -511,7 +540,7 @@ export function createRulesetInstaller({
511
540
  /**
512
541
  * The file an `instructions` entry of `configPath` names, or null when the entry is not one plain path: a URL, or
513
542
  * a pattern with glob characters. A leading `~` is the installer's home, and a relative path starts at the
514
- * directory of config.json (never at this process's working directory).
543
+ * directory of opencode.json (never at this process's working directory).
515
544
  */
516
545
  function entryFile(value, configPath) {
517
546
  if (typeof value !== 'string' || !value) return null;
@@ -530,8 +559,7 @@ export function createRulesetInstaller({
530
559
  if (path === resolve(owned)) return true;
531
560
  try { return realpathSync(path) === realpathSync(owned); } catch { return false; }
532
561
  }
533
- function readOpencodeConfig() {
534
- const path = layout().opencodeConfig;
562
+ function readOpencodeConfig(path = layout().opencodeConfig) {
535
563
  const entry = opencodeEntry();
536
564
  const refuse = (why) => ({ path, exists: true, hasEntry: false, cfg: null, text: null, bytes: null, error: `${path} ${why}. SynaBun will not rewrite it: fix the file, or add "${entry}" to its "instructions" list by hand.` });
537
565
  let bytes;
@@ -558,7 +586,7 @@ export function createRulesetInstaller({
558
586
  return { path, exists: true, hasEntry: (cfg.instructions || []).some((value) => entryIsOwnedFile(value, path)), cfg, text, bytes, error: null };
559
587
  }
560
588
  /**
561
- * The text of config.json after `edit()`, accepted only when it parses to
589
+ * The text of opencode.json after `edit()`, accepted only when it parses to
562
590
  * exactly `cfg`. There is no other way to write this file: when the edit
563
591
  * cannot be made on the text, SynaBun refuses rather than write the whole
564
592
  * object out again and lose what the user's file spells its own way.
@@ -570,7 +598,7 @@ export function createRulesetInstaller({
570
598
  } catch { /* text the editor could not follow */ }
571
599
  throw new Error(`${path} could not be edited safely, so SynaBun did not write it. Change its "instructions" list by hand: the entry is "${opencodeEntry()}".`);
572
600
  }
573
- /** What install writes when there is no config.json yet: remove deletes the file only while it still holds exactly this. */
601
+ /** What install writes when there is no opencode.json yet: remove deletes the file only while it still holds exactly this. */
574
602
  function newConfigText(value) {
575
603
  return addToJsonList('{}\n', 'instructions', value);
576
604
  }
@@ -582,7 +610,7 @@ export function createRulesetInstaller({
582
610
  }
583
611
  /**
584
612
  * The `instructions` entries that resolve to SynaBun's owned file and that SynaBun has no record of adding: the
585
- * user's own lines, however they are spelled (`~/...`, relative to config.json, a symlink to the file). One listing
613
+ * user's own lines, however they are spelled (`~/...`, relative to opencode.json, a symlink to the file). One listing
586
614
  * of the recorded string is SynaBun's; every other is theirs. A URL or a glob pattern is never one of them.
587
615
  */
588
616
  function userEntries(row, config) {
@@ -592,13 +620,13 @@ export function createRulesetInstaller({
592
620
  return list.filter((value, index) => index !== mine && entryIsOwnedFile(value, config.path));
593
621
  }
594
622
  /**
595
- * One change to config.json. `plan(config)` answers null (nothing to do) or
623
+ * One change to opencode.json. `plan(config)` answers null (nothing to do) or
596
624
  * {text, done?}; `text: null` deletes the file. The file is replaced only
597
625
  * while it still holds the bytes that were read: a change by another program
598
- * in between is CHANGED_UNDERNEATH, and config.json is left to it.
626
+ * in between is CHANGED_UNDERNEATH, and opencode.json is left to it.
599
627
  */
600
- function editOpencodeConfig(tally, plan) {
601
- const config = readOpencodeConfig();
628
+ function editOpencodeConfig(tally, plan, path = layout().opencodeConfig) {
629
+ const config = readOpencodeConfig(path);
602
630
  if (config.error) throw new Error(config.error);
603
631
  const step = plan(config);
604
632
  if (!step) return;
@@ -611,7 +639,7 @@ export function createRulesetInstaller({
611
639
  tally.changed = true;
612
640
  if (step.done) step.done();
613
641
  }
614
- /** Lists synabun.md in config.json unless it is listed already, and records the string SynaBun added. */
642
+ /** Lists synabun.md in opencode.json unless it is listed already, and records the string SynaBun added. */
615
643
  function addOpencodeEntry(row, tally) {
616
644
  const value = opencodeEntry();
617
645
  let listed = null;
@@ -645,7 +673,7 @@ export function createRulesetInstaller({
645
673
  const mine = ownedEntry(row, config);
646
674
  const others = theirs ? userEntries(row, config) : [];
647
675
  if (mine === null && !others.length) return null;
648
- // A config.json install created goes only while its bytes are still what install wrote. Anything the user
676
+ // An opencode.json install created goes only while its bytes are still what install wrote. Anything the user
649
677
  // added since makes it their file: the entries are edited out and the file stays.
650
678
  if (mine !== null && row.created.includes(config.path) && config.text === newConfigText(mine)) return { text: null };
651
679
  const dropKey = row.created.includes(`${config.path}#instructions`);
@@ -661,6 +689,60 @@ export function createRulesetInstaller({
661
689
  });
662
690
  }
663
691
 
692
+ // ── OpenCode 1's config.json ───────────────────────────────────────────────
693
+ // An older SynaBun listed synabun.md in config.json, which OpenCode 2 never reads. A copy SynaBun manages whose
694
+ // recorded entry is there is moved, at the next boot (reconcile) or install: listed in opencode.json, then the one
695
+ // string SynaBun added is taken out of config.json (the file goes when SynaBun made it and it still holds only that
696
+ // string). A remove takes that string out too. A line the user wrote in config.json is never touched. At a boot, a
697
+ // copy config.json no longer lists (the user took the line out, or the file) is an opt-out, as it was with
698
+ // OpenCode 1: never put back in opencode.json. An install, which the user asked for, lists it whatever config.json says.
699
+ function opencode1ConfigPath() {
700
+ return join(layout().opencodeDir, 'config.json');
701
+ }
702
+ /** The entry an older SynaBun recorded adding to config.json, or null. */
703
+ function opencode1Record(row) {
704
+ const owned = row.instructionsEntry;
705
+ return owned && typeof owned.value === 'string' && samePath(owned.config, opencode1ConfigPath()) ? { config: owned.config, value: owned.value } : null;
706
+ }
707
+ /**
708
+ * Whether config.json still lists the copy (`legacy`: opencode1Record), by any spelling: the line SynaBun added or
709
+ * one of the user's. A config.json SynaBun cannot read as plain JSON cannot say it does not, so it counts as listing.
710
+ */
711
+ function opencode1Listed(legacy) {
712
+ const config = readOpencodeConfig(legacy.config);
713
+ return !!config.error || config.hasEntry;
714
+ }
715
+ /** Takes the string of `legacy` (opencode1Record) out of config.json, and SynaBun's record of what it made there. */
716
+ function removeOpencode1Entry(row, tally, legacy) {
717
+ editOpencodeConfig(tally, (config) => {
718
+ if (!config.exists || !config.cfg) return null;
719
+ const list = [...(config.cfg.instructions || [])];
720
+ const at = list.lastIndexOf(legacy.value);
721
+ if (at < 0) return null;
722
+ if (row.created.includes(config.path) && config.text === newConfigText(legacy.value)) return { text: null };
723
+ const dropKey = row.created.includes(`${config.path}#instructions`);
724
+ list.splice(at, 1);
725
+ const cfg = { ...config.cfg, instructions: list };
726
+ if (!list.length && dropKey) delete cfg.instructions;
727
+ return { text: configText(config.path, cfg, () => removeFromJsonList(config.text, 'instructions', legacy.value, { dropEmptyKey: dropKey })) };
728
+ }, legacy.config);
729
+ row.created = row.created.filter((path) => !samePath(path, legacy.config) && path !== `${legacy.config}#instructions`);
730
+ }
731
+ /**
732
+ * A managed copy listed in config.json only: listed in opencode.json, and SynaBun's string taken out of
733
+ * config.json (a failure there leaves it with a warning: OpenCode 2 does not read that file). False when the row
734
+ * has no such record.
735
+ */
736
+ function moveOpencode1Entry(row, tally) {
737
+ const legacy = opencode1Record(row);
738
+ if (!legacy) return false;
739
+ addOpencodeEntry(row, tally);
740
+ try { removeOpencode1Entry(row, tally, legacy); } catch (error) {
741
+ tally.warnings.push(`${legacy.config} still lists ${legacy.value} under "instructions" (OpenCode 2 does not read that file): ${error?.message || error}`);
742
+ }
743
+ return true;
744
+ }
745
+
664
746
  // ── Writing ────────────────────────────────────────────────────────────────
665
747
  /**
666
748
  * The pasted copies in `text`, sorted by what install may do with them:
@@ -700,6 +782,45 @@ export function createRulesetInstaller({
700
782
  }
701
783
  tally.changed = true;
702
784
  }
785
+ /**
786
+ * The block an earlier SynaBun wrote where this host's tool also reads rules, under a name this host replaced
787
+ * (Gemini CLI's ~/.gemini/GEMINI.md, host=gemini, which Antigravity reads beside its own ~/.gemini/config/GEMINI.md):
788
+ * once the rules are where the new host keeps them, an untouched old block goes, or the tool would load them twice.
789
+ * An edited one is the user's: it stays, with a warning. A file that held nothing else and that SynaBun created is
790
+ * deleted; any other file keeps everything but the block. Never forced.
791
+ */
792
+ function moveLegacyBlock(host, file, row, tally) {
793
+ let bytes;
794
+ try { bytes = readBytes(file); } catch { return; }
795
+ if (bytes === null) return;
796
+ const text = bytes.toString('utf8');
797
+ const { blocks, conflict } = findBlocks(text);
798
+ if (conflict) {
799
+ tally.warnings.push(`${conflict.message} in ${file}, which ${HOSTS[host].label} also reads, so SynaBun left it as it is: remove the old SynaBun marker lines by hand.`);
800
+ return;
801
+ }
802
+ const block = blocks[0];
803
+ if (!block || !ownStamp(host, block.host)) return;
804
+ if (!isPristine(block)) {
805
+ tally.warnings.push(`The SynaBun block an earlier version wrote in ${file} was edited, so it stays there. ${HOSTS[host].label} reads that file as well: take that block out by hand, or the rules are loaded twice.`);
806
+ return;
807
+ }
808
+ const next = removeBlock(text);
809
+ const created = Array.isArray(row.created) && row.created.some((path) => samePath(path, file));
810
+ try {
811
+ tally.backup(backedUp(file, host, () => {
812
+ if (created && !isSymlink(file) && withoutBom(next).trim() === '') unlinkUnchanged(file, text);
813
+ else commit(file, next, text);
814
+ }));
815
+ } catch (error) {
816
+ if (error?.code !== 'CHANGED_UNDERNEATH') throw error;
817
+ tally.warnings.push(`${file} changed while SynaBun was moving its old rules out of it, so it was left as it is.`);
818
+ return;
819
+ }
820
+ tally.changed = true;
821
+ row.paths = row.paths.filter((path) => !samePath(path, file));
822
+ row.created = row.created.filter((path) => !samePath(path, file));
823
+ }
703
824
  /**
704
825
  * One carrier. Returns the status it ended in; writes only when the copy is
705
826
  * missing, untouched and old, or (forced) one well-formed copy that was
@@ -847,8 +968,7 @@ export function createRulesetInstaller({
847
968
  if (first.block) out.installedVersion = first.block.version;
848
969
  if (host === 'opencode') {
849
970
  const config = readOpencodeConfig();
850
- const sideFiles = ['opencode.json', 'opencode.jsonc'].filter((name) => existsSync(join(primary.dir, name)));
851
- if (sideFiles.length) out.notes = [`OpenCode also reads ${sideFiles.join(' and ')} in ${primary.dir}; SynaBun writes config.json, the same file its MCP toggle uses.`];
971
+ if (existsSync(join(primary.dir, 'opencode.jsonc'))) out.notes = [`OpenCode also reads opencode.jsonc in ${primary.dir}; SynaBun writes opencode.json, the same file its MCP toggle uses.`];
852
972
  if (config.error) return { ...out, state: 'error', error: config.error, detail: config.error };
853
973
  if (first.status !== 'missing' && !config.hasEntry) {
854
974
  unlisted = `${config.path} does not list it under "instructions", so OpenCode does not load it.`;
@@ -858,7 +978,7 @@ export function createRulesetInstaller({
858
978
  return { ...out, state: 'not-installed', installedVersion: null, detail: `${primary.path} exists, but ${unlisted}` };
859
979
  }
860
980
  }
861
- // A line in config.json that SynaBun did not add points at the file: a remove keeps both unless it is forced.
981
+ // A line in opencode.json that SynaBun did not add points at the file: a remove keeps both unless it is forced.
862
982
  if (first.status !== 'missing' && userEntries(row, config).length) out.entry = 'user';
863
983
  }
864
984
  if (first.status === 'missing' && RANK[worst.status] < RANK.error) return { ...out, installedVersion: null };
@@ -896,7 +1016,7 @@ export function createRulesetInstaller({
896
1016
  };
897
1017
  for (const target of targets('claude')) add(target.legacyFile, 'claude', 'global');
898
1018
  for (const target of targets('codex')) add(target.path, 'codex', 'global');
899
- for (const target of targets('gemini')) add(target.path, 'gemini', 'global');
1019
+ for (const target of targets('antigravity')) { add(target.path, 'antigravity', 'global'); add(target.legacyBlock, 'antigravity', 'global'); }
900
1020
  for (const target of targets('opencode')) add(target.legacyFile, 'opencode', 'global');
901
1021
  for (const dir of projectPaths()) {
902
1022
  for (const [name, host] of PROJECT_FILES) add(join(dir, name), host, 'project');
@@ -991,7 +1111,8 @@ export function createRulesetInstaller({
991
1111
  stripLegacy(host, target.legacyFile, tally);
992
1112
  }
993
1113
  }
994
- if (host === 'opencode') addOpencodeEntry(row, tally);
1114
+ if (host === 'opencode' && !moveOpencode1Entry(row, tally)) addOpencodeEntry(row, tally);
1115
+ for (const target of list) if (target.legacyBlock) moveLegacyBlock(host, target.legacyBlock, row, tally);
995
1116
 
996
1117
  Object.assign(row, {
997
1118
  managed: true,
@@ -1055,10 +1176,10 @@ export function createRulesetInstaller({
1055
1176
  * first; damaged markers, a block stamped for another tool, a symlinked owned
1056
1177
  * file and a file that cannot be read are refused either way.
1057
1178
  *
1058
- * OpenCode: a line in config.json that points at the owned file and that
1179
+ * OpenCode: a line in opencode.json that points at the owned file and that
1059
1180
  * SynaBun did not add keeps the file too (`kept`, reason `listed-in-config`):
1060
1181
  * nothing is ever left pointing at a file SynaBun deleted. With `force` that
1061
- * line goes as well, after a backup of config.json, and then the file.
1182
+ * line goes as well, after a backup of opencode.json, and then the file.
1062
1183
  *
1063
1184
  * Symlinks at a block carrier (AGENTS.md, GEMINI.md): the block is taken out
1064
1185
  * of the file the link points at and the link stays, exactly as install wrote
@@ -1076,7 +1197,7 @@ export function createRulesetInstaller({
1076
1197
  * True while a copy that keeps a removal open is still on disk: one SynaBun
1077
1198
  * should have taken and could not. That is damaged markers, a file that
1078
1199
  * cannot be read, an untouched copy of this host's rules (behind a symlink,
1079
- * or held back by another refusal), and for OpenCode a config.json that
1200
+ * or held back by another refusal), and for OpenCode an opencode.json that
1080
1201
  * cannot be edited while SynaBun's entry is on record. A copy the user
1081
1202
  * edited, a file without markers and a block stamped for another tool are
1082
1203
  * not: the keep rule leaves the first two to the user, and the third was
@@ -1126,7 +1247,7 @@ export function createRulesetInstaller({
1126
1247
  const created = new Set(row.created);
1127
1248
  // Every place a copy can be: the host's carriers, the row's paths, and what an unfinished removal recorded.
1128
1249
  const recorded = Array.isArray(row.removal?.paths) ? row.removal.paths.filter((path) => typeof path === 'string') : [];
1129
- const paths = unique([...list.map((target) => target.path), ...row.paths, ...recorded]);
1250
+ const paths = unique([...list.map((target) => target.path), ...list.map((target) => target.legacyBlock).filter(Boolean), ...row.paths, ...recorded]);
1130
1251
  /** Intent first: the paths about to go are saved before the first of them is touched. */
1131
1252
  const recordIntent = (planned) => {
1132
1253
  row.removal = { at: stamp(), error: INTERRUPTED, paths: unique(planned) };
@@ -1169,6 +1290,11 @@ export function createRulesetInstaller({
1169
1290
  if (go && doomed.length) recordIntent(doomed.map((entry) => entry.path));
1170
1291
  if (go && together) {
1171
1292
  try { removeOpencodeEntry(row, tally, { theirs: force && doomed.length > 0 }); } catch (error) { refuse(layout().opencodeConfig, 'error', error?.message || String(error)); }
1293
+ // The string an older SynaBun added to OpenCode 1's config.json goes too (OpenCode 2 never read it).
1294
+ const legacy = opencode1Record(row);
1295
+ if (legacy) {
1296
+ try { removeOpencode1Entry(row, tally, legacy); } catch (error) { tally.warnings.push(`${legacy.config} still lists ${legacy.value} under "instructions": ${error?.message || error}`); }
1297
+ }
1172
1298
  }
1173
1299
  if (!(together && refused.length)) {
1174
1300
  for (const { path, text } of go ? doomed : []) {
@@ -1196,7 +1322,7 @@ export function createRulesetInstaller({
1196
1322
  if (conflict) { refuse(path, 'conflict', `${conflict.message} in ${path}. SynaBun will not guess: remove the SynaBun marker lines by hand, then remove again.`); continue; }
1197
1323
  const block = blocks[0];
1198
1324
  if (!block) continue;
1199
- if (block.host !== host) { refuse(path, 'conflict', `${foreignBlock(host, block, path)} Take that block out by hand if you no longer want it.`); continue; }
1325
+ if (!ownStamp(host, block.host)) { refuse(path, 'conflict', `${foreignBlock(host, block, path)} Take that block out by hand if you no longer want it.`); continue; }
1200
1326
  const pristine = isPristine(block);
1201
1327
  if (!force && !pristine) {
1202
1328
  left.push({ path, reason: 'edited', message: `The SynaBun block in ${path} was edited, so SynaBun left it in place and no longer manages it.` });
@@ -1253,7 +1379,7 @@ export function createRulesetInstaller({
1253
1379
  // (`created`, OpenCode's entry) stays on record, so a forced remove or a Replace can still clean up. The same
1254
1380
  // row for a refusal that leaves nothing to wait for (a block stamped for another tool, a copy that turned out
1255
1381
  // edited): the host is opted out, and no removal is kept open over a file that was never SynaBun's to take.
1256
- // `paths` are places a copy of the rules is: config.json, which a refusal can name, is not one of them.
1382
+ // `paths` are places a copy of the rules is: opencode.json, which a refusal can name, is not one of them.
1257
1383
  const config = host === 'opencode' ? layout().opencodeConfig : null;
1258
1384
  Object.assign(row, {
1259
1385
  managed: false, installedVersion: null, installedSha: null, path: primary.path,
@@ -1349,7 +1475,24 @@ export function createRulesetInstaller({
1349
1475
  const config = host === 'opencode' ? readOpencodeConfig() : null;
1350
1476
  if (config?.error) { states[host] = 'error'; continue; }
1351
1477
  const first = isDir(primary.dir) ? inspect(host, primary, expected) : { status: 'missing' };
1352
- if (first.status === 'missing' || (config && !config.hasEntry)) {
1478
+ // Listed by an older SynaBun in OpenCode 1's config.json only: moved to opencode.json, never an opt-out. A copy
1479
+ // config.json does not list any more is not moved: the user took it out, which is the opt-out below.
1480
+ const older = config && first.status !== 'missing' && !config.hasEntry ? opencode1Record(row) : null;
1481
+ const moving = older !== null && opencode1Listed(older);
1482
+ if (first.status === 'missing' && row.movedFrom && isDir(primary.dir)) {
1483
+ // A host this SynaBun replaced (Gemini CLI → Antigravity) was managed: its rules go where the new host reads
1484
+ // them, and the old block goes (installHost moves it). Not an opt-out: nothing was deleted by the user.
1485
+ const moved = installHost(state, host, { force: false }, call);
1486
+ if (moved.ok) { delete row.movedFrom; updated.push(host); to = expected.version; from = from || row.installedVersion || null; }
1487
+ states[host] = hostStatus(host, state).state;
1488
+ continue;
1489
+ }
1490
+ if (first.status === 'missing' && row.movedFrom) {
1491
+ // The new host's folder is not there yet (Antigravity not installed): nothing to move to; asked again later.
1492
+ states[host] = 'not-installed';
1493
+ continue;
1494
+ }
1495
+ if (first.status === 'missing' || (config && !config.hasEntry && !moving)) {
1353
1496
  // The user deleted it: an opt-out, never a reason to put it back. (A copy SynaBun's own removal took is
1354
1497
  // not this case: that removal is on record and was dealt with above.)
1355
1498
  Object.assign(row, { managed: false, optedOutAt: stamp() });
@@ -1358,6 +1501,7 @@ export function createRulesetInstaller({
1358
1501
  continue;
1359
1502
  }
1360
1503
  const tally = call.tally(host);
1504
+ if (moving) moveOpencode1Entry(row, tally);
1361
1505
  const known = new Set(row.paths.map((path) => realKey(path)));
1362
1506
  let primaryCurrent = first.status === 'current';
1363
1507
  for (const target of list) {
@@ -2,7 +2,7 @@
2
2
  // SynaBun — one entry of a JSON list, edited as text (pure, no fs)
3
3
  // ═══════════════════════════════════════════
4
4
  //
5
- // OpenCode's config.json belongs to the user. Parsing it and writing it back
5
+ // OpenCode's opencode.json belongs to the user. Parsing it and writing it back
6
6
  // would re-indent it, re-space it and drop whatever JSON.stringify spells
7
7
  // differently, all to add one string to one list. These two functions change
8
8
  // only the characters of that entry (and of the key, when SynaBun adds or takes
@@ -18,7 +18,7 @@ import { normalise, sha12 } from './normalise.js';
18
18
 
19
19
  export { normalise, sha12 };
20
20
 
21
- export const RULESET_HOSTS = Object.freeze(['claude', 'codex', 'opencode', 'gemini', 'cursor']);
21
+ export const RULESET_HOSTS = Object.freeze(['claude', 'codex', 'opencode', 'antigravity', 'cursor']);
22
22
  export const RULESETS_DIR = resolve(dirname(fileURLToPath(import.meta.url)), '..', '..', 'templates', 'rulesets');
23
23
 
24
24
  const HOST_SLOT = '<!-- host -->';
@@ -3,7 +3,7 @@ import { normalizeMemoryEvents, ingestMemoryEvents } from '../../mcp-server/dist
3
3
  import { detectProject } from '../../mcp-server/dist/config.js';
4
4
  /**
5
5
  * Session Cache Builder — populates session_cache + session_fts for
6
- * Claude Code, Codex CLI, and OpenCode so the Resume surfaces can do
6
+ * Claude Code, Codex CLI, OpenCode and Antigravity so the Resume surfaces can do
7
7
  * full-body keyword search via FTS5.
8
8
  *
9
9
  * Per-provider rebuilders walk the provider's session storage, extract
@@ -24,7 +24,8 @@ import {
24
24
  } from './db.js';
25
25
  import { parseLine } from './session-chunker.js';
26
26
  import { listCodexSessionsFromAccounts } from './codex-session-catalog.js';
27
- import { opencodeDbFlavor, sessionTablesFor, v2MessageText } from './opencode-db-schema.js';
27
+ import { OPENCODE_SESSION_TABLES, hasOpencodeSessionTables, v2MessageText } from './opencode-db-schema.js';
28
+ import { listAntigravityConversations, parseAntigravityTranscript, readTranscriptText } from './antigravity/transcripts.js';
28
29
 
29
30
  const MAX_BODY = 256 * 1024;
30
31
  const MAX_MSG_CHARS = 8 * 1024;
@@ -381,18 +382,15 @@ export function rebuildCodexCache({ project, projects, accounts, onProgress } =
381
382
 
382
383
  // --- OpenCode ---
383
384
 
384
- // `protocol`: the OpenCode major SynaBun talks to (lib/opencode-db-schema.js
385
- // opencodeDbFlavor): OpenCode 2 keeps its sessions in session_v2 and their text
386
- // in session_message rows, in the same database file as OpenCode 1's tables.
387
- export function rebuildOpencodeCache({ getOpencodeDb, onProgress, protocol = null } = {}) {
385
+ // OpenCode 2 keeps its sessions in session_v2 and their text in session_message rows
386
+ // (lib/opencode-db-schema.js); a file without those tables has nothing to index.
387
+ export function rebuildOpencodeCache({ getOpencodeDb, onProgress } = {}) {
388
388
  const emit = onProgress || (() => {});
389
389
  if (typeof getOpencodeDb !== 'function') return { sessions: 0, updated: 0 };
390
390
 
391
391
  const ocdb = getOpencodeDb();
392
- if (!ocdb) return { sessions: 0, updated: 0 };
393
- const flavor = opencodeDbFlavor(ocdb, protocol);
394
- if (!flavor) return { sessions: 0, updated: 0 };
395
- const tables = sessionTablesFor(flavor);
392
+ if (!ocdb || !hasOpencodeSessionTables(ocdb)) return { sessions: 0, updated: 0 };
393
+ const tables = OPENCODE_SESSION_TABLES;
396
394
 
397
395
  let sessions;
398
396
  try {
@@ -409,29 +407,19 @@ export function rebuildOpencodeCache({ getOpencodeDb, onProgress, protocol = nul
409
407
  let total = sessions.length;
410
408
  let updated = 0;
411
409
 
412
- // OpenCode 1 schema: message.data (JSON w/ role+metadata) + part.data (JSON w/ type+text).
413
- // Pull parts per message, decode JSON, grab text where type === 'text'.
414
- // OpenCode 2: one session_message row per message, its text in `data`
415
- // (v2MessageText); read as the same { part_id, part_created, pdata, mdata } rows.
410
+ // One session_message row per message, its text in `data` (v2MessageText); read as
411
+ // { part_id, part_created, pdata, mdata } rows.
416
412
  let partStmt;
417
413
  try {
418
- partStmt = flavor === 'v2'
419
- ? (() => {
420
- const rows = ocdb.prepare(`SELECT id, type, time_created, data FROM session_message
421
- WHERE session_id = ? AND type IN ('user', 'assistant')
422
- ORDER BY seq ASC`);
423
- return {
424
- all: (sessionId) => rows.all(sessionId).map((row) => {
425
- const said = v2MessageText(row.type, row.data);
426
- return said ? { part_id: row.id, part_created: row.time_created, pdata: JSON.stringify({ type: 'text', text: said.text }), mdata: JSON.stringify({ role: said.role }) } : null;
427
- }).filter(Boolean),
428
- };
429
- })()
430
- : ocdb.prepare(`SELECT p.id AS part_id, p.time_created AS part_created, p.data AS pdata, m.data AS mdata
431
- FROM part p
432
- LEFT JOIN message m ON m.id = p.message_id
433
- WHERE p.session_id = ?
434
- ORDER BY p.time_created ASC`);
414
+ const rows = ocdb.prepare(`SELECT id, type, time_created, data FROM session_message
415
+ WHERE session_id = ? AND type IN ('user', 'assistant')
416
+ ORDER BY seq ASC`);
417
+ partStmt = {
418
+ all: (sessionId) => rows.all(sessionId).map((row) => {
419
+ const said = v2MessageText(row.type, row.data);
420
+ return said ? { part_id: row.id, part_created: row.time_created, pdata: JSON.stringify({ type: 'text', text: said.text }), mdata: JSON.stringify({ role: said.role }) } : null;
421
+ }).filter(Boolean),
422
+ };
435
423
  } catch { partStmt = null; }
436
424
 
437
425
  for (const row of sessions) {
@@ -506,6 +494,68 @@ export function rebuildOpencodeCache({ getOpencodeDb, onProgress, protocol = nul
506
494
  return { sessions: total, updated };
507
495
  }
508
496
 
497
+ // --- Antigravity ---
498
+
499
+ // agy keeps one transcript.jsonl per conversation (lib/antigravity/transcripts.js). Every conversation it holds,
500
+ // SynaBun's brain and run homes included, is queued for memory capture; the user's own (the panel's and a terminal
501
+ // agy's, the only ones the panel can load again) also go into the Resume index, titled as Antigravity titles them.
502
+ // A conversation unchanged since the last pass (size, time, folder, title) is not read again. `only`: one
503
+ // conversation (a panel turn just ended), the others left as they are. Request/timer paths read at most
504
+ // MAX_BODY bytes per transcript: the index is bounded; full transcripts remain available to memory capture.
505
+ export function rebuildAntigravityCache({ stores = [], only = null, onProgress, list = listAntigravityConversations, read = readTranscriptText } = {}) {
506
+ const emit = onProgress || (() => {});
507
+ let conversations;
508
+ try { conversations = list(stores); } catch { return { sessions: 0, updated: 0 }; }
509
+ if (only) conversations = conversations.filter((c) => c.sessionId === only);
510
+ const listed = new Set(conversations.filter((c) => c.store === 'user').map((c) => c.sessionId));
511
+ const total = listed.size;
512
+ let updated = 0;
513
+ for (const c of conversations) {
514
+ try {
515
+ queueMemoryCapture({ host: 'antigravity', sessionId: c.sessionId, filePath: c.transcript, cwd: c.cwd || undefined, project: c.cwd ? detectProject(c.cwd) : 'global', size: c.size });
516
+ } catch { /* memory capture is best effort */ }
517
+ if (c.store !== 'user') continue;
518
+ const mtimeIso = new Date(c.mtimeMs).toISOString();
519
+ const existing = getSessionCacheEntry(c.sessionId, 'antigravity');
520
+ if (existing && !existing.deleted && Number(existing.file_size) === c.size && existing.file_mtime === mtimeIso
521
+ && (existing.project_path || null) === (c.cwd || null) && (!c.title || existing.first_prompt === c.title)) continue;
522
+ const parsed = parseAntigravityTranscript(read(c.transcript, { maxBytes: MAX_BODY }));
523
+ let body = '';
524
+ for (const message of parsed.messages) {
525
+ if (message.role !== 'user' && message.role !== 'assistant') continue;
526
+ if (message.text) body = appendBody(body, message.text.slice(0, MAX_MSG_CHARS));
527
+ }
528
+ const firstPrompt = c.title || parsed.firstPrompt;
529
+ const project = c.cwd ? basename(c.cwd) : null;
530
+ upsertSessionCache({
531
+ session_id: c.sessionId,
532
+ provider: 'antigravity',
533
+ project,
534
+ project_path: c.cwd,
535
+ git_branch: null,
536
+ first_prompt: firstPrompt,
537
+ message_count: parsed.messageCount,
538
+ created: parsed.created,
539
+ modified: c.updatedAt || parsed.modified || mtimeIso,
540
+ file_path: c.transcript,
541
+ file_size: c.size,
542
+ file_mtime: mtimeIso,
543
+ body_size: body.length,
544
+ deleted: 0,
545
+ });
546
+ upsertSessionFts({ session_id: c.sessionId, provider: 'antigravity', project, first_prompt: firstPrompt, body });
547
+ updated++;
548
+ emit({ type: 'cache:session', provider: 'antigravity', sessionId: c.sessionId, done: updated, total });
549
+ }
550
+ // A conversation Antigravity no longer has (deleted there, or its folder cleared) leaves Resume.
551
+ if (!only) {
552
+ for (const cached of listSessionCache('antigravity', { limit: 100000 })) {
553
+ if (!listed.has(cached.session_id) && !cached.deleted) markSessionDeleted(cached.session_id, 'antigravity', true);
554
+ }
555
+ }
556
+ return { sessions: total, updated };
557
+ }
558
+
509
559
  // --- Single-session refresh (for piggyback from session-indexer) ---
510
560
 
511
561
  export function updateSessionCacheEntry(provider, sessionId, opts = {}) {