synabun 2.1.0 → 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 (317) hide show
  1. package/CHANGELOG.md +121 -0
  2. package/README.md +1 -1
  3. package/docs/whatsapp.md +11 -11
  4. package/lib/client-config-repair.js +13 -9
  5. package/lib/external-tools.js +6 -5
  6. package/lib/update-snapshot.js +77 -3
  7. package/lib/virustotal.mjs +12 -1
  8. package/mcp-server/dist/index.js +1 -1
  9. package/mcp-server/dist/index.js.map +1 -1
  10. package/mcp-server/dist/services/budget-judgments.d.ts +1 -1
  11. package/mcp-server/dist/services/budget-judgments.d.ts.map +1 -1
  12. package/mcp-server/dist/services/budget-judgments.js +5 -3
  13. package/mcp-server/dist/services/budget-judgments.js.map +1 -1
  14. package/mcp-server/dist/services/identity.d.ts +2 -2
  15. package/mcp-server/dist/services/identity.js +2 -2
  16. package/mcp-server/dist/services/memory-sessions.d.ts +1 -1
  17. package/mcp-server/dist/services/memory-sessions.d.ts.map +1 -1
  18. package/mcp-server/dist/services/memory-sessions.js +28 -2
  19. package/mcp-server/dist/services/memory-sessions.js.map +1 -1
  20. package/mcp-server/dist/services/neural-interface.d.ts +2 -1
  21. package/mcp-server/dist/services/neural-interface.d.ts.map +1 -1
  22. package/mcp-server/dist/services/neural-interface.js.map +1 -1
  23. package/mcp-server/dist/services/server-instructions.d.ts.map +1 -1
  24. package/mcp-server/dist/services/server-instructions.js +2 -1
  25. package/mcp-server/dist/services/server-instructions.js.map +1 -1
  26. package/mcp-server/dist/services/tool-catalog.js +1 -1
  27. package/mcp-server/dist/services/tool-catalog.js.map +1 -1
  28. package/mcp-server/dist/services/tool-list.d.ts +1 -1
  29. package/mcp-server/dist/services/tool-list.d.ts.map +1 -1
  30. package/mcp-server/dist/services/tool-runtime.d.ts +2 -2
  31. package/mcp-server/dist/services/tool-runtime.d.ts.map +1 -1
  32. package/mcp-server/dist/services/tool-runtime.js +1 -1
  33. package/mcp-server/dist/services/tool-runtime.js.map +1 -1
  34. package/mcp-server/dist/services/typesafe-config.js +1 -1
  35. package/mcp-server/dist/services/typesafe-config.js.map +1 -1
  36. package/mcp-server/dist/tools/agents.d.ts +8 -8
  37. package/mcp-server/dist/tools/agents.d.ts.map +1 -1
  38. package/mcp-server/dist/tools/agents.js +10 -9
  39. package/mcp-server/dist/tools/agents.js.map +1 -1
  40. package/mcp-server/dist/tools/choice.d.ts +6 -0
  41. package/mcp-server/dist/tools/choice.d.ts.map +1 -1
  42. package/mcp-server/dist/tools/choice.js +18 -13
  43. package/mcp-server/dist/tools/choice.js.map +1 -1
  44. package/mcp-server/dist/tools/git-tools.js +2 -2
  45. package/mcp-server/dist/tools/git-tools.js.map +1 -1
  46. package/mcp-server/dist/tools/morelogin.d.ts.map +1 -1
  47. package/mcp-server/dist/tools/morelogin.js +9 -6
  48. package/mcp-server/dist/tools/morelogin.js.map +1 -1
  49. package/mcp-server/dist/tools/skill-tools.d.ts +8 -8
  50. package/mcp-server/dist/tools/skill-tools.d.ts.map +1 -1
  51. package/mcp-server/dist/tools/skill-tools.js +11 -8
  52. package/mcp-server/dist/tools/skill-tools.js.map +1 -1
  53. package/mcp-server/package-lock.json +2 -2
  54. package/mcp-server/package.json +1 -1
  55. package/mcp-server/src/index.ts +1 -1
  56. package/mcp-server/src/services/budget-judgments.ts +5 -3
  57. package/mcp-server/src/services/identity.ts +2 -2
  58. package/mcp-server/src/services/memory-sessions.ts +24 -3
  59. package/mcp-server/src/services/neural-interface.ts +2 -1
  60. package/mcp-server/src/services/server-instructions.ts +2 -1
  61. package/mcp-server/src/services/tool-catalog.ts +1 -1
  62. package/mcp-server/src/services/tool-list.ts +1 -1
  63. package/mcp-server/src/services/tool-runtime.ts +2 -2
  64. package/mcp-server/src/services/typesafe-config.ts +1 -1
  65. package/mcp-server/src/tools/agents.ts +10 -9
  66. package/mcp-server/src/tools/choice.ts +17 -12
  67. package/mcp-server/src/tools/git-tools.ts +2 -2
  68. package/mcp-server/src/tools/morelogin.ts +6 -4
  69. package/mcp-server/src/tools/skill-tools.ts +11 -8
  70. package/neural-interface/i18n/en.json +501 -39
  71. package/neural-interface/i18n/pt-BR.json +501 -39
  72. package/neural-interface/lib/agent-sandbox-elevation.js +6 -0
  73. package/neural-interface/lib/antigravity/acp-client-host.js +554 -0
  74. package/neural-interface/lib/antigravity/acp-connection.js +299 -0
  75. package/neural-interface/lib/antigravity/bypass.js +100 -0
  76. package/neural-interface/lib/antigravity/catalog.js +273 -0
  77. package/neural-interface/lib/antigravity/home.js +260 -0
  78. package/neural-interface/lib/antigravity/migrate-gemini.js +139 -0
  79. package/neural-interface/lib/antigravity/panel-bridge.js +1058 -0
  80. package/neural-interface/lib/antigravity/policy-hook.mjs +78 -0
  81. package/neural-interface/lib/antigravity/policy.js +74 -0
  82. package/neural-interface/lib/antigravity/tool-call.js +178 -0
  83. package/neural-interface/lib/antigravity/transcripts.js +252 -0
  84. package/neural-interface/lib/antigravity/usage.js +43 -0
  85. package/neural-interface/lib/assistant-api.js +1 -0
  86. package/neural-interface/lib/assistant-brains/antigravity.js +423 -0
  87. package/neural-interface/lib/assistant-budget-planner.js +7 -3
  88. package/neural-interface/lib/assistant-budget-split.js +42 -15
  89. package/neural-interface/lib/assistant-catalog.js +76 -9
  90. package/neural-interface/lib/assistant-config.js +6 -3
  91. package/neural-interface/lib/assistant-dispatch.js +207 -49
  92. package/neural-interface/lib/assistant-envelope.js +153 -1
  93. package/neural-interface/lib/assistant-evidence.js +80 -0
  94. package/neural-interface/lib/assistant-hidden-models.js +7 -5
  95. package/neural-interface/lib/assistant-persona.js +16 -11
  96. package/neural-interface/lib/assistant-plan-permissions.js +15 -0
  97. package/neural-interface/lib/assistant-router.js +237 -35
  98. package/neural-interface/lib/assistant-runtime.js +158 -12
  99. package/neural-interface/lib/assistant-task-prompt.js +10 -8
  100. package/neural-interface/lib/assistant-tools.js +2 -2
  101. package/neural-interface/lib/assistant-usage.js +29 -0
  102. package/neural-interface/lib/backup-service.js +6 -1
  103. package/neural-interface/lib/browser-guard-cdp.js +5 -4
  104. package/neural-interface/lib/browser-network-guard.js +274 -82
  105. package/neural-interface/lib/browser-tool-policy.js +12 -7
  106. package/neural-interface/lib/claude-agent-bridge.js +7 -0
  107. package/neural-interface/lib/claude-history-cache.js +210 -0
  108. package/neural-interface/lib/claude-model-catalog.js +5 -1
  109. package/neural-interface/lib/cli-install-api.js +1 -1
  110. package/neural-interface/lib/cli-install.js +160 -31
  111. package/neural-interface/lib/cli-resolver.js +9 -2
  112. package/neural-interface/lib/cli-update-planner.js +25 -15
  113. package/neural-interface/lib/codex-rollout-reader.js +52 -0
  114. package/neural-interface/lib/codex-worker-app-server.js +25 -6
  115. package/neural-interface/lib/editor-git-api.js +3 -20
  116. package/neural-interface/lib/exec-loop-command.js +9 -2
  117. package/neural-interface/lib/file-explorer-api.js +74 -40
  118. package/neural-interface/lib/file-explorer-watch.js +9 -3
  119. package/neural-interface/lib/git-bash/install.js +52 -6
  120. package/neural-interface/lib/git-bash/manager.js +59 -17
  121. package/neural-interface/lib/git-bash/pins.js +12 -0
  122. package/neural-interface/lib/git-read.js +2 -2
  123. package/neural-interface/lib/git-status-runner.js +390 -0
  124. package/neural-interface/lib/git-status-watchdog.js +40 -0
  125. package/neural-interface/lib/greeting/budgets.js +1 -0
  126. package/neural-interface/lib/greeting/engine.js +2 -2
  127. package/neural-interface/lib/greeting/sources.js +10 -12
  128. package/neural-interface/lib/greeting/writer.js +1 -1
  129. package/neural-interface/lib/mcp-client-config.js +37 -6
  130. package/neural-interface/lib/mcp-external-servers.js +13 -4
  131. package/neural-interface/lib/mcp-installer.js +2 -1
  132. package/neural-interface/lib/memory-session-capture.js +17 -3
  133. package/neural-interface/lib/morelogin.js +147 -25
  134. package/neural-interface/lib/native-loop-providers.js +420 -21
  135. package/neural-interface/lib/native-loop-runtime.js +23 -2
  136. package/neural-interface/lib/opencode-native-boundary.js +11 -2
  137. package/neural-interface/lib/owner-authority.js +1 -1
  138. package/neural-interface/lib/path-confine.js +12 -9
  139. package/neural-interface/lib/peer-identity.js +32 -2
  140. package/neural-interface/lib/pty-host/core.js +28 -1
  141. package/neural-interface/lib/pty-host/lifetime.js +12 -0
  142. package/neural-interface/lib/pty-host/manager.js +12 -1
  143. package/neural-interface/lib/remote-policy.js +1 -1
  144. package/neural-interface/lib/request-gate.js +3 -0
  145. package/neural-interface/lib/rulesets/api.js +6 -5
  146. package/neural-interface/lib/rulesets/fs-safe.js +1 -1
  147. package/neural-interface/lib/rulesets/installer.js +89 -10
  148. package/neural-interface/lib/rulesets/render.js +1 -1
  149. package/neural-interface/lib/session-cache-builder.js +64 -1
  150. package/neural-interface/lib/skills/catalog.js +5 -1
  151. package/neural-interface/lib/skills/creation-brief.js +1 -1
  152. package/neural-interface/lib/skills/creation-sources.js +19 -1
  153. package/neural-interface/lib/skills/deploy.js +9 -4
  154. package/neural-interface/lib/skills/draft-confinement.js +3 -1
  155. package/neural-interface/lib/skills/eval-confinement.js +3 -1
  156. package/neural-interface/lib/skills/eval-trace.js +16 -0
  157. package/neural-interface/lib/skills/export.js +5 -2
  158. package/neural-interface/lib/skills/known-bridge-digests.json +58 -4
  159. package/neural-interface/lib/skills/ownership.js +1 -1
  160. package/neural-interface/lib/skills/roots.js +10 -3
  161. package/neural-interface/lib/skills/runtime-checks.js +6 -3
  162. package/neural-interface/lib/skills/service.js +15 -7
  163. package/neural-interface/lib/skills/telemetry.js +6 -0
  164. package/neural-interface/lib/synabun-version.js +1 -1
  165. package/neural-interface/lib/system-activity.js +1 -1
  166. package/neural-interface/lib/whatsapp/brain.js +7 -3
  167. package/neural-interface/lib/whatsapp/cards.js +22 -9
  168. package/neural-interface/lib/whatsapp/config.js +1 -1
  169. package/neural-interface/lib/worker-confinement.js +77 -1
  170. package/neural-interface/lib/worker-question.js +74 -0
  171. package/neural-interface/lib/worker-resume.js +13 -4
  172. package/neural-interface/lib/worker-sandbox.js +46 -16
  173. package/neural-interface/package-lock.json +18 -2
  174. package/neural-interface/package.json +2 -1
  175. package/neural-interface/public/onboarding.html +1 -1
  176. package/neural-interface/public/shared/agent-runtime-options.js +89 -11
  177. package/neural-interface/public/shared/agy/agy-bypass.js +47 -0
  178. package/neural-interface/public/shared/agy/agy-client.js +266 -0
  179. package/neural-interface/public/shared/agy/agy-commands.js +120 -0
  180. package/neural-interface/public/shared/agy/agy-copy.js +326 -0
  181. package/neural-interface/public/shared/agy/agy-diff.js +161 -0
  182. package/neural-interface/public/shared/agy/agy-events.js +469 -0
  183. package/neural-interface/public/shared/agy/agy-greeting.js +26 -0
  184. package/neural-interface/public/shared/agy/agy-options.js +232 -0
  185. package/neural-interface/public/shared/agy/agy-panel.js +2543 -0
  186. package/neural-interface/public/shared/agy/agy-render.js +392 -0
  187. package/neural-interface/public/shared/agy/agy-setup.js +149 -0
  188. package/neural-interface/public/shared/agy/agy-styles.js +604 -0
  189. package/neural-interface/public/shared/agy/agy-tabs-logic.js +181 -0
  190. package/neural-interface/public/shared/api.js +4 -4
  191. package/neural-interface/public/shared/assistant/asst-agents-dock.js +3 -4
  192. package/neural-interface/public/shared/assistant/asst-api.js +1 -1
  193. package/neural-interface/public/shared/assistant/asst-brain-picker.js +56 -9
  194. package/neural-interface/public/shared/assistant/asst-budget.js +5 -4
  195. package/neural-interface/public/shared/assistant/asst-control.js +48 -0
  196. package/neural-interface/public/shared/assistant/asst-hosts.js +16 -7
  197. package/neural-interface/public/shared/assistant/asst-limit-dock.js +6 -1
  198. package/neural-interface/public/shared/assistant/asst-limit-wait.js +38 -5
  199. package/neural-interface/public/shared/assistant/asst-panel.js +45 -8
  200. package/neural-interface/public/shared/assistant/asst-render.js +51 -12
  201. package/neural-interface/public/shared/assistant/asst-route.js +237 -57
  202. package/neural-interface/public/shared/assistant/asst-routes-editor.js +9 -8
  203. package/neural-interface/public/shared/assistant/asst-scenes.js +54 -1
  204. package/neural-interface/public/shared/assistant/asst-sidepanel.js +51 -7
  205. package/neural-interface/public/shared/assistant/asst-slash.js +8 -2
  206. package/neural-interface/public/shared/assistant/asst-state.js +76 -9
  207. package/neural-interface/public/shared/assistant/asst-styles.js +34 -0
  208. package/neural-interface/public/shared/assistant/asst-tool-kinds.js +34 -7
  209. package/neural-interface/public/shared/assistant/asst-usage.js +2 -1
  210. package/neural-interface/public/shared/cdx/cdx-output.js +26 -3
  211. package/neural-interface/public/shared/cdx/cdx-panel.js +14 -2
  212. package/neural-interface/public/shared/cdx/cdx-preview.js +12 -0
  213. package/neural-interface/public/shared/cdx/cdx-protocol.js +11 -10
  214. package/neural-interface/public/shared/cdx/cdx-render.js +10 -9
  215. package/neural-interface/public/shared/cdx/cdx-requests.js +11 -1
  216. package/neural-interface/public/shared/cdx/cdx-styles.js +4 -0
  217. package/neural-interface/public/shared/cdx/cdx-tabs.js +75 -5
  218. package/neural-interface/public/shared/cli-install-controller.js +218 -0
  219. package/neural-interface/public/shared/cli-install-view.js +7 -4
  220. package/neural-interface/public/shared/cli-status.js +9 -8
  221. package/neural-interface/public/shared/constants.js +3 -2
  222. package/neural-interface/public/shared/context-menu-model.js +1 -0
  223. package/neural-interface/public/shared/cp/cp-restore.js +162 -0
  224. package/neural-interface/public/shared/cp/cp-tool-cards.js +10 -3
  225. package/neural-interface/public/shared/desktop-bridge.js +17 -0
  226. package/neural-interface/public/shared/desktop-titlebar-view.js +12 -0
  227. package/neural-interface/public/shared/desktop-titlebar.js +13 -4
  228. package/neural-interface/public/shared/desktop-update-view.js +1 -0
  229. package/neural-interface/public/shared/explorer/fx-api.js +4 -4
  230. package/neural-interface/public/shared/explorer/fx-links.js +3 -3
  231. package/neural-interface/public/shared/explorer/fx-logic.js +1 -1
  232. package/neural-interface/public/shared/explorer/fx-main.js +48 -16
  233. package/neural-interface/public/shared/explorer/fx-tree.js +1 -0
  234. package/neural-interface/public/shared/greeting/greeting-card.js +2 -2
  235. package/neural-interface/public/shared/greeting/greeting-view.js +1 -0
  236. package/neural-interface/public/shared/html-shell.js +21 -4
  237. package/neural-interface/public/shared/ocp-v2/ocp-v2-panel.js +27 -7
  238. package/neural-interface/public/shared/ocp-v2/ocp-v2-rehydrate.js +13 -4
  239. package/neural-interface/public/shared/ocp-v2/ocp-v2-render.js +7 -1
  240. package/neural-interface/public/shared/ocp-v2/ocp-v2-styles.js +17 -0
  241. package/neural-interface/public/shared/ocp-v2/ocp-v2-ws.js +46 -3
  242. package/neural-interface/public/shared/provider-icons.js +4 -2
  243. package/neural-interface/public/shared/settings/settings-rules.js +2 -2
  244. package/neural-interface/public/shared/settings/settings-skill-folders-pane.js +1 -1
  245. package/neural-interface/public/shared/settings/settings-skill-folders.js +2 -2
  246. package/neural-interface/public/shared/showcase-privacy.js +6 -1
  247. package/neural-interface/public/shared/sidepanel-session-status.js +3 -3
  248. package/neural-interface/public/shared/skills/ss-creation.js +6 -3
  249. package/neural-interface/public/shared/skills/ss-dialog.js +5 -2
  250. package/neural-interface/public/shared/skills/ss-lint.js +9 -1
  251. package/neural-interface/public/shared/skills/ss-profiles.js +44 -6
  252. package/neural-interface/public/shared/skills/ss-review-view.js +2 -2
  253. package/neural-interface/public/shared/skills/studio/sx-actions.js +1 -1
  254. package/neural-interface/public/shared/skills/studio/sx-create-ai-view.js +1 -1
  255. package/neural-interface/public/shared/skills/studio/sx-create-ai.js +2 -1
  256. package/neural-interface/public/shared/skills/studio/sx-dom.js +2 -1
  257. package/neural-interface/public/shared/skills/studio/sx-fixes-view.js +359 -0
  258. package/neural-interface/public/shared/skills/studio/sx-fixes.js +327 -0
  259. package/neural-interface/public/shared/skills/studio/sx-inspector.js +1 -1
  260. package/neural-interface/public/shared/skills/studio/sx-install-flow.js +9 -6
  261. package/neural-interface/public/shared/skills/studio/sx-install.js +20 -3
  262. package/neural-interface/public/shared/skills/studio/sx-library-view.js +144 -35
  263. package/neural-interface/public/shared/skills/studio/sx-library.js +6 -2
  264. package/neural-interface/public/shared/skills/studio/sx-main.js +11 -2
  265. package/neural-interface/public/shared/skills/studio/sx-review-view.js +1 -1
  266. package/neural-interface/public/shared/skills/studio/sx-subject.js +7 -6
  267. package/neural-interface/public/shared/skills/studio/sx-workspace-view.js +6 -5
  268. package/neural-interface/public/shared/state.js +1 -1
  269. package/neural-interface/public/shared/streaming-markdown.js +58 -0
  270. package/neural-interface/public/shared/styles.css +354 -34
  271. package/neural-interface/public/shared/text-cache.js +29 -0
  272. package/neural-interface/public/shared/tool-list-picker.js +2 -2
  273. package/neural-interface/public/shared/tool-list-view.js +2 -2
  274. package/neural-interface/public/shared/topright-overflow-logic.js +54 -0
  275. package/neural-interface/public/shared/ui-antigravity-panel.js +19 -0
  276. package/neural-interface/public/shared/ui-assistant.js +2 -0
  277. package/neural-interface/public/shared/ui-automation-studio.js +20 -12
  278. package/neural-interface/public/shared/ui-claude-panel.js +299 -77
  279. package/neural-interface/public/shared/ui-cli-banner.js +23 -167
  280. package/neural-interface/public/shared/ui-file-explorer.js +48 -6
  281. package/neural-interface/public/shared/ui-file-links.js +2 -2
  282. package/neural-interface/public/shared/ui-games.js +2 -2
  283. package/neural-interface/public/shared/ui-judgments.js +1 -1
  284. package/neural-interface/public/shared/ui-keybinds.js +8 -2
  285. package/neural-interface/public/shared/ui-link.js +3 -3
  286. package/neural-interface/public/shared/ui-menubar.js +2 -2
  287. package/neural-interface/public/shared/ui-native-loop-router.js +4 -0
  288. package/neural-interface/public/shared/ui-navbar.js +45 -0
  289. package/neural-interface/public/shared/ui-notifications.js +1 -0
  290. package/neural-interface/public/shared/ui-resume.js +9 -7
  291. package/neural-interface/public/shared/ui-schedules-studio.js +41 -10
  292. package/neural-interface/public/shared/ui-scroll-follow.js +16 -5
  293. package/neural-interface/public/shared/ui-sessions.js +22 -12
  294. package/neural-interface/public/shared/ui-settings.js +90 -65
  295. package/neural-interface/public/shared/ui-sidepanel-session-entry.js +9 -2
  296. package/neural-interface/public/shared/ui-sidepanel-sessions.js +3 -3
  297. package/neural-interface/public/shared/ui-sidepanel-tray.js +48 -7
  298. package/neural-interface/public/shared/ui-sidepanel-windows.js +3 -3
  299. package/neural-interface/public/shared/ui-terminal.js +146 -10
  300. package/neural-interface/public/shared/ui-tool-updates.js +3 -3
  301. package/neural-interface/public/shared/ui-tooltip.js +71 -46
  302. package/neural-interface/public/shared/ui-topright-overflow.js +233 -0
  303. package/neural-interface/public/shared/ui-whiteboard.js +1 -1
  304. package/neural-interface/public/shared/ui-worker-end.js +1 -1
  305. package/neural-interface/public/shared/whatsapp/wa-view.js +2 -2
  306. package/neural-interface/public/shared/worker-questions.js +34 -0
  307. package/neural-interface/public/sidepanel-session.html +1 -1
  308. package/neural-interface/server.js +644 -426
  309. package/neural-interface/templates/rulesets/README.md +1 -1
  310. package/neural-interface/templates/rulesets/legacy-hashes.json +5 -5
  311. package/neural-interface/templates/rulesets/manifest.json +1 -1
  312. package/npm-shrinkwrap.json +18 -2
  313. package/package.json +2 -1
  314. package/skills/skill-forge/SKILL.md +4 -4
  315. package/skills/synabun/SKILL.md +1 -1
  316. package/skills/synabun/modules/schedule.md +3 -3
  317. /package/neural-interface/templates/rulesets/{gemini.md → antigravity.md} +0 -0
@@ -4,10 +4,24 @@ import { detectProject } from '../../mcp-server/dist/config.js';
4
4
  import { normalizeMemoryEvents, ingestMemoryEvents } from '../../mcp-server/dist/services/memory-sessions.js';
5
5
  import { maintenancePaused } from './memory-timers.js';
6
6
 
7
- export function queueMemoryCapture({host,sessionId,filePath,project,cwd}) {
8
- if(!filePath || !sessionId || !['claude-code','codex'].includes(host))return;
7
+ /** The hosts whose transcripts are captured from a file (OpenCode's rows are taken in session-cache-builder.js). */
8
+ export const CAPTURE_HOSTS=Object.freeze(['claude-code','codex','antigravity']);
9
+
10
+ /**
11
+ * `size`: the transcript's size now, when the caller knows it. A file already read to that size is left as it is
12
+ * (a pass over every Antigravity conversation would otherwise mark each one pending again).
13
+ */
14
+ export function queueMemoryCapture({host,sessionId,filePath,project,cwd,size=null}) {
15
+ if(!filePath || !sessionId || !CAPTURE_HOSTS.includes(host))return;
16
+ if(size!=null) {
17
+ const row=getDb().prepare('SELECT file_path,byte_offset,status,cwd FROM memory_capture_files WHERE host=? AND session_id=?').get(host,sessionId);
18
+ if(row && row.status==='complete' && row.file_path===filePath && Number(row.byte_offset)===Number(size) && (row.cwd || null)===(cwd || null))return;
19
+ }
20
+ // An Antigravity conversation whose folder agy named only later is read again from its start: its events take the
21
+ // project (each step keeps its source id, so nothing is stored twice).
9
22
  getDb().prepare(`INSERT INTO memory_capture_files(host,session_id,file_path,project,cwd) VALUES(?,?,?,?,?)
10
- ON CONFLICT(host,session_id) DO UPDATE SET file_path=excluded.file_path,project=excluded.project,cwd=excluded.cwd,status='pending',error=NULL`)
23
+ ON CONFLICT(host,session_id) DO UPDATE SET file_path=excluded.file_path,project=excluded.project,cwd=excluded.cwd,status='pending',error=NULL,
24
+ byte_offset=CASE WHEN excluded.host='antigravity' AND memory_capture_files.cwd IS NOT excluded.cwd THEN 0 ELSE memory_capture_files.byte_offset END`)
11
25
  .run(host,sessionId,filePath,cwd ? detectProject(cwd) : project || 'global',cwd || null);
12
26
  }
13
27
 
@@ -47,7 +47,8 @@ export function isMoreLoginInstalled() {
47
47
  } else if (process.platform === 'win32') {
48
48
  const { LOCALAPPDATA, ProgramFiles } = process.env;
49
49
  const PF86 = process.env['ProgramFiles(x86)'];
50
- if (LOCALAPPDATA) candidates.push(`${LOCALAPPDATA}\\Programs\\MoreLogin\\MoreLogin.exe`, `${LOCALAPPDATA}\\MoreLogin\\MoreLogin.exe`);
50
+ if (process.env.MORELOGIN_APP_PATH) candidates.push(process.env.MORELOGIN_APP_PATH);
51
+ if (LOCALAPPDATA) candidates.push(`${LOCALAPPDATA}\\Programs\\MoreLogin\\MoreLogin.exe`, `${LOCALAPPDATA}\\Programs\\morelogin\\MoreLogin.exe`, `${LOCALAPPDATA}\\MoreLogin\\MoreLogin.exe`);
51
52
  if (ProgramFiles) candidates.push(`${ProgramFiles}\\MoreLogin\\MoreLogin.exe`);
52
53
  if (PF86) candidates.push(`${PF86}\\MoreLogin\\MoreLogin.exe`);
53
54
  } else {
@@ -100,40 +101,147 @@ function buildHeaders(opts = {}) {
100
101
 
101
102
  /**
102
103
  * Low-level POST to the MoreLogin local API. Returns the `data` payload.
103
- * Throws with a `.code` of MORELOGIN_UNREACHABLE | MORELOGIN_HTTP | MORELOGIN_API.
104
+ * Throws with a `.code` of MORELOGIN_UNREACHABLE | MORELOGIN_HTTP | MORELOGIN_API | MORELOGIN_SHAPE
105
+ * (answered 2xx with a body that is not JSON).
106
+ */
107
+ // Loopback hosts to try, in order. MoreLogin's local server may listen on IPv6 only
108
+ // (an Electron server bound to "localhost" resolves to ::1 first on Windows), so a
109
+ // refused 127.0.0.1 is retried on [::1]. The host that answered is remembered.
110
+ const LOOPBACK_HOSTS = ['127.0.0.1', '[::1]'];
111
+ let _preferredHost = LOOPBACK_HOSTS[0];
112
+ let _lastAnswerAt = 0; // when the local API last answered anything (any status, any body)
113
+ export function _resetMoreLoginHostForTests() { _preferredHost = LOOPBACK_HOSTS[0]; _lastAnswerAt = 0; }
114
+ export function _preferredMoreLoginHostForTests() { return _preferredHost; }
115
+
116
+ /** Whether the local API answered within the last `withinMs` (no request is made). */
117
+ export function moreLoginApiAnsweredRecently(withinMs = 120000) {
118
+ return _lastAnswerAt > 0 && Date.now() - _lastAnswerAt <= withinMs;
119
+ }
120
+
121
+ /**
122
+ * Cheap, synchronous "is MoreLogin here": the exe is in a known folder (or
123
+ * MORELOGIN_APP_PATH) or its local API answered recently. Callers that need a
124
+ * fresh answer probe first (probeMoreLoginApi).
125
+ */
126
+ export function isMoreLoginPresent(withinMs = 120000) {
127
+ let exe = false;
128
+ try { exe = isMoreLoginInstalled().installed; } catch { exe = false; }
129
+ return exe || moreLoginApiAnsweredRecently(withinMs);
130
+ }
131
+
132
+ // Error codes that prove the connection never opened, so the request was never
133
+ // delivered and the other loopback host may be tried even for a call that changes
134
+ // state (create, start). Anything else (a reset after sending, a malformed answer)
135
+ // may have reached MoreLogin: it is thrown, never sent a second time.
136
+ const NEVER_CONNECTED_CODES = new Set([
137
+ 'ECONNREFUSED', 'EHOSTUNREACH', 'ENETUNREACH', 'EADDRNOTAVAIL', 'EAFNOSUPPORT', 'ENOTFOUND',
138
+ 'EAI_AGAIN', 'UND_ERR_CONNECT_TIMEOUT', 'UND_ERR_CONNECT',
139
+ ]);
140
+ export function _neverConnected(err) {
141
+ for (let e = err, i = 0; e && i < 4; e = e.cause, i++) {
142
+ if (NEVER_CONNECTED_CODES.has(e.code)) return true;
143
+ if (Array.isArray(e.errors) && e.errors.some(x => NEVER_CONNECTED_CODES.has(x?.code))) return true;
144
+ }
145
+ return false;
146
+ }
147
+
148
+ /**
149
+ * One deadline for the whole call (opts.timeout, default 15 s): each loopback host
150
+ * gets what is left of it, so two hosts never double the budget. The other host is
151
+ * tried while time remains when the first one provably never connected; a timeout
152
+ * is tried on the other host only for a read (opts.idempotent), since a timed-out
153
+ * write may have been received.
104
154
  */
105
155
  async function request(path, body, opts = {}) {
106
156
  const port = opts.port || getMoreLoginPort(opts.savedCfg);
107
- const url = `http://127.0.0.1:${port}${path}`;
157
+ const fetchImpl = opts.fetch || fetch;
158
+ const idempotent = opts.idempotent ?? (path === '/api/env/page' || path === '/api/env/status');
159
+ const budget = opts.timeout || 15000;
160
+ const deadline = Date.now() + budget;
161
+ const hosts = [_preferredHost, ...LOOPBACK_HOSTS.filter(h => h !== _preferredHost)];
108
162
  let res;
109
- try {
110
- res = await fetch(url, {
111
- method: 'POST',
112
- headers: buildHeaders(opts),
113
- body: JSON.stringify(body || {}),
114
- signal: AbortSignal.timeout(opts.timeout || 15000),
115
- });
116
- } catch (err) {
117
- const e = new Error(`MoreLogin API unreachable on :${port} (${err?.message || err})`);
163
+ let lastErr = null;
164
+ for (const host of hosts) {
165
+ const left = deadline - Date.now();
166
+ if (left <= 0) break;
167
+ try {
168
+ res = await fetchImpl(`http://${host}:${port}${path}`, {
169
+ method: 'POST',
170
+ headers: buildHeaders(opts),
171
+ body: JSON.stringify(body || {}),
172
+ signal: AbortSignal.timeout(left),
173
+ });
174
+ _preferredHost = host;
175
+ _lastAnswerAt = Date.now();
176
+ break;
177
+ } catch (err) {
178
+ lastErr = err;
179
+ const timedOut = err?.name === 'TimeoutError' || err?.name === 'AbortError';
180
+ const retry = _neverConnected(err) || (timedOut && idempotent);
181
+ if (!retry) break;
182
+ }
183
+ }
184
+ if (!res) {
185
+ const err = lastErr;
186
+ const reason = !err ? `no time left of ${budget} ms` : (err?.cause?.code || err?.code || err?.message || err);
187
+ const e = new Error(`MoreLogin API unreachable on :${port} (${reason})`);
118
188
  e.code = 'MORELOGIN_UNREACHABLE';
119
189
  throw e;
120
190
  }
121
191
  let json = null;
192
+ let unparsable = false;
122
193
  try { json = await res.json(); }
123
- catch { try { await res.body?.cancel(); } catch { /* ignore */ } }
194
+ catch { unparsable = true; try { await res.body?.cancel(); } catch { /* ignore */ } }
124
195
  if (!res.ok) {
125
- const e = new Error(`MoreLogin API ${path} → HTTP ${res.status}`);
196
+ const detail = json && (json.msg || json.message);
197
+ const e = new Error(`MoreLogin API ${path} → HTTP ${res.status}${detail ? ` (${detail})` : ''}${res.status === 401 || res.status === 403 ? ' (set the API ID and API Key from MoreLogin → Settings → API in SynaBun Settings → MoreLogin)' : ''}`);
126
198
  e.code = 'MORELOGIN_HTTP';
127
199
  e.status = res.status;
128
200
  throw e;
129
201
  }
130
202
  if (json && json.code !== undefined && json.code !== 0) {
131
- const e = new Error(`MoreLogin API ${path}: ${json.msg || `code ${json.code}`}`);
203
+ const msg = json.msg || json.message || `code ${json.code}`;
204
+ const e = new Error(`MoreLogin API ${path}: ${msg}${looksLikeAuthError(json.code, msg) ? ' (set the API ID and API Key from MoreLogin → Settings → API in SynaBun Settings → MoreLogin)' : ''}`);
132
205
  e.code = 'MORELOGIN_API';
133
206
  e.apiCode = json.code;
134
207
  throw e;
135
208
  }
136
- return json ? json.data : null;
209
+ if (unparsable || !json || typeof json !== 'object') {
210
+ const type = res.headers?.get?.('content-type') || 'no content type';
211
+ const e = new Error(`MoreLogin API ${path} answered HTTP ${res.status} with a body that is not JSON (${type}); is something else listening on port ${port}?`);
212
+ e.code = 'MORELOGIN_SHAPE';
213
+ throw e;
214
+ }
215
+ return json.data;
216
+ }
217
+
218
+ function looksLikeAuthError(code, msg) {
219
+ return /auth|sign|api.?key|api.?id|nonce|unauthori[sz]ed|forbidden|permission|token/i.test(String(msg || ''))
220
+ || code === 401 || code === 403;
221
+ }
222
+
223
+ const PROFILE_LIST_KEYS = ['dataList', 'list', 'records', 'rows'];
224
+
225
+ /** Profile rows across response shapes: data.dataList | data.list | data.records | data.rows | data (array). A non-empty array wins over an empty one. */
226
+ export function profileRows(data) {
227
+ if (Array.isArray(data)) return data;
228
+ if (!data || typeof data !== 'object') return [];
229
+ const arrays = PROFILE_LIST_KEYS.map(k => data[k]).filter(Array.isArray);
230
+ return arrays.find(a => a.length) || arrays[0] || [];
231
+ }
232
+
233
+ /** Whether a profile-page answer has a shape SynaBun reads (an array, a known list key, or a total). */
234
+ export function hasProfileShape(data) {
235
+ if (Array.isArray(data)) return true;
236
+ if (!data || typeof data !== 'object') return false;
237
+ return PROFILE_LIST_KEYS.some(k => Array.isArray(data[k])) || (data.total != null && Number.isFinite(Number(data.total)));
238
+ }
239
+
240
+ function shapeError(data) {
241
+ const keys = data && typeof data === 'object' ? Object.keys(data).slice(0, 8).join(', ') : typeof data;
242
+ const e = new Error(`MoreLogin API /api/env/page answered in a shape SynaBun does not read (data: ${keys || 'empty'}); a newer MoreLogin may have changed its API`);
243
+ e.code = 'MORELOGIN_SHAPE';
244
+ return e;
137
245
  }
138
246
 
139
247
  /**
@@ -171,19 +279,29 @@ function normalizeProfile(e = {}) {
171
279
  /** List browser profiles (environments). Returns normalized rows. */
172
280
  export async function listProfiles(opts = {}) {
173
281
  const data = await request('/api/env/page', { pageNo: opts.pageNo || 1, pageSize: opts.pageSize || 100 }, opts);
174
- const list = (data && (data.dataList || data.list)) || [];
175
- return list.map(normalizeProfile).filter(p => p.id);
282
+ if (!hasProfileShape(data)) throw shapeError(data);
283
+ return profileRows(data).map(normalizeProfile).filter(p => p.id);
176
284
  }
177
285
 
178
- /** Lightweight reachability probe. Never throws — returns {running, count}. */
286
+ /**
287
+ * Lightweight reachability probe. Never throws — returns {running, count}.
288
+ * `running` means the local API answered at all: an answer that is an HTTP or API
289
+ * error (signature required, API disabled, ...) still proves MoreLogin is up, and its
290
+ * reason is returned in `apiError` instead of being reported as "not running".
291
+ */
179
292
  export async function probeMoreLoginApi(opts = {}) {
180
293
  try {
181
294
  const data = await request('/api/env/page', { pageNo: 1, pageSize: 1 }, { ...opts, timeout: opts.timeout || 4000 });
182
- const total = data && data.total != null ? Number(data.total)
183
- : (data && (data.dataList || data.list) ? (data.dataList || data.list).length : 0);
295
+ if (!hasProfileShape(data)) throw shapeError(data);
296
+ const total = data && !Array.isArray(data) && data.total != null ? Number(data.total) : profileRows(data).length;
184
297
  return { running: true, count: Number.isFinite(total) ? total : 0 };
185
298
  } catch (err) {
186
- return { running: false, count: 0, error: err?.message || String(err), errCode: err?.code || null };
299
+ const answered = err?.code === 'MORELOGIN_HTTP' || err?.code === 'MORELOGIN_API' || err?.code === 'MORELOGIN_SHAPE';
300
+ return {
301
+ running: answered, count: 0,
302
+ error: err?.message || String(err), errCode: err?.code || null,
303
+ ...(answered ? { apiError: err?.message || String(err) } : {}),
304
+ };
187
305
  }
188
306
  }
189
307
 
@@ -221,13 +339,17 @@ export async function getMoreLoginStatus(opts = {}) {
221
339
  const port = getMoreLoginPort(opts.savedCfg);
222
340
  const probe = await probeMoreLoginApi({ ...opts, port });
223
341
  return {
224
- installed: inst.installed,
342
+ // An answering local API is proof of an install, wherever it lives (a custom
343
+ // install folder on Windows is not among the known paths).
344
+ installed: inst.installed || probe.running,
225
345
  appPath: inst.path,
226
346
  port,
227
347
  running: probe.running,
348
+ apiError: probe.apiError || null,
228
349
  profileCount: probe.count || 0,
229
350
  signed: !!((opts.appId || process.env.MORELOGIN_API_ID) && (opts.secretKey || process.env.MORELOGIN_SECRET)),
230
- error: probe.error || null,
351
+ // Transport failures only: an API that answered with an error is running, and says why in apiError.
352
+ error: probe.running ? null : (probe.error || null),
231
353
  };
232
354
  }
233
355
 
@@ -259,7 +381,7 @@ export async function startProfile(envId, opts = {}) {
259
381
  try {
260
382
  data = await request('/api/env/start', { envId: String(envId), ...(opts.startArgs || {}) }, opts);
261
383
  } catch (err) {
262
- if (err?.code === 'MORELOGIN_UNREACHABLE' || err?.code === 'MORELOGIN_HTTP') throw err;
384
+ if (err?.code === 'MORELOGIN_UNREACHABLE' || err?.code === 'MORELOGIN_HTTP' || err?.code === 'MORELOGIN_SHAPE') throw err;
263
385
  // MORELOGIN_API (e.g. "already running") → fall through to status recovery.
264
386
  }
265
387
  let port = extractDebugPort(data);