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,273 @@
1
+ // ═══════════════════════════════════════════
2
+ // SynaBun — Antigravity's models and past sessions, asked of the CLI itself
3
+ // ═══════════════════════════════════════════
4
+ //
5
+ // Models: what an ACP session offers, because SynaBun drives every Antigravity brain, run and panel
6
+ // over ACP. agy 1.4.12's ACP sessions offer a model option of base models (gemini-4-argon,
7
+ // gemini-3.8-flash) and a thinking-level option (low / medium / high), and list each pair as one
8
+ // id (`models.availableModels`: gemini-4-argon-high …). `agy models` lists more (Claude and GPT-OSS
9
+ // models its own TUI runs), which ACP refuses ("Unknown model ID"), and it has no
10
+ // `--output-format` in 1.4.12. So the list is read from a short-lived `agy acp` in a throwaway
11
+ // home (lib/antigravity/home.js; the sign-in is the keychain's, nothing of the user's changes),
12
+ // and `agy models` (text, or JSON from a later agy) is only the fallback of an agy without ACP.
13
+ // Nothing here names a model of its own: what Antigravity offers is the list.
14
+ //
15
+ // Sessions: ACP session/list on a short-lived `agy acp` (lib/antigravity/acp-connection.js),
16
+ // page by page, grouped under SynaBun's registered projects for the Resume window.
17
+ // Both answer `{ ..., error, authRequired }` instead of throwing: a CLI that is
18
+ // missing, signed out or slow is a state the page shows.
19
+
20
+ import { spawn as nodeSpawn } from 'node:child_process';
21
+ import { mkdtempSync, rmSync } from 'node:fs';
22
+ import { tmpdir } from 'node:os';
23
+ import { basename, join, resolve, sep } from 'node:path';
24
+ import { acpErrorInfo, createAcpConnection, isAuthRequired, redactSecrets } from './acp-connection.js';
25
+
26
+ const MODELS_TIMEOUT_MS = 30_000;
27
+ const MAX_OUTPUT = 2 * 1024 * 1024;
28
+ /** Antigravity's thinking levels, lowest first (`--effort` takes low … max; ACP sessions offer what each model has). */
29
+ export const ANTIGRAVITY_THINKING_LEVELS = Object.freeze(['minimal', 'low', 'medium', 'high', 'xhigh', 'max']);
30
+ const LEVEL_SUFFIX = new RegExp(`^(.+)-(${ANTIGRAVITY_THINKING_LEVELS.join('|')})$`);
31
+
32
+ /**
33
+ * An Antigravity model id as its base model and thinking level: "gemini-4-argon-high" → { model: 'gemini-4-argon',
34
+ * effort: 'high' }. `known` (base ids, optional): the split is made only when the base is one of them. An id
35
+ * without a level suffix is its own base ({ model, effort: null }).
36
+ */
37
+ export function splitAntigravityModel(id, known = null) {
38
+ const text = String(id || '').trim();
39
+ const match = LEVEL_SUFFIX.exec(text);
40
+ if (!match) return { model: text || null, effort: null };
41
+ const list = known instanceof Set ? known : Array.isArray(known) ? new Set(known) : null;
42
+ if (list && !list.has(match[1]) && list.has(text)) return { model: text, effort: null };
43
+ if (list && !list.has(match[1])) return { model: text, effort: null };
44
+ return { model: match[1], effort: match[2] };
45
+ }
46
+
47
+ /**
48
+ * The models an ACP session offers ({ models, configOptions } of session/new or session/resume):
49
+ * [{ id, label, efforts, default? }], one row per base model, its thinking levels from the session's own
50
+ * model × level ids (else the level option's values). [] when the session lists none.
51
+ */
52
+ export function antigravitySessionModels(session) {
53
+ const options = Array.isArray(session?.configOptions) ? session.configOptions : [];
54
+ const modelOption = options.find((option) => option?.category === 'model' || option?.id === 'model');
55
+ const levelOption = options.find((option) => option?.category === 'thought_level' || option?.id === 'thought_level');
56
+ const flat = (option) => {
57
+ const out = [];
58
+ for (const entry of Array.isArray(option?.options) ? option.options : []) {
59
+ for (const value of Array.isArray(entry?.options) ? entry.options : [entry]) {
60
+ if (value && value.value !== undefined && value.value !== null) out.push({ value: String(value.value), name: typeof value.name === 'string' ? value.name : String(value.value), description: typeof value.description === 'string' ? value.description : '' });
61
+ }
62
+ }
63
+ return out;
64
+ };
65
+ const levels = flat(levelOption).map((entry) => entry.value);
66
+ const available = Array.isArray(session?.models?.availableModels) ? session.models.availableModels : [];
67
+ const bases = flat(modelOption);
68
+ const known = new Set(bases.map((entry) => entry.value));
69
+ // A session without a model option still names its model × level pairs: their bases are the models.
70
+ if (!bases.length) {
71
+ for (const row of available) {
72
+ const { model } = splitAntigravityModel(row?.modelId);
73
+ if (model && !known.has(model)) { known.add(model); bases.push({ value: model, name: String(row?.name || model).replace(/\s*\([^)]*\)\s*$/, ''), description: '' }); }
74
+ }
75
+ }
76
+ const efforts = new Map();
77
+ for (const row of available) {
78
+ const { model, effort } = splitAntigravityModel(row?.modelId, known);
79
+ if (model && effort) { if (!efforts.has(model)) efforts.set(model, []); efforts.get(model).push(effort); }
80
+ }
81
+ const current = modelOption?.currentValue !== undefined ? String(modelOption.currentValue) : splitAntigravityModel(session?.models?.currentModelId, known).model;
82
+ const order = (list) => [...new Set(list)].sort((a, b) => ANTIGRAVITY_THINKING_LEVELS.indexOf(a) - ANTIGRAVITY_THINKING_LEVELS.indexOf(b));
83
+ return bases.map((entry) => {
84
+ const row = { id: entry.value, label: entry.name || entry.value };
85
+ if (entry.description) row.description = entry.description;
86
+ const own = efforts.get(entry.value);
87
+ const list = own?.length ? order(own) : (entry.value === current && levels.length ? order(levels) : []);
88
+ if (list.length) row.efforts = list;
89
+ if (entry.value === current) row.default = true;
90
+ return row;
91
+ });
92
+ }
93
+
94
+ /** Rows from `agy models` text output: one `<id>\t<label>` line per model (status lines without a tab are skipped). */
95
+ export function parseAntigravityModelLines(text) {
96
+ const rows = [];
97
+ const seen = new Set();
98
+ for (const line of String(text || '').split(/\r?\n/)) {
99
+ const [id, ...rest] = line.split('\t');
100
+ const key = String(id || '').trim();
101
+ if (!key || !rest.length || seen.has(key) || /\s/.test(key)) continue;
102
+ seen.add(key);
103
+ rows.push({ id: key, label: rest.join('\t').trim() || key });
104
+ }
105
+ return rows;
106
+ }
107
+
108
+ const pick = (row, keys) => {
109
+ for (const key of keys) {
110
+ const value = row?.[key];
111
+ if (typeof value === 'string' && value.trim()) return value.trim();
112
+ }
113
+ return '';
114
+ };
115
+
116
+ /** Rows from a JSON model list (a later agy's `agy models`, a stand-in): [{ id, label, description?, default? }] (never throws). */
117
+ export function parseAntigravityModels(text) {
118
+ let data;
119
+ try { data = JSON.parse(String(text || '').trim()); } catch { return []; }
120
+ const list = Array.isArray(data) ? data
121
+ : Array.isArray(data?.models) ? data.models
122
+ : Array.isArray(data?.availableModels) ? data.availableModels
123
+ : Array.isArray(data?.data) ? data.data : [];
124
+ const rows = [];
125
+ const seen = new Set();
126
+ for (const entry of list) {
127
+ if (typeof entry === 'string') {
128
+ if (entry.trim() && !seen.has(entry.trim())) { seen.add(entry.trim()); rows.push({ id: entry.trim(), label: entry.trim() }); }
129
+ continue;
130
+ }
131
+ if (!entry || typeof entry !== 'object') continue;
132
+ const id = pick(entry, ['id', 'model_id', 'modelId', 'slug', 'model', 'value', 'name']);
133
+ if (!id || seen.has(id)) continue;
134
+ seen.add(id);
135
+ const row = { id, label: pick(entry, ['display_name', 'displayName', 'label', 'name']) || id };
136
+ const description = pick(entry, ['description', 'tagline', 'summary']);
137
+ if (description) row.description = description;
138
+ if (entry.is_default === true || entry.isDefault === true || entry.default === true || entry.selected === true || entry.current === true) row.default = true;
139
+ const efforts = Array.isArray(entry.efforts) ? entry.efforts : Array.isArray(entry.thinking_levels) ? entry.thinking_levels : Array.isArray(entry.effort_levels) ? entry.effort_levels : null;
140
+ if (efforts) row.efforts = efforts.map((e) => (typeof e === 'string' ? e : e?.id || e?.value || e?.name)).filter((e) => typeof e === 'string' && e);
141
+ rows.push(row);
142
+ }
143
+ return rows;
144
+ }
145
+
146
+ /**
147
+ * The models Antigravity offers SynaBun: those of an ACP session in a throwaway home (antigravitySessionModels),
148
+ * else (an agy without ACP) `agy models`. `launch`: { command, args } of the CLI (null: not installed).
149
+ * Answers { models, source: 'live' | 'unavailable', via: 'acp' | 'cli', error?, authRequired? }.
150
+ */
151
+ export async function listAntigravityModels({ launch, env = process.env, spawnImpl = nodeSpawn, connect = createAcpConnection, timeoutMs = MODELS_TIMEOUT_MS, tempRoot = tmpdir() } = {}) {
152
+ if (!launch?.command) return { models: [], source: 'unavailable', error: 'The Antigravity CLI (agy) is not installed.', cliMissing: true };
153
+ let scratch = null;
154
+ let conn = null;
155
+ let acpError = null;
156
+ try {
157
+ scratch = mkdtempSync(join(tempRoot, 'synabun-agy-models-'));
158
+ conn = connect({ command: launch.command, args: launch.args || [], acpArgs: ['--gemini-dir', scratch], env, cwd: scratch, spawnImpl, clientInfo: { name: 'synabun', title: 'SynaBun', version: '0' } });
159
+ await conn.initialize();
160
+ const session = await conn.request('session/new', { cwd: scratch, mcpServers: [] }, { timeoutMs });
161
+ const models = antigravitySessionModels(session);
162
+ // The plan the sign-in is on, as the session says it (_meta.antigravity.tier: "Google AI Pro" …).
163
+ const tier = typeof session?._meta?.antigravity?.tier?.name === 'string' ? session._meta.antigravity.tier.name : null;
164
+ try { if (session?.sessionId) await conn.request('session/close', { sessionId: session.sessionId }, { timeoutMs: 5_000 }); } catch { /* the home goes anyway */ }
165
+ if (models.length) return { models, source: 'live', via: 'acp', signedIn: true, tier };
166
+ acpError = { message: 'The Antigravity session offered no models.' };
167
+ } catch (error) {
168
+ if (isAuthRequired(error)) return { models: [], source: 'unavailable', error: 'Antigravity is not signed in.', authRequired: true, signedIn: false };
169
+ acpError = acpErrorInfo(error);
170
+ } finally {
171
+ try { await conn?.close(); } catch { /* gone */ }
172
+ if (scratch) { try { rmSync(scratch, { recursive: true, force: true }); } catch { /* the temp folder's own cleanup */ } }
173
+ }
174
+ const viaCli = await listAntigravityCliModels({ launch, env, spawnImpl, timeoutMs });
175
+ if (viaCli.models.length) return viaCli;
176
+ return { ...viaCli, error: viaCli.error || acpError?.message || 'Antigravity listed no models.' };
177
+ }
178
+
179
+ /**
180
+ * `agy models` (its text lines; JSON from an agy that prints JSON): the fallback of an agy whose ACP session
181
+ * could not list models. Answers { models, source, via: 'cli', error?, authRequired? }.
182
+ */
183
+ export function listAntigravityCliModels({ launch, env = process.env, spawnImpl = nodeSpawn, timeoutMs = MODELS_TIMEOUT_MS } = {}) {
184
+ if (!launch?.command) return Promise.resolve({ models: [], source: 'unavailable', via: 'cli', error: 'The Antigravity CLI (agy) is not installed.', cliMissing: true });
185
+ return new Promise((resolveResult) => {
186
+ let stdout = '';
187
+ let stderr = '';
188
+ let settled = false;
189
+ let child;
190
+ const finish = (result) => { if (!settled) { settled = true; clearTimeout(timer); resolveResult(result); } };
191
+ try {
192
+ child = spawnImpl(launch.command, [...(launch.args || []), 'models'], { env, stdio: ['ignore', 'pipe', 'pipe'], windowsHide: true });
193
+ } catch (error) {
194
+ resolveResult({ models: [], source: 'unavailable', via: 'cli', error: redactSecrets(error?.message || String(error)) });
195
+ return;
196
+ }
197
+ const timer = setTimeout(() => { try { child.kill('SIGKILL'); } catch { /* gone */ } finish({ models: [], source: 'unavailable', via: 'cli', error: `agy models did not answer within ${Math.round(timeoutMs / 1000)} s.` }); }, timeoutMs);
198
+ timer.unref?.();
199
+ child.stdout?.on('data', (chunk) => { if (stdout.length < MAX_OUTPUT) stdout += chunk; });
200
+ child.stderr?.on('data', (chunk) => { if (stderr.length < 16_384) stderr += chunk; });
201
+ child.on('error', (error) => finish({ models: [], source: 'unavailable', via: 'cli', error: redactSecrets(error?.message || String(error)) }));
202
+ child.on('close', (code) => {
203
+ // A later agy may print JSON; 1.4.12 prints `<id>\t<label>` lines after a status line.
204
+ const json = parseAntigravityModels(stdout);
205
+ const models = json.length ? json : parseAntigravityModelLines(stdout);
206
+ if (models.length) { finish({ models, source: 'live', via: 'cli' }); return; }
207
+ const said = redactSecrets((stderr || stdout).trim()).split('\n').filter(Boolean).slice(-3).join(' ');
208
+ const authRequired = /sign in|log in|authenticat/i.test(said);
209
+ finish({ models: [], source: 'unavailable', via: 'cli', error: said || `agy models exited with code ${code}.`, ...(authRequired ? { authRequired: true } : {}) });
210
+ });
211
+ });
212
+ }
213
+
214
+ /**
215
+ * Every session ACP's session/list reports (all pages, up to `maxSessions`), through a short-lived `agy acp`.
216
+ * Answers { sessions: [{ sessionId, cwd, title, updatedAt }], error?, authRequired? }.
217
+ */
218
+ export async function listAntigravitySessions({ launch, env = process.env, connect = createAcpConnection, maxSessions = 500, cwd } = {}) {
219
+ if (!launch?.command) return { sessions: [], error: 'The Antigravity CLI (agy) is not installed.', cliMissing: true };
220
+ const conn = connect({ command: launch.command, args: launch.args || [], env, cwd, clientInfo: { name: 'synabun', title: 'SynaBun', version: '0' } });
221
+ const sessions = [];
222
+ try {
223
+ await conn.initialize();
224
+ let cursor = null;
225
+ for (let page = 0; page < 50 && sessions.length < maxSessions; page++) {
226
+ const answer = await conn.request('session/list', cursor ? { cursor } : {}, { timeoutMs: 20_000 });
227
+ for (const row of Array.isArray(answer?.sessions) ? answer.sessions : []) {
228
+ if (row && typeof row.sessionId === 'string') sessions.push({ sessionId: row.sessionId, cwd: typeof row.cwd === 'string' ? row.cwd : '', title: typeof row.title === 'string' ? row.title : '', updatedAt: typeof row.updatedAt === 'string' ? row.updatedAt : null });
229
+ }
230
+ cursor = typeof answer?.nextCursor === 'string' && answer.nextCursor ? answer.nextCursor : null;
231
+ if (!cursor) break;
232
+ }
233
+ return { sessions: sessions.slice(0, maxSessions) };
234
+ } catch (error) {
235
+ return { sessions, error: acpErrorInfo(error).message, ...(isAuthRequired(error) ? { authRequired: true } : {}) };
236
+ } finally {
237
+ conn.close();
238
+ }
239
+ }
240
+
241
+ /** The Resume window's shape: one entry per registered project, its sessions newest first, searched and paged. */
242
+ export function groupSessionsByProject(sessions, projects, { targetProject = null, search = '', offset = 0, limit = 30 } = {}) {
243
+ const roots = (Array.isArray(projects) ? projects : []).map((project) => ({ project, root: resolve(project.path) }))
244
+ // The deepest project wins a session that sits in a nested one.
245
+ .sort((a, b) => b.root.length - a.root.length);
246
+ const byRoot = new Map(roots.map(({ root }) => [root, []]));
247
+ for (const session of Array.isArray(sessions) ? sessions : []) {
248
+ if (!session?.cwd) continue;
249
+ const dir = resolve(session.cwd);
250
+ const owner = roots.find(({ root }) => dir === root || dir.startsWith(root + sep));
251
+ if (!owner) continue;
252
+ byRoot.get(owner.root).push({
253
+ sessionId: session.sessionId,
254
+ firstPrompt: session.title || '',
255
+ messageCount: null,
256
+ created: null,
257
+ modified: session.updatedAt || null,
258
+ gitBranch: null,
259
+ cwd: session.cwd,
260
+ });
261
+ }
262
+ const needle = String(search || '').toLowerCase().trim();
263
+ const result = [];
264
+ for (const project of Array.isArray(projects) ? projects : []) {
265
+ const root = resolve(project.path);
266
+ if (targetProject && root !== resolve(targetProject)) continue;
267
+ let entries = byRoot.get(root) || [];
268
+ entries.sort((a, b) => (Date.parse(b.modified || 0) || 0) - (Date.parse(a.modified || 0) || 0));
269
+ if (needle) entries = entries.filter((e) => e.firstPrompt.toLowerCase().includes(needle) || e.sessionId.toLowerCase().includes(needle));
270
+ result.push({ path: project.path, label: project.label || basename(project.path), total: entries.length, sessions: entries.slice(offset, offset + limit) });
271
+ }
272
+ return result;
273
+ }
@@ -0,0 +1,260 @@
1
+ import { acpReadOnlyKind, acpToolPaths } from './tool-call.js';
2
+ // ═══════════════════════════════════════════
3
+ // SynaBun — Antigravity homes: the Antigravity folder of each Assistant brain and each run
4
+ // ═══════════════════════════════════════════
5
+ //
6
+ // `agy acp --gemini-dir <dir>` reads everything that shapes a session from <dir> instead of
7
+ // ~/.gemini: its MCP servers (config/mcp_config.json), its hooks (config/hooks.json), its global
8
+ // rules (config/GEMINI.md), extra skill folders (config/skills.json) and its settings
9
+ // (antigravity-cli/settings.json: tool permissions, permission rules); its conversations are kept
10
+ // there too (antigravity-cli/conversations). The sign-in is not: agy keeps its token in the
11
+ // system keychain, which every gemini dir shares, so a SynaBun home never signs in or out.
12
+ // Measured on agy 1.4.12 (docs/antigravity-sidepanel.md → Assistant).
13
+ //
14
+ // So each brain and each run SynaBun starts gets a home of its own, written before agy starts:
15
+ // - exactly the MCP servers the run may use (SynaBun's own entry, then the external servers its
16
+ // tool list names, copied from the user's ~/.gemini/config/mcp_config.json); project MCP config
17
+ // loads separately, so managed starts refuse enabled project servers before starting agy;
18
+ // - one PreToolUse hook (lib/antigravity/policy-hook.mjs) that asks SynaBun about every call
19
+ // before it runs (route gate, browser policy, worker confinement, MCP scope): a refusal reaches
20
+ // the model with its reason and the turn goes on;
21
+ // - settings that ask before writes, commands, MCP and the web (toolPermission request-review) and
22
+ // deny Antigravity's own web reading and browser (read_url, execute_url) outright, plus the
23
+ // user's own sign-in related keys (Gemini API key mode, Google Cloud project, AI credits);
24
+ // - the user's global rules (a copy of ~/.gemini/config/GEMINI.md, SynaBun's block included) and
25
+ // skills (~/.gemini/config/skills through skills.json).
26
+ // Plugins of the user's are not loaded (they can bring MCP servers and hooks of their own).
27
+ // A home is kept while its brain or run may resume; pruneAntigravityHomes removes the rest.
28
+
29
+ import { chmodSync, existsSync, mkdirSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync } from 'node:fs';
30
+ import { homedir } from 'node:os';
31
+ import { dirname, isAbsolute, join, relative, resolve } from 'node:path';
32
+ import { createHash } from 'node:crypto';
33
+
34
+ /** The settings keys of the user's own Antigravity settings a SynaBun home keeps: how they sign in and which models they get. */
35
+ export const KEPT_USER_SETTINGS = Object.freeze(['modelProvider', 'customModelsConfig', 'gcp', 'useG1Credits']);
36
+ /** Antigravity's own web reading and browser: denied in every SynaBun home (the SynaBun browser policy). */
37
+ export const SYNABUN_HOME_DENY = Object.freeze(['read_url_content(*)', 'execute_url(*)']);
38
+ /** The hook's time limit, in seconds (Antigravity's default is 30). */
39
+ export const POLICY_HOOK_TIMEOUT_S = 20;
40
+
41
+ const HOME_KINDS = new Set(['brain', 'run', 'models']);
42
+
43
+ /** Where SynaBun's Antigravity homes live: <data home>/runtime/antigravity/homes (outside data/, which is backed up). */
44
+ export function antigravityHomesRoot(dataHome) {
45
+ return resolve(String(dataHome || join(homedir(), '.synabun')), 'runtime', 'antigravity', 'homes');
46
+ }
47
+
48
+ /** The home of one brain ('brain', its Assistant session id) or run ('run', its run id): a stable folder name per id. */
49
+ export function antigravityHomeDir(root, kind, id) {
50
+ if (!HOME_KINDS.has(kind)) throw new Error(`Unknown Antigravity home kind ${kind}`);
51
+ const raw = String(id || '');
52
+ if (!raw) throw new Error('An Antigravity home needs an id');
53
+ const readable = raw.replace(/[^A-Za-z0-9_-]/g, '_').slice(0, 48);
54
+ const digest = createHash('sha256').update(raw).digest('hex').slice(0, 10);
55
+ return join(resolve(root), `${kind}-${readable}-${digest}`);
56
+ }
57
+
58
+ /** The user's own gemini dir (what agy reads without --gemini-dir). */
59
+ export function userGeminiDir(home = homedir()) {
60
+ return join(home, '.gemini');
61
+ }
62
+
63
+ function readJson(path) {
64
+ try {
65
+ const text = readFileSync(path, 'utf8').replace(/^\uFEFF/, '');
66
+ if (!text.trim()) return {};
67
+ const value = JSON.parse(text);
68
+ return value && typeof value === 'object' && !Array.isArray(value) ? value : {};
69
+ } catch { return {}; }
70
+ }
71
+
72
+ function writePrivate(path, text) {
73
+ writeFileSync(path, text, { encoding: 'utf8', mode: 0o600 });
74
+ try { chmodSync(path, 0o600); } catch { /* a filesystem without modes */ }
75
+ }
76
+
77
+ function ensurePrivateDir(path) {
78
+ mkdirSync(path, { recursive: true, mode: 0o700 });
79
+ try { chmodSync(path, 0o700); } catch { /* a filesystem without modes */ }
80
+ }
81
+
82
+ /** The MCP servers of the user's own Antigravity configuration ({ name: entry }), read loosely ({} when there is none). */
83
+ export function userAntigravityMcpServers(geminiDir = userGeminiDir()) {
84
+ const config = readJson(join(geminiDir, 'config', 'mcp_config.json'));
85
+ const servers = config.mcpServers && typeof config.mcpServers === 'object' && !Array.isArray(config.mcpServers) ? config.mcpServers : {};
86
+ const out = {};
87
+ for (const [name, entry] of Object.entries(servers)) if (entry && typeof entry === 'object' && !Array.isArray(entry)) out[name] = entry;
88
+ return out;
89
+ }
90
+
91
+ /** The user's own Antigravity settings (~/.gemini/antigravity-cli/settings.json), read loosely ({} when there are none). */
92
+ export function userAntigravitySettings(geminiDir = userGeminiDir()) {
93
+ return readJson(join(geminiDir, 'antigravity-cli', 'settings.json'));
94
+ }
95
+
96
+ /**
97
+ * An MCP server definition as mcp_config.json holds it: a remote server `{ serverUrl, headers }`, a local one
98
+ * `{ command, args, env }` (the inventory of lib/mcp-external-servers.js names a remote address `url`).
99
+ */
100
+ export function toAntigravityMcpEntry(definition) {
101
+ const source = definition && typeof definition === 'object' ? definition : {};
102
+ const url = typeof source.serverUrl === 'string' && source.serverUrl ? source.serverUrl : (typeof source.url === 'string' ? source.url : '');
103
+ if (url) {
104
+ const entry = { serverUrl: url };
105
+ if (source.headers && typeof source.headers === 'object' && Object.keys(source.headers).length) entry.headers = { ...source.headers };
106
+ return entry;
107
+ }
108
+ const entry = { command: typeof source.command === 'string' ? source.command : '' };
109
+ if (Array.isArray(source.args) && source.args.length) entry.args = source.args.map(String);
110
+ if (source.env && typeof source.env === 'object' && Object.keys(source.env).length) entry.env = { ...source.env };
111
+ if (typeof source.cwd === 'string' && source.cwd) entry.cwd = source.cwd;
112
+ return entry;
113
+ }
114
+
115
+ /**
116
+ * The settings of a SynaBun home: `toolPermission` (request-review asks before writes, commands, MCP and the
117
+ * web; Antigravity's own default), SynaBun's deny rules plus `deny`, and the user's own KEPT_USER_SETTINGS.
118
+ */
119
+ export function antigravityHomeSettings({ userSettings = {}, toolPermission = 'request-review', deny = [], allow = [] } = {}) {
120
+ const out = {};
121
+ for (const key of KEPT_USER_SETTINGS) if (userSettings[key] !== undefined) out[key] = userSettings[key];
122
+ out.toolPermission = toolPermission;
123
+ const denyRules = [...new Set([...SYNABUN_HOME_DENY, ...(Array.isArray(deny) ? deny : [])].filter((rule) => typeof rule === 'string' && rule))];
124
+ const allowRules = [...new Set((Array.isArray(allow) ? allow : []).filter((rule) => typeof rule === 'string' && rule))];
125
+ out.permissions = { deny: denyRules, ...(allowRules.length ? { allow: allowRules } : {}) };
126
+ return out;
127
+ }
128
+
129
+ /** The hooks.json of a SynaBun home: one PreToolUse hook for every tool, the command `hookCommand`. */
130
+ export function antigravityHomeHooks(hookCommand, { timeoutSec = POLICY_HOOK_TIMEOUT_S } = {}) {
131
+ return { 'synabun-policy': { PreToolUse: [{ matcher: '*', hooks: [{ type: 'command', command: hookCommand, timeout: timeoutSec }] }] } };
132
+ }
133
+
134
+ /** A shell word for the hook command line (sh -c on Unix, cmd /c on Windows): double quotes, inner ones escaped. */
135
+ export function shellWord(value) {
136
+ const text = String(value ?? '');
137
+ if (/^[A-Za-z0-9_./:@%+=,-]+$/.test(text)) return text;
138
+ return `"${text.replace(/(["\\$`])/g, '\\$1')}"`;
139
+ }
140
+
141
+ /** The command line that runs the policy hook: Node, the hook script. */
142
+ export function policyHookCommand({ node = process.execPath, script } = {}) {
143
+ if (!script) throw new Error('The policy hook needs its script');
144
+ return `${shellWord(node)} ${shellWord(script)}`;
145
+ }
146
+
147
+ /**
148
+ * Write (or rewrite) a home before agy starts. `mcpServers`: { name: entry } exactly as mcp_config.json holds
149
+ * them; `hookCommand`: the policy hook's command line (null: no hook, which only a test does); `settings`:
150
+ * antigravityHomeSettings(); `userGemini`: the user's gemini dir (rules and skills come from there).
151
+ * → { dir, configDir, appDir }. Conversations already in the home are kept (a resume needs them).
152
+ */
153
+ export function prepareAntigravityHome({ dir, mcpServers = {}, hookCommand = null, settings = null, userGemini = userGeminiDir(), rules = true, skills = true } = {}) {
154
+ if (!dir) throw new Error('prepareAntigravityHome needs a dir');
155
+ const configDir = join(dir, 'config');
156
+ const appDir = join(dir, 'antigravity-cli');
157
+ ensurePrivateDir(dir);
158
+ ensurePrivateDir(configDir);
159
+ ensurePrivateDir(appDir);
160
+ writePrivate(join(configDir, 'mcp_config.json'), `${JSON.stringify({ mcpServers }, null, 2)}\n`);
161
+ if (hookCommand) writePrivate(join(configDir, 'hooks.json'), `${JSON.stringify(antigravityHomeHooks(hookCommand), null, 2)}\n`);
162
+ else rmSync(join(configDir, 'hooks.json'), { force: true });
163
+ writePrivate(join(appDir, 'settings.json'), `${JSON.stringify(settings || antigravityHomeSettings({ userSettings: userAntigravitySettings(userGemini) }), null, 2)}\n`);
164
+ // The user's global rules (SynaBun's own block included), as they are now.
165
+ const rulesTarget = join(configDir, 'GEMINI.md');
166
+ const rulesSource = join(userGemini, 'config', 'GEMINI.md');
167
+ if (rules && existsSync(rulesSource)) {
168
+ try { writePrivate(rulesTarget, readFileSync(rulesSource, 'utf8')); } catch { rmSync(rulesTarget, { force: true }); }
169
+ } else rmSync(rulesTarget, { force: true });
170
+ // The user's skills folder, read in place (Skills Studio installs Antigravity skills there).
171
+ const skillsTarget = join(configDir, 'skills.json');
172
+ const skillsSource = join(userGemini, 'config', 'skills');
173
+ let hasSkills = false;
174
+ try { hasSkills = skills && statSync(skillsSource).isDirectory(); } catch { hasSkills = false; }
175
+ if (hasSkills) writePrivate(skillsTarget, `${JSON.stringify({ entries: [{ path: resolve(skillsSource) }] }, null, 2)}\n`);
176
+ else rmSync(skillsTarget, { force: true });
177
+ return { dir, configDir, appDir };
178
+ }
179
+
180
+ /** Whether a home holds Antigravity's record of a conversation (a resume needs it). */
181
+ export function homeHasConversation(dir, sessionId) {
182
+ const id = String(sessionId || '');
183
+ if (!dir || !/^[A-Za-z0-9_-]{4,128}$/.test(id)) return false;
184
+ return existsSync(join(dir, 'antigravity-cli', 'conversations', `${id}.db`)) || existsSync(join(dir, 'antigravity-cli', 'brain', id));
185
+ }
186
+
187
+ /** Whether Antigravity has listed the tools of an MCP server in a home (it writes one schema file per tool once connected). */
188
+ export function homeMcpTools(dir, server) {
189
+ try {
190
+ return readdirSync(join(dir, 'antigravity-cli', 'mcp', String(server)))
191
+ .filter((name) => name.endsWith('.json'))
192
+ .map((name) => name.slice(0, -5));
193
+ } catch { return []; }
194
+ }
195
+
196
+ /**
197
+ * Remove the homes under `root` nobody needs: older than `maxAgeMs` (by their last change) and not named in
198
+ * `keep` (folder names). Never a folder outside the root or one that is not a home. → the names removed.
199
+ */
200
+ export function pruneAntigravityHomes(root, { keep = new Set(), maxAgeMs = 7 * 24 * 60 * 60_000, now = Date.now(), kinds = ['run', 'models'] } = {}) {
201
+ const removed = [];
202
+ let names = [];
203
+ try { names = readdirSync(root, { withFileTypes: true }).filter((item) => item.isDirectory()).map((item) => item.name); } catch { return removed; }
204
+ const keepSet = keep instanceof Set ? keep : new Set(keep || []);
205
+ for (const name of names) {
206
+ const kind = name.split('-')[0];
207
+ if (!kinds.includes(kind) || keepSet.has(name)) continue;
208
+ const path = join(root, name);
209
+ // Its last use: the folder, its MCP list (rewritten at every start) or its conversations, whichever is newest.
210
+ let changed = 0;
211
+ for (const part of ['', join('config', 'mcp_config.json'), join('antigravity-cli', 'conversations')]) {
212
+ try { changed = Math.max(changed, statSync(part ? join(path, part) : path).mtimeMs); } catch { /* not there */ }
213
+ }
214
+ if (!changed || now - changed < maxAgeMs) continue;
215
+ try { rmSync(path, { recursive: true, force: true }); removed.push(name); } catch { /* left for the next pass */ }
216
+ }
217
+ return removed;
218
+ }
219
+
220
+ /** Project MCP processes start before PreToolUse. Refuse them before any managed agent/session starts.
221
+ * Scan ancestors too, so a nested cwd cannot hide a project config. Even a named server could replace the
222
+ * trusted definition with an arbitrary command: managed sessions use only their prepared home definitions.
223
+ */
224
+ export function assertSafeAntigravityProject(cwd) {
225
+ for (let dir = resolve(cwd || process.cwd()); ; dir = dirname(dir)) {
226
+ const file = join(dir, '.agents', 'mcp_config.json');
227
+ const unsafe = (reason) => Object.assign(new Error(`Antigravity did not start: ${file} ${reason}. Project MCP processes start before SynaBun's policy. Disable those project servers and use the session's configured MCP servers.`), { code: 'PROJECT_MCP_UNSAFE' });
228
+ let config;
229
+ try {
230
+ if (statSync(file).size > 1024 * 1024) throw unsafe('exceeds the configuration size limit');
231
+ config = JSON.parse(readFileSync(file, 'utf8').replace(/^\uFEFF/, '') || '{}');
232
+ } catch (error) {
233
+ if (error.code !== 'ENOENT') throw unsafe('could not be safely read');
234
+ }
235
+ if (config !== undefined) {
236
+ if (!config || typeof config !== 'object' || Array.isArray(config)) throw unsafe('is not a valid configuration');
237
+ const servers = config.mcpServers;
238
+ if (servers !== undefined && (!servers || typeof servers !== 'object' || Array.isArray(servers))) throw unsafe('has an invalid server list');
239
+ if (Object.values(servers || {}).some((entry) => !entry || typeof entry !== 'object' || entry.disabled !== true)) throw unsafe('defines enabled MCP servers');
240
+ }
241
+ if (dirname(dir) === dir) break;
242
+ }
243
+ }
244
+
245
+ /** The only automatic reads in a managed home are MCP tool schemas. Config/settings copy credentials.
246
+ * null for a call outside the home; deny mixed reads so a safe schema cannot mask another file.
247
+ */
248
+ export function antigravityHomeReadPolicy(call, { homeDir, cwd } = {}) {
249
+ if (!homeDir || !acpReadOnlyKind(call.kind)) return null;
250
+ const paths = acpToolPaths(call).map((raw) => {
251
+ const path = raw.trim();
252
+ if (path === '~' || path.startsWith('~/')) return resolve(homedir(), path.slice(2));
253
+ if (/^\$\{?HOME\}?(\/|$)/.test(path)) return resolve(homedir(), path.replace(/^\$\{?HOME\}?\/?/, ''));
254
+ return resolve(cwd || process.cwd(), path);
255
+ });
256
+ const inside = (path) => { const rel = relative(resolve(homeDir), path); return rel === '' || (!rel.startsWith('..') && !isAbsolute(rel)); };
257
+ if (!paths.some(inside)) return null;
258
+ if (paths.every((path) => inside(path) && /^antigravity-cli[\\/]mcp[\\/][^\\/]+[\\/][^\\/]+\.json$/.test(relative(resolve(homeDir), path)))) return { decision: 'allow' };
259
+ return { decision: 'deny', reason: 'SynaBun refuses reads of its Antigravity home configuration: it can contain MCP credentials and sign-in settings. Only tool schemas may be read here.' };
260
+ }