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.
- package/CHANGELOG.md +207 -0
- package/README.md +25 -2
- package/THIRD-PARTY-LICENSES.md +22 -0
- package/bin/synabun.js +71 -24
- package/docs/whatsapp.md +13 -13
- package/hooks/claude-code/pre-websearch.mjs +12 -1
- package/hooks/claude-code/shared.mjs +5 -0
- package/hooks/claude-code/stop.mjs +1 -1
- package/lib/claude-hooks.js +172 -18
- package/lib/client-config-repair.js +30 -17
- package/lib/desktop-app.js +7 -1
- package/lib/external-tools.js +7 -6
- package/lib/first-launch-protection.js +57 -12
- package/lib/mcp-dist.js +176 -0
- package/lib/release-npm-ci.mjs +138 -0
- package/lib/release-publish.mjs +91 -0
- package/lib/release-scan.mjs +50 -0
- package/lib/server-crash-record.js +123 -0
- package/lib/server-exit.js +318 -0
- package/lib/server-supervisor.js +508 -0
- package/lib/start-launcher.js +37 -4
- package/lib/tools-cli.js +45 -0
- package/lib/update-snapshot.js +302 -0
- package/lib/virustotal.mjs +203 -0
- package/lib/windows-crash-event.js +269 -0
- package/mcp-server/dist/http.d.ts +20 -1
- package/mcp-server/dist/http.d.ts.map +1 -1
- package/mcp-server/dist/http.js +59 -12
- package/mcp-server/dist/http.js.map +1 -1
- package/mcp-server/dist/index.d.ts +33 -27
- package/mcp-server/dist/index.d.ts.map +1 -1
- package/mcp-server/dist/index.js +128 -143
- package/mcp-server/dist/index.js.map +1 -1
- package/mcp-server/dist/preload.js +1 -1
- package/mcp-server/dist/preload.js.map +1 -1
- package/mcp-server/dist/services/budget-judgments.d.ts +1 -1
- package/mcp-server/dist/services/budget-judgments.d.ts.map +1 -1
- package/mcp-server/dist/services/budget-judgments.js +5 -3
- package/mcp-server/dist/services/budget-judgments.js.map +1 -1
- package/mcp-server/dist/services/codex-config-heal.d.ts +6 -2
- package/mcp-server/dist/services/codex-config-heal.d.ts.map +1 -1
- package/mcp-server/dist/services/codex-config-heal.js +81 -28
- package/mcp-server/dist/services/codex-config-heal.js.map +1 -1
- package/mcp-server/dist/services/identity.d.ts +2 -2
- package/mcp-server/dist/services/identity.js +2 -2
- package/mcp-server/dist/services/memory-judge-backfill.d.ts +6 -0
- package/mcp-server/dist/services/memory-judge-backfill.d.ts.map +1 -1
- package/mcp-server/dist/services/memory-judge-backfill.js +7 -1
- package/mcp-server/dist/services/memory-judge-backfill.js.map +1 -1
- package/mcp-server/dist/services/memory-sessions.d.ts +1 -1
- package/mcp-server/dist/services/memory-sessions.d.ts.map +1 -1
- package/mcp-server/dist/services/memory-sessions.js +28 -2
- package/mcp-server/dist/services/memory-sessions.js.map +1 -1
- package/mcp-server/dist/services/neural-interface.d.ts +18 -11
- package/mcp-server/dist/services/neural-interface.d.ts.map +1 -1
- package/mcp-server/dist/services/neural-interface.js +67 -11
- package/mcp-server/dist/services/neural-interface.js.map +1 -1
- package/mcp-server/dist/services/server-instructions.d.ts +7 -2
- package/mcp-server/dist/services/server-instructions.d.ts.map +1 -1
- package/mcp-server/dist/services/server-instructions.js +22 -63
- package/mcp-server/dist/services/server-instructions.js.map +1 -1
- package/mcp-server/dist/services/tool-catalog.d.ts +120 -0
- package/mcp-server/dist/services/tool-catalog.d.ts.map +1 -0
- package/mcp-server/dist/services/tool-catalog.js +339 -0
- package/mcp-server/dist/services/tool-catalog.js.map +1 -0
- package/mcp-server/dist/services/tool-list-refresh-barrier.d.ts +12 -0
- package/mcp-server/dist/services/tool-list-refresh-barrier.d.ts.map +1 -0
- package/mcp-server/dist/services/tool-list-refresh-barrier.js +40 -0
- package/mcp-server/dist/services/tool-list-refresh-barrier.js.map +1 -0
- package/mcp-server/dist/services/tool-list.d.ts +108 -0
- package/mcp-server/dist/services/tool-list.d.ts.map +1 -0
- package/mcp-server/dist/services/tool-list.js +334 -0
- package/mcp-server/dist/services/tool-list.js.map +1 -0
- package/mcp-server/dist/services/tool-runtime.d.ts +161 -0
- package/mcp-server/dist/services/tool-runtime.d.ts.map +1 -0
- package/mcp-server/dist/services/tool-runtime.js +400 -0
- package/mcp-server/dist/services/tool-runtime.js.map +1 -0
- package/mcp-server/dist/services/typesafe-config.js +1 -1
- package/mcp-server/dist/services/typesafe-config.js.map +1 -1
- package/mcp-server/dist/services/whiteboard-geometry.d.ts +26 -2
- package/mcp-server/dist/services/whiteboard-geometry.d.ts.map +1 -1
- package/mcp-server/dist/services/whiteboard-geometry.js +91 -8
- package/mcp-server/dist/services/whiteboard-geometry.js.map +1 -1
- package/mcp-server/dist/tools/agents.d.ts +14 -14
- package/mcp-server/dist/tools/agents.d.ts.map +1 -1
- package/mcp-server/dist/tools/agents.js +29 -19
- package/mcp-server/dist/tools/agents.js.map +1 -1
- package/mcp-server/dist/tools/browser-batch.d.ts +3 -3
- package/mcp-server/dist/tools/choice.d.ts +6 -0
- package/mcp-server/dist/tools/choice.d.ts.map +1 -1
- package/mcp-server/dist/tools/choice.js +18 -13
- package/mcp-server/dist/tools/choice.js.map +1 -1
- package/mcp-server/dist/tools/git-tools.js +2 -2
- package/mcp-server/dist/tools/git-tools.js.map +1 -1
- package/mcp-server/dist/tools/image-tools.d.ts +1 -1
- package/mcp-server/dist/tools/image-tools.js +1 -1
- package/mcp-server/dist/tools/morelogin.d.ts.map +1 -1
- package/mcp-server/dist/tools/morelogin.js +9 -6
- package/mcp-server/dist/tools/morelogin.js.map +1 -1
- package/mcp-server/dist/tools/skill-tools.d.ts +505 -0
- package/mcp-server/dist/tools/skill-tools.d.ts.map +1 -0
- package/mcp-server/dist/tools/skill-tools.js +642 -0
- package/mcp-server/dist/tools/skill-tools.js.map +1 -0
- package/mcp-server/dist/tools/skill.d.ts +7 -0
- package/mcp-server/dist/tools/skill.d.ts.map +1 -0
- package/mcp-server/dist/tools/skill.js +11 -0
- package/mcp-server/dist/tools/skill.js.map +1 -0
- package/mcp-server/dist/tools/tool-groups.d.ts +68 -0
- package/mcp-server/dist/tools/tool-groups.d.ts.map +1 -0
- package/mcp-server/dist/tools/tool-groups.js +147 -0
- package/mcp-server/dist/tools/tool-groups.js.map +1 -0
- package/mcp-server/dist/tools/whiteboard-format.d.ts.map +1 -1
- package/mcp-server/dist/tools/whiteboard-format.js +7 -4
- package/mcp-server/dist/tools/whiteboard-format.js.map +1 -1
- package/mcp-server/dist/tools/whiteboard-tools.d.ts +64 -13
- package/mcp-server/dist/tools/whiteboard-tools.d.ts.map +1 -1
- package/mcp-server/dist/tools/whiteboard-tools.js +30 -5
- package/mcp-server/dist/tools/whiteboard-tools.js.map +1 -1
- package/mcp-server/package-lock.json +2 -2
- package/mcp-server/package.json +1 -1
- package/mcp-server/src/http.ts +75 -12
- package/mcp-server/src/index.ts +147 -154
- package/mcp-server/src/preload.ts +12 -12
- package/mcp-server/src/services/budget-judgments.ts +5 -3
- package/mcp-server/src/services/codex-config-heal.ts +80 -29
- package/mcp-server/src/services/identity.ts +2 -2
- package/mcp-server/src/services/memory-judge-backfill.ts +7 -1
- package/mcp-server/src/services/memory-sessions.ts +24 -3
- package/mcp-server/src/services/neural-interface.ts +81 -21
- package/mcp-server/src/services/server-instructions.ts +29 -64
- package/mcp-server/src/services/tool-catalog.ts +403 -0
- package/mcp-server/src/services/tool-list-refresh-barrier.ts +33 -0
- package/mcp-server/src/services/tool-list.ts +410 -0
- package/mcp-server/src/services/tool-runtime.ts +457 -0
- package/mcp-server/src/services/typesafe-config.ts +1 -1
- package/mcp-server/src/services/whiteboard-geometry.ts +94 -9
- package/mcp-server/src/tools/agents.ts +29 -20
- package/mcp-server/src/tools/choice.ts +17 -12
- package/mcp-server/src/tools/git-tools.ts +2 -2
- package/mcp-server/src/tools/image-tools.ts +1 -1
- package/mcp-server/src/tools/morelogin.ts +6 -4
- package/mcp-server/src/tools/skill-tools.ts +592 -0
- package/mcp-server/src/tools/skill.ts +13 -0
- package/mcp-server/src/tools/tool-groups.ts +164 -0
- package/mcp-server/src/tools/whiteboard-format.ts +9 -3
- package/mcp-server/src/tools/whiteboard-tools.ts +39 -5
- package/neural-interface/i18n/en.json +3953 -228
- package/neural-interface/i18n/pt-BR.json +3901 -179
- package/neural-interface/lib/agent-sandbox-elevation.js +6 -0
- package/neural-interface/lib/antigravity/acp-client-host.js +554 -0
- package/neural-interface/lib/antigravity/acp-connection.js +299 -0
- package/neural-interface/lib/antigravity/bypass.js +100 -0
- package/neural-interface/lib/antigravity/catalog.js +273 -0
- package/neural-interface/lib/antigravity/home.js +260 -0
- package/neural-interface/lib/antigravity/migrate-gemini.js +139 -0
- package/neural-interface/lib/antigravity/panel-bridge.js +1058 -0
- package/neural-interface/lib/antigravity/policy-hook.mjs +78 -0
- package/neural-interface/lib/antigravity/policy.js +74 -0
- package/neural-interface/lib/antigravity/tool-call.js +178 -0
- package/neural-interface/lib/antigravity/transcripts.js +252 -0
- package/neural-interface/lib/antigravity/usage.js +43 -0
- package/neural-interface/lib/assistant-api.js +128 -28
- package/neural-interface/lib/assistant-brains/antigravity.js +423 -0
- package/neural-interface/lib/assistant-brains/claude.js +4 -3
- package/neural-interface/lib/assistant-brains/codex-browser-policy-hook.mjs +12 -2
- package/neural-interface/lib/assistant-brains/codex-route-gate-hook.mjs +32 -9
- package/neural-interface/lib/assistant-brains/codex.js +9 -5
- package/neural-interface/lib/assistant-brains/opencode.js +120 -54
- package/neural-interface/lib/assistant-brains/opencode2-browser-policy/index.js +28 -13
- package/neural-interface/lib/assistant-brains/opencode2-route-gate/index.js +59 -19
- package/neural-interface/lib/assistant-budget-planner.js +7 -3
- package/neural-interface/lib/assistant-budget-split.js +42 -15
- package/neural-interface/lib/assistant-catalog.js +81 -15
- package/neural-interface/lib/assistant-config.js +6 -3
- package/neural-interface/lib/assistant-dispatch.js +1073 -200
- package/neural-interface/lib/assistant-envelope.js +156 -2
- package/neural-interface/lib/assistant-evidence.js +80 -0
- package/neural-interface/lib/assistant-hidden-models.js +7 -5
- package/neural-interface/lib/assistant-persona.js +93 -19
- package/neural-interface/lib/assistant-plan-permissions.js +25 -9
- package/neural-interface/lib/assistant-route-gate-codex.js +3 -0
- package/neural-interface/lib/assistant-route-gate.js +6 -4
- package/neural-interface/lib/assistant-router.js +245 -38
- package/neural-interface/lib/assistant-runtime.js +214 -30
- package/neural-interface/lib/assistant-task-prompt.js +87 -21
- package/neural-interface/lib/assistant-tools.js +51 -0
- package/neural-interface/lib/assistant-usage.js +29 -0
- package/neural-interface/lib/backup-service.js +626 -4
- package/neural-interface/lib/backup-zip-reader.js +10 -5
- package/neural-interface/lib/backup-zip-writer.js +257 -0
- package/neural-interface/lib/browser-execution.js +10 -2
- package/neural-interface/lib/browser-guard-cdp.js +84 -0
- package/neural-interface/lib/browser-network-guard.js +476 -0
- package/neural-interface/lib/browser-policy-roots.js +64 -0
- package/neural-interface/lib/browser-tool-policy.js +198 -38
- package/neural-interface/lib/claude-agent-bridge.js +11 -2
- package/neural-interface/lib/claude-history-cache.js +210 -0
- package/neural-interface/lib/claude-hooks-status.js +103 -0
- package/neural-interface/lib/claude-model-catalog.js +5 -1
- package/neural-interface/lib/claude-temporary.js +5 -11
- package/neural-interface/lib/cli-install-api.js +1 -1
- package/neural-interface/lib/cli-install.js +163 -154
- package/neural-interface/lib/cli-resolver.js +13 -3
- package/neural-interface/lib/cli-update-planner.js +52 -41
- package/neural-interface/lib/cloudflared/tunnel.js +42 -2
- package/neural-interface/lib/codex-mcp-approvals.js +11 -0
- package/neural-interface/lib/codex-rollout-reader.js +52 -0
- package/neural-interface/lib/codex-worker-app-server.js +191 -0
- package/neural-interface/lib/confined-fs.js +30 -3
- package/neural-interface/lib/crash-notice-api.js +98 -0
- package/neural-interface/lib/editor-completion-opencode.js +68 -68
- package/neural-interface/lib/editor-git-api.js +3 -20
- package/neural-interface/lib/exec-loop-command.js +13 -10
- package/neural-interface/lib/file-explorer-api.js +74 -40
- package/neural-interface/lib/file-explorer-watch.js +9 -3
- package/neural-interface/lib/git-bash/install.js +52 -6
- package/neural-interface/lib/git-bash/manager.js +59 -17
- package/neural-interface/lib/git-bash/pins.js +12 -0
- package/neural-interface/lib/git-read.js +2 -2
- package/neural-interface/lib/git-status-runner.js +390 -0
- package/neural-interface/lib/git-status-watchdog.js +40 -0
- package/neural-interface/lib/greeting/budgets.js +1 -0
- package/neural-interface/lib/greeting/engine.js +2 -2
- package/neural-interface/lib/greeting/sources.js +10 -12
- package/neural-interface/lib/greeting/writer.js +1 -1
- package/neural-interface/lib/http-guards.js +8 -2
- package/neural-interface/lib/install-details.js +4 -1
- package/neural-interface/lib/mcp-agent-servers.js +67 -0
- package/neural-interface/lib/mcp-client-config.js +35 -33
- package/neural-interface/lib/mcp-external-servers.js +332 -0
- package/neural-interface/lib/mcp-installer.js +2 -1
- package/neural-interface/lib/{mcp-profile-refresh-coordinator.js → mcp-tools-refresh-coordinator.js} +4 -4
- package/neural-interface/lib/memory-session-capture.js +17 -3
- package/neural-interface/lib/morelogin.js +177 -25
- package/neural-interface/lib/native-loop-providers.js +965 -66
- package/neural-interface/lib/native-loop-runtime.js +290 -42
- package/neural-interface/lib/opencode-config.js +557 -0
- package/neural-interface/lib/opencode-db-schema.js +17 -34
- package/neural-interface/lib/opencode-history.js +48 -218
- package/neural-interface/lib/opencode-mcp-ready.js +108 -0
- package/neural-interface/lib/opencode-native-boundary.js +53 -0
- package/neural-interface/lib/opencode-protocol.js +249 -112
- package/neural-interface/lib/opencode-runtime-config.js +32 -22
- package/neural-interface/lib/opencode-serve-records.js +39 -21
- package/neural-interface/lib/opencode-v2-client.js +48 -153
- package/neural-interface/lib/opencode-v2-ws-requests.js +36 -210
- package/neural-interface/lib/opencode-worker-data.js +27 -0
- package/neural-interface/lib/opencode2-client.js +73 -37
- package/neural-interface/lib/opencode2-proxy.js +23 -63
- package/neural-interface/lib/opencode2-translate.js +51 -2
- package/neural-interface/lib/owner-authority.js +249 -0
- package/neural-interface/lib/page-session.js +275 -0
- package/neural-interface/lib/path-confine.js +12 -9
- package/neural-interface/lib/peer-identity.js +793 -0
- package/neural-interface/lib/pty-host/core.js +28 -1
- package/neural-interface/lib/pty-host/lifetime.js +12 -0
- package/neural-interface/lib/pty-host/manager.js +12 -1
- package/neural-interface/lib/remote-policy.js +1 -1
- package/neural-interface/lib/request-gate.js +20 -2
- package/neural-interface/lib/rulesets/api.js +7 -6
- package/neural-interface/lib/rulesets/fs-safe.js +1 -1
- package/neural-interface/lib/rulesets/installer.js +180 -36
- package/neural-interface/lib/rulesets/json-edit.js +1 -1
- package/neural-interface/lib/rulesets/render.js +1 -1
- package/neural-interface/lib/session-cache-builder.js +81 -31
- package/neural-interface/lib/session-title-generator.js +58 -36
- package/neural-interface/lib/skills/api-v2.js +495 -0
- package/neural-interface/lib/skills/bundle.js +418 -0
- package/neural-interface/lib/skills/catalog.js +298 -0
- package/neural-interface/lib/skills/creation-api.js +191 -0
- package/neural-interface/lib/skills/creation-brief.js +247 -0
- package/neural-interface/lib/skills/creation-sources.js +285 -0
- package/neural-interface/lib/skills/creation.js +843 -0
- package/neural-interface/lib/skills/deploy.js +569 -0
- package/neural-interface/lib/skills/digest.js +119 -0
- package/neural-interface/lib/skills/discover.js +111 -0
- package/neural-interface/lib/skills/draft-confinement.js +216 -0
- package/neural-interface/lib/skills/eval-confinement.js +399 -0
- package/neural-interface/lib/skills/eval-sandbox.js +280 -0
- package/neural-interface/lib/skills/eval-trace.js +135 -0
- package/neural-interface/lib/skills/evals-api.js +212 -0
- package/neural-interface/lib/skills/evals.js +1573 -0
- package/neural-interface/lib/skills/export.js +203 -0
- package/neural-interface/lib/skills/frontmatter.js +64 -0
- package/neural-interface/lib/skills/health.js +75 -0
- package/neural-interface/lib/skills/json-edit.js +165 -0
- package/neural-interface/lib/skills/known-bridge-digests.json +441 -0
- package/neural-interface/lib/skills/known-bridges.js +96 -0
- package/neural-interface/lib/skills/library.js +823 -0
- package/neural-interface/lib/skills/local-store.js +21 -0
- package/neural-interface/lib/skills/migration.js +433 -0
- package/neural-interface/lib/skills/operations.js +45 -0
- package/neural-interface/lib/skills/ownership.js +427 -0
- package/neural-interface/lib/skills/packages.js +88 -0
- package/neural-interface/lib/skills/reviews.js +212 -0
- package/neural-interface/lib/skills/revision.js +80 -0
- package/neural-interface/lib/skills/roots.js +269 -0
- package/neural-interface/lib/skills/runtime-checks.js +358 -0
- package/neural-interface/lib/skills/scan-assets.js +252 -0
- package/neural-interface/lib/skills/scan-context.js +26 -0
- package/neural-interface/lib/skills/scan-shell.js +324 -0
- package/neural-interface/lib/skills/scan.js +364 -0
- package/neural-interface/lib/skills/scanners.js +54 -0
- package/neural-interface/lib/skills/service.js +530 -0
- package/neural-interface/lib/skills/telemetry.js +119 -0
- package/neural-interface/lib/sqlite-integrity-worker.js +22 -0
- package/neural-interface/lib/synabun-version.js +1 -1
- package/neural-interface/lib/system-activity.js +1 -1
- package/neural-interface/lib/tool-lists.js +124 -0
- package/neural-interface/lib/whatsapp/brain.js +7 -3
- package/neural-interface/lib/whatsapp/bridge.js +6 -3
- package/neural-interface/lib/whatsapp/cards.js +22 -9
- package/neural-interface/lib/whatsapp/config.js +1 -1
- package/neural-interface/lib/worker-confinement.js +1268 -0
- package/neural-interface/lib/worker-guard-setting.js +56 -0
- package/neural-interface/lib/worker-mcp-channel.js +175 -0
- package/neural-interface/lib/worker-question.js +74 -0
- package/neural-interface/lib/worker-relay-ports.js +227 -0
- package/neural-interface/lib/worker-resume.js +238 -0
- package/neural-interface/lib/worker-sandbox.js +329 -0
- package/neural-interface/package-lock.json +34 -12
- package/neural-interface/package.json +3 -2
- package/neural-interface/public/index.html +3 -1
- package/neural-interface/public/index2d.html +19 -11
- package/neural-interface/public/onboarding.html +3 -3
- package/neural-interface/public/shared/account-menu.js +8 -5
- package/neural-interface/public/shared/agent-runtime-options.js +125 -31
- package/neural-interface/public/shared/agy/agy-bypass.js +47 -0
- package/neural-interface/public/shared/agy/agy-client.js +266 -0
- package/neural-interface/public/shared/agy/agy-commands.js +120 -0
- package/neural-interface/public/shared/agy/agy-copy.js +326 -0
- package/neural-interface/public/shared/agy/agy-diff.js +161 -0
- package/neural-interface/public/shared/agy/agy-events.js +469 -0
- package/neural-interface/public/shared/agy/agy-greeting.js +26 -0
- package/neural-interface/public/shared/agy/agy-options.js +232 -0
- package/neural-interface/public/shared/agy/agy-panel.js +2543 -0
- package/neural-interface/public/shared/agy/agy-render.js +392 -0
- package/neural-interface/public/shared/agy/agy-setup.js +149 -0
- package/neural-interface/public/shared/agy/agy-styles.js +604 -0
- package/neural-interface/public/shared/agy/agy-tabs-logic.js +181 -0
- package/neural-interface/public/shared/api.js +1527 -1336
- package/neural-interface/public/shared/app-frame.js +192 -0
- package/neural-interface/public/shared/assistant/asst-agents-dock.js +36 -6
- package/neural-interface/public/shared/assistant/asst-api.js +1 -1
- package/neural-interface/public/shared/assistant/asst-ask-styles.js +270 -0
- package/neural-interface/public/shared/assistant/asst-ask-tail.js +118 -0
- package/neural-interface/public/shared/assistant/asst-ask.js +397 -0
- package/neural-interface/public/shared/assistant/asst-brain-picker.js +105 -44
- package/neural-interface/public/shared/assistant/asst-budget.js +5 -4
- package/neural-interface/public/shared/assistant/asst-control.js +205 -26
- package/neural-interface/public/shared/assistant/asst-followups-card.js +383 -0
- package/neural-interface/public/shared/assistant/asst-followups.js +417 -0
- package/neural-interface/public/shared/assistant/asst-hosts.js +16 -7
- package/neural-interface/public/shared/assistant/asst-limit-dock.js +45 -0
- package/neural-interface/public/shared/assistant/asst-limit-wait.js +327 -0
- package/neural-interface/public/shared/assistant/asst-limit.js +168 -0
- package/neural-interface/public/shared/assistant/asst-mascot.js +49 -12
- package/neural-interface/public/shared/assistant/asst-menu.js +7 -6
- package/neural-interface/public/shared/assistant/asst-panel.js +151 -19
- package/neural-interface/public/shared/assistant/asst-rack-styles.js +66 -49
- package/neural-interface/public/shared/assistant/asst-render.js +445 -82
- package/neural-interface/public/shared/assistant/asst-route.js +304 -53
- package/neural-interface/public/shared/assistant/asst-routes-editor.js +9 -8
- package/neural-interface/public/shared/assistant/asst-scenes.js +56 -1
- package/neural-interface/public/shared/assistant/asst-sidepanel.js +117 -10
- package/neural-interface/public/shared/assistant/asst-slash.js +17 -9
- package/neural-interface/public/shared/assistant/asst-state.js +87 -24
- package/neural-interface/public/shared/assistant/asst-stop.js +127 -0
- package/neural-interface/public/shared/assistant/asst-styles.js +93 -21
- package/neural-interface/public/shared/assistant/asst-tool-kinds.js +190 -23
- package/neural-interface/public/shared/assistant/asst-usage.js +2 -1
- package/neural-interface/public/shared/automation-context.js +5 -2
- package/neural-interface/public/shared/cc-dropdown.js +89 -19
- package/neural-interface/public/shared/cdx/cdx-context-menu.js +10 -9
- package/neural-interface/public/shared/cdx/cdx-copy.js +16 -0
- package/neural-interface/public/shared/cdx/cdx-output-model.js +22 -1
- package/neural-interface/public/shared/cdx/cdx-output.js +34 -10
- package/neural-interface/public/shared/cdx/cdx-panel.js +59 -151
- package/neural-interface/public/shared/cdx/cdx-preview.js +12 -0
- package/neural-interface/public/shared/cdx/cdx-protocol.js +39 -11
- package/neural-interface/public/shared/cdx/cdx-render.js +57 -38
- package/neural-interface/public/shared/cdx/cdx-requests.js +14 -4
- package/neural-interface/public/shared/cdx/cdx-skill-hints.js +54 -0
- package/neural-interface/public/shared/cdx/cdx-styles.js +15 -3
- package/neural-interface/public/shared/cdx/cdx-tabs.js +127 -44
- package/neural-interface/public/shared/cdx/cdx-ws.js +0 -1
- package/neural-interface/public/shared/cli-install-controller.js +218 -0
- package/neural-interface/public/shared/cli-install-view.js +11 -12
- package/neural-interface/public/shared/cli-status.js +11 -10
- package/neural-interface/public/shared/constants.js +5 -4
- package/neural-interface/public/shared/context-menu-areas.js +34 -0
- package/neural-interface/public/shared/context-menu-logic.js +243 -0
- package/neural-interface/public/shared/context-menu-model.js +367 -0
- package/neural-interface/public/shared/context-menu.js +372 -0
- package/neural-interface/public/shared/cp/cp-context-menu.js +10 -9
- package/neural-interface/public/shared/cp/cp-restore.js +162 -0
- package/neural-interface/public/shared/cp/cp-tool-cards.js +10 -3
- package/neural-interface/public/shared/crash-notice-view.js +168 -0
- package/neural-interface/public/shared/desktop-bridge.js +17 -0
- package/neural-interface/public/shared/desktop-titlebar-view.js +12 -0
- package/neural-interface/public/shared/desktop-titlebar.js +13 -4
- package/neural-interface/public/shared/desktop-update-view.js +21 -0
- package/neural-interface/public/shared/editor/editor-panel-logic.js +2 -2
- package/neural-interface/public/shared/explorer/fx-api.js +4 -4
- package/neural-interface/public/shared/explorer/fx-links.js +3 -3
- package/neural-interface/public/shared/explorer/fx-logic.js +1 -1
- package/neural-interface/public/shared/explorer/fx-main.js +48 -16
- package/neural-interface/public/shared/explorer/fx-tree.js +1 -0
- package/neural-interface/public/shared/greeting/greeting-card.js +2 -2
- package/neural-interface/public/shared/greeting/greeting-view.js +1 -0
- package/neural-interface/public/shared/html-shell.js +30 -15
- package/neural-interface/public/shared/i18n.js +2 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-approvals.js +7 -7
- package/neural-interface/public/shared/ocp-v2/ocp-v2-binding.js +4 -4
- package/neural-interface/public/shared/ocp-v2/ocp-v2-changes-logic.js +3 -101
- package/neural-interface/public/shared/ocp-v2/ocp-v2-childpanel.js +2 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-compact-button.js +1 -3
- package/neural-interface/public/shared/ocp-v2/ocp-v2-composer-logic.js +2 -6
- package/neural-interface/public/shared/ocp-v2/ocp-v2-context-menu.js +11 -11
- package/neural-interface/public/shared/ocp-v2/ocp-v2-context-model.js +0 -3
- package/neural-interface/public/shared/ocp-v2/ocp-v2-events.js +8 -4
- package/neural-interface/public/shared/ocp-v2/ocp-v2-manager.js +7 -7
- package/neural-interface/public/shared/ocp-v2/ocp-v2-outcome-notifications.js +16 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-panel.js +74 -259
- package/neural-interface/public/shared/ocp-v2/ocp-v2-plan.js +1 -2
- package/neural-interface/public/shared/ocp-v2/ocp-v2-projectbar.js +95 -202
- package/neural-interface/public/shared/ocp-v2/ocp-v2-rehydrate.js +13 -4
- package/neural-interface/public/shared/ocp-v2/ocp-v2-render.js +13 -22
- package/neural-interface/public/shared/ocp-v2/ocp-v2-send.js +4 -4
- package/neural-interface/public/shared/ocp-v2/ocp-v2-session-actions.js +8 -61
- package/neural-interface/public/shared/ocp-v2/ocp-v2-sessions-logic.js +2 -91
- package/neural-interface/public/shared/ocp-v2/ocp-v2-slash-hints.js +16 -15
- package/neural-interface/public/shared/ocp-v2/ocp-v2-state.js +8 -21
- package/neural-interface/public/shared/ocp-v2/ocp-v2-status-logic.js +1 -99
- package/neural-interface/public/shared/ocp-v2/ocp-v2-status.js +5 -35
- package/neural-interface/public/shared/ocp-v2/ocp-v2-styles.js +17 -21
- package/neural-interface/public/shared/ocp-v2/{ocp-v2-profile-inheritance.js → ocp-v2-tools-inheritance.js} +16 -16
- package/neural-interface/public/shared/ocp-v2/ocp-v2-ws.js +60 -50
- package/neural-interface/public/shared/page-session.js +96 -0
- package/neural-interface/public/shared/provider-icons.js +4 -2
- package/neural-interface/public/shared/registry.js +5 -3
- package/neural-interface/public/shared/retired-2d.js +3 -0
- package/neural-interface/public/shared/schedules-view.js +195 -61
- package/neural-interface/public/shared/settings/settings-claude-hooks.js +135 -0
- package/neural-interface/public/shared/settings/settings-data.js +3 -1
- package/neural-interface/public/shared/settings/settings-ia.js +6 -6
- package/neural-interface/public/shared/settings/settings-opencode.js +89 -0
- package/neural-interface/public/shared/settings/settings-rules.js +2 -2
- package/neural-interface/public/shared/settings/settings-skill-folders-pane.js +265 -0
- package/neural-interface/public/shared/settings/settings-skill-folders.js +130 -0
- package/neural-interface/public/shared/settings/settings-worker-guard.js +72 -0
- package/neural-interface/public/shared/showcase-privacy.js +6 -1
- package/neural-interface/public/shared/sidepanel-session-status.js +3 -3
- package/neural-interface/public/shared/skills/ss-args.js +96 -0
- package/neural-interface/public/shared/skills/ss-creation.js +222 -0
- package/neural-interface/public/shared/skills/ss-dialog.js +133 -0
- package/neural-interface/public/shared/skills/ss-doc.js +173 -0
- package/neural-interface/public/shared/skills/ss-eval-adapters.js +269 -0
- package/neural-interface/public/shared/skills/ss-eval-grade.js +359 -0
- package/neural-interface/public/shared/skills/ss-eval-optimise.js +153 -0
- package/neural-interface/public/shared/skills/ss-eval-plan.js +315 -0
- package/neural-interface/public/shared/skills/ss-evals.js +417 -0
- package/neural-interface/public/shared/skills/ss-form.js +159 -0
- package/neural-interface/public/shared/skills/ss-frontmatter.js +376 -0
- package/neural-interface/public/shared/skills/ss-ids.js +32 -0
- package/neural-interface/public/shared/skills/ss-lint.js +149 -0
- package/neural-interface/public/shared/skills/ss-presets.js +117 -0
- package/neural-interface/public/shared/skills/ss-profiles.js +513 -0
- package/neural-interface/public/shared/skills/ss-resources.js +165 -0
- package/neural-interface/public/shared/skills/ss-review-view.js +190 -0
- package/neural-interface/public/shared/skills/ss-tabs.js +79 -0
- package/neural-interface/public/shared/skills/ss-unicode.js +135 -0
- package/neural-interface/public/shared/skills/studio/sx-actions.js +222 -0
- package/neural-interface/public/shared/skills/studio/sx-cm.js +101 -0
- package/neural-interface/public/shared/skills/studio/sx-create-ai-view.js +749 -0
- package/neural-interface/public/shared/skills/studio/sx-create-ai.js +237 -0
- package/neural-interface/public/shared/skills/studio/sx-create-view.js +254 -0
- package/neural-interface/public/shared/skills/studio/sx-create.js +126 -0
- package/neural-interface/public/shared/skills/studio/sx-diff-view.js +43 -0
- package/neural-interface/public/shared/skills/studio/sx-diff.js +133 -0
- package/neural-interface/public/shared/skills/studio/sx-docs.js +480 -0
- package/neural-interface/public/shared/skills/studio/sx-dom.js +230 -0
- package/neural-interface/public/shared/skills/studio/sx-edit-view.js +848 -0
- package/neural-interface/public/shared/skills/studio/sx-editor-model.js +193 -0
- package/neural-interface/public/shared/skills/studio/sx-errors.js +22 -0
- package/neural-interface/public/shared/skills/studio/sx-fixes-view.js +359 -0
- package/neural-interface/public/shared/skills/studio/sx-fixes.js +327 -0
- package/neural-interface/public/shared/skills/studio/sx-geometry.js +82 -0
- package/neural-interface/public/shared/skills/studio/sx-import.js +262 -0
- package/neural-interface/public/shared/skills/studio/sx-inspector.js +308 -0
- package/neural-interface/public/shared/skills/studio/sx-install-flow.js +282 -0
- package/neural-interface/public/shared/skills/studio/sx-install.js +313 -0
- package/neural-interface/public/shared/skills/studio/sx-library-view.js +748 -0
- package/neural-interface/public/shared/skills/studio/sx-library.js +479 -0
- package/neural-interface/public/shared/skills/studio/sx-main.js +690 -0
- package/neural-interface/public/shared/skills/studio/sx-operations-view.js +98 -0
- package/neural-interface/public/shared/skills/studio/sx-operations.js +11 -0
- package/neural-interface/public/shared/skills/studio/sx-plan.js +158 -0
- package/neural-interface/public/shared/skills/studio/sx-publish-view.js +621 -0
- package/neural-interface/public/shared/skills/studio/sx-review-view.js +369 -0
- package/neural-interface/public/shared/skills/studio/sx-review.js +148 -0
- package/neural-interface/public/shared/skills/studio/sx-scan.js +35 -0
- package/neural-interface/public/shared/skills/studio/sx-snippets.js +96 -0
- package/neural-interface/public/shared/skills/studio/sx-subject.js +249 -0
- package/neural-interface/public/shared/skills/studio/sx-test-view.js +994 -0
- package/neural-interface/public/shared/skills/studio/sx-test.js +328 -0
- package/neural-interface/public/shared/skills/studio/sx-versions-view.js +241 -0
- package/neural-interface/public/shared/skills/studio/sx-workspace-view.js +426 -0
- package/neural-interface/public/shared/state.js +1 -1
- package/neural-interface/public/shared/streaming-markdown.js +58 -0
- package/neural-interface/public/shared/styleguide/sg-panel.js +4 -2
- package/neural-interface/public/shared/styles.css +1822 -1756
- package/neural-interface/public/shared/synabun-mascot.js +1115 -9
- package/neural-interface/public/shared/text-cache.js +29 -0
- package/neural-interface/public/shared/tool-list-picker.js +55 -0
- package/neural-interface/public/shared/tool-list-storage.js +24 -0
- package/neural-interface/public/shared/tool-list-view.js +112 -0
- package/neural-interface/public/shared/topright-overflow-logic.js +54 -0
- package/neural-interface/public/shared/tour/tour-actor.js +268 -0
- package/neural-interface/public/shared/tour/tour-beats.js +336 -0
- package/neural-interface/public/shared/tour/tour-engine.js +884 -0
- package/neural-interface/public/shared/tour/tour-ink.js +390 -0
- package/neural-interface/public/shared/tour/tour-stage.js +440 -0
- package/neural-interface/public/shared/tour/tour-state.js +40 -0
- package/neural-interface/public/shared/tour/tour-tips.js +99 -0
- package/neural-interface/public/shared/tour/tour.css +144 -0
- package/neural-interface/public/shared/ui-antigravity-panel.js +19 -0
- package/neural-interface/public/shared/ui-assistant.js +2 -0
- package/neural-interface/public/shared/ui-automation-studio.js +111 -140
- package/neural-interface/public/shared/ui-claude-panel.js +376 -82
- package/neural-interface/public/shared/ui-cli-banner.js +23 -167
- package/neural-interface/public/shared/ui-command-runner.js +6 -3
- package/neural-interface/public/shared/ui-context-menu.js +295 -0
- package/neural-interface/public/shared/ui-cost-widget.js +57 -59
- package/neural-interface/public/shared/ui-crash-notice.js +187 -0
- package/neural-interface/public/shared/ui-detail.js +15 -3
- package/neural-interface/public/shared/ui-file-explorer.js +48 -6
- package/neural-interface/public/shared/ui-file-links.js +2 -2
- package/neural-interface/public/shared/ui-games.js +2 -2
- package/neural-interface/public/shared/ui-image-gallery.js +50 -47
- package/neural-interface/public/shared/ui-judgments.js +1 -1
- package/neural-interface/public/shared/ui-keybinds.js +33 -2
- package/neural-interface/public/shared/ui-link.js +3 -3
- package/neural-interface/public/shared/ui-menubar.js +10 -20
- package/neural-interface/public/shared/ui-native-loop-router-state.js +5 -0
- package/neural-interface/public/shared/ui-native-loop-router.js +11 -1
- package/neural-interface/public/shared/ui-navbar.js +49 -24
- package/neural-interface/public/shared/ui-notifications.js +1 -0
- package/neural-interface/public/shared/ui-panels.js +96 -65
- package/neural-interface/public/shared/ui-resume.js +9 -7
- package/neural-interface/public/shared/ui-schedules-studio.js +546 -431
- package/neural-interface/public/shared/ui-scroll-follow.js +16 -5
- package/neural-interface/public/shared/ui-sessions.js +27 -15
- package/neural-interface/public/shared/ui-settings.js +683 -526
- package/neural-interface/public/shared/ui-sidepanel-session-entry.js +9 -2
- package/neural-interface/public/shared/ui-sidepanel-sessions.js +4 -4
- package/neural-interface/public/shared/ui-sidepanel-state.js +23 -12
- package/neural-interface/public/shared/ui-sidepanel-tray.js +48 -7
- package/neural-interface/public/shared/ui-sidepanel-windows.js +18 -13
- package/neural-interface/public/shared/ui-skills.js +33 -2830
- package/neural-interface/public/shared/ui-styleguide.js +5 -2
- package/neural-interface/public/shared/ui-sync.js +15 -5
- package/neural-interface/public/shared/ui-terminal.js +270 -190
- package/neural-interface/public/shared/ui-tool-updates.js +6 -4
- package/neural-interface/public/shared/ui-tooltip.js +81 -51
- package/neural-interface/public/shared/ui-topright-overflow.js +233 -0
- package/neural-interface/public/shared/ui-trash.js +6 -4
- package/neural-interface/public/shared/ui-tutorial-layout.js +3 -117
- package/neural-interface/public/shared/ui-tutorial-preview.js +103 -0
- package/neural-interface/public/shared/ui-tutorial-steps.js +3 -65
- package/neural-interface/public/shared/ui-tutorial.css +47 -100
- package/neural-interface/public/shared/ui-tutorial.js +285 -509
- package/neural-interface/public/shared/ui-update.js +38 -2
- package/neural-interface/public/shared/ui-whiteboard.js +312 -59
- package/neural-interface/public/shared/ui-worker-end.js +5 -1
- package/neural-interface/public/shared/ui-workspaces.js +3 -2
- package/neural-interface/public/shared/view-variant.js +66 -0
- package/neural-interface/public/shared/whatsapp/wa-view.js +3 -3
- package/neural-interface/public/shared/whiteboard-list.js +172 -0
- package/neural-interface/public/shared/worker-end.js +10 -3
- package/neural-interface/public/shared/worker-questions.js +34 -0
- package/neural-interface/public/shared/worker-restart.js +12 -0
- package/neural-interface/public/sidepanel-session.html +2 -2
- package/neural-interface/public/variant/2d/background.js +2 -1
- package/neural-interface/public/variant/2d/context-menu.js +8 -2
- package/neural-interface/public/variant/2d/graph.js +42 -20
- package/neural-interface/public/variant/2d/hulls.js +14 -9
- package/neural-interface/public/variant/2d/lasso.js +11 -7
- package/neural-interface/public/variant/2d/main.js +32 -1
- package/neural-interface/public/variant/2d/minimap.js +11 -13
- package/neural-interface/public/variant/3d/main.js +69 -6
- package/neural-interface/public/variant/3d/map-controls.js +24 -9
- package/neural-interface/public/vendor/caveat/OFL.txt +93 -0
- package/neural-interface/public/vendor/caveat/caveat-latin-400-normal.woff2 +0 -0
- package/neural-interface/public/vendor/caveat/caveat-latin-700-normal.woff2 +0 -0
- package/neural-interface/public/vendor/caveat/caveat.css +17 -0
- package/neural-interface/public/vendor/caveat/manifest.json +12 -0
- package/neural-interface/public/vendor/yaml/LICENSE +13 -0
- package/neural-interface/public/vendor/yaml/manifest.json +4 -0
- package/neural-interface/public/vendor/yaml/yaml-2.9.1.min.js +137 -0
- package/neural-interface/scripts/build-vendor.mjs +32 -0
- package/neural-interface/server.js +4553 -2855
- package/neural-interface/templates/rulesets/README.md +1 -1
- package/neural-interface/templates/rulesets/core.md +1 -1
- package/neural-interface/templates/rulesets/legacy-hashes.json +23 -5
- package/neural-interface/templates/rulesets/manifest.json +8 -8
- package/npm-shrinkwrap.json +34 -12
- package/package.json +17 -3
- package/postinstall.js +9 -4
- package/preuninstall.js +1 -1
- package/setup.js +97 -322
- package/skills/skill-forge/SKILL.md +177 -0
- package/skills/skill-forge/evals/evals.json +54 -0
- package/skills/skill-forge/references/package.md +105 -0
- package/skills/skill-forge/references/review-and-recovery.md +63 -0
- package/skills/skill-forge/references/runtime-profiles.md +20 -0
- package/skills/skill-forge/references/sources-and-capabilities.md +51 -0
- package/skills/synabun/SKILL.md +10 -7
- package/skills/synabun/modules/audit.md +1 -5
- package/skills/synabun/modules/changelog.md +1 -5
- package/skills/synabun/modules/idea.md +1 -1
- package/skills/synabun/modules/memorize.md +6 -9
- package/skills/synabun/modules/schedule.md +6 -6
- package/mcp-server/dist/services/profiles.d.ts +0 -120
- package/mcp-server/dist/services/profiles.d.ts.map +0 -1
- package/mcp-server/dist/services/profiles.js +0 -387
- package/mcp-server/dist/services/profiles.js.map +0 -1
- package/mcp-server/dist/tools/leonardo-browser-tools.d.ts +0 -97
- package/mcp-server/dist/tools/leonardo-browser-tools.d.ts.map +0 -1
- package/mcp-server/dist/tools/leonardo-browser-tools.js +0 -228
- package/mcp-server/dist/tools/leonardo-browser-tools.js.map +0 -1
- package/mcp-server/dist/tools/leonardo.d.ts +0 -13
- package/mcp-server/dist/tools/leonardo.d.ts.map +0 -1
- package/mcp-server/dist/tools/leonardo.js +0 -21
- package/mcp-server/dist/tools/leonardo.js.map +0 -1
- package/mcp-server/dist/tools/profile.d.ts +0 -17
- package/mcp-server/dist/tools/profile.d.ts.map +0 -1
- package/mcp-server/dist/tools/profile.js +0 -114
- package/mcp-server/dist/tools/profile.js.map +0 -1
- package/mcp-server/src/services/profiles.ts +0 -428
- package/mcp-server/src/tools/leonardo-browser-tools.ts +0 -291
- package/mcp-server/src/tools/leonardo.ts +0 -30
- package/mcp-server/src/tools/profile.ts +0 -122
- package/neural-interface/lib/assistant-brains/opencode-browser-policy.js +0 -47
- package/neural-interface/lib/assistant-brains/opencode-route-gate.js +0 -62
- package/neural-interface/lib/mcp-profile-servers.js +0 -120
- package/neural-interface/public/shared/ui-tutorial-draw.js +0 -311
- package/skills/leonardo/SKILL.md +0 -168
- package/skills/leonardo/icon.svg +0 -1
- package/skills/leonardo/modules/browser-guide.md +0 -378
- package/skills/leonardo/modules/image-prompter.md +0 -283
- package/skills/leonardo/modules/model-advisor.md +0 -100
- package/skills/leonardo/modules/prompt-library.md +0 -110
- package/skills/leonardo/modules/style-guide.md +0 -186
- package/skills/leonardo/modules/video-prompter.md +0 -317
- /package/neural-interface/templates/rulesets/{gemini.md → antigravity.md} +0 -0
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// ═══════════════════════════════════════════
|
|
3
|
+
// SynaBun — the PreToolUse hook of a SynaBun Antigravity home (lib/antigravity/home.js)
|
|
4
|
+
// ═══════════════════════════════════════════
|
|
5
|
+
//
|
|
6
|
+
// Antigravity runs this before every tool call of a brain or run SynaBun started, with the call on
|
|
7
|
+
// stdin ({ toolCall: { name, args }, conversationId, workspacePaths, … }) and the agent's own
|
|
8
|
+
// environment, which carries where SynaBun listens (SYNABUN_AGY_POLICY_URL, a loopback address) and
|
|
9
|
+
// the home's token (SYNABUN_AGY_POLICY_TOKEN). It prints SynaBun's answer ({ decision, reason? }).
|
|
10
|
+
// Whatever goes wrong (no token, SynaBun not answering, a bad answer) the call is refused with the
|
|
11
|
+
// reason: a SynaBun home never runs a tool nobody checked. No imports of SynaBun's own: it starts
|
|
12
|
+
// for every call, so it stays small.
|
|
13
|
+
|
|
14
|
+
const MAX_INPUT = 4 * 1024 * 1024;
|
|
15
|
+
const TIMEOUT_MS = 15_000;
|
|
16
|
+
|
|
17
|
+
function answer(value) {
|
|
18
|
+
process.stdout.write(JSON.stringify(value));
|
|
19
|
+
}
|
|
20
|
+
function refuse(reason) {
|
|
21
|
+
answer({ decision: 'deny', reason: `SynaBun policy: ${reason}` });
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async function readStdin() {
|
|
25
|
+
let size = 0;
|
|
26
|
+
const chunks = [];
|
|
27
|
+
let truncated = false;
|
|
28
|
+
for await (const chunk of process.stdin) {
|
|
29
|
+
size += chunk.length;
|
|
30
|
+
if (size > MAX_INPUT) { truncated = true; continue; }
|
|
31
|
+
chunks.push(chunk);
|
|
32
|
+
}
|
|
33
|
+
return { text: Buffer.concat(chunks).toString('utf8'), truncated };
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function loopbackUrl(raw) {
|
|
37
|
+
try {
|
|
38
|
+
const url = new URL(String(raw || ''));
|
|
39
|
+
if (url.protocol !== 'http:') return null;
|
|
40
|
+
const host = url.hostname.replace(/^\[|\]$/g, '');
|
|
41
|
+
return host === '127.0.0.1' || host === 'localhost' || host === '::1' ? url : null;
|
|
42
|
+
} catch { return null; }
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async function main() {
|
|
46
|
+
const url = loopbackUrl(process.env.SYNABUN_AGY_POLICY_URL);
|
|
47
|
+
const token = String(process.env.SYNABUN_AGY_POLICY_TOKEN || '');
|
|
48
|
+
if (!url || !token) { refuse('this Antigravity session is missing its SynaBun policy settings, so no tool runs. End the turn and report it.'); return; }
|
|
49
|
+
const input = await readStdin();
|
|
50
|
+
if (input.truncated) { refuse('the tool-call input exceeded the size limit, so it is refused.'); return; }
|
|
51
|
+
let payload;
|
|
52
|
+
try { payload = JSON.parse(input.text); } catch { refuse('the tool-call input is not valid JSON, so it is refused.'); return; }
|
|
53
|
+
const toolCall = payload?.toolCall;
|
|
54
|
+
if (!toolCall || typeof toolCall !== 'object' || Array.isArray(toolCall) || typeof toolCall.name !== 'string' || !toolCall.name.trim()) {
|
|
55
|
+
refuse('the input has no valid tool call, so it is refused.'); return;
|
|
56
|
+
}
|
|
57
|
+
const controller = new AbortController();
|
|
58
|
+
const timer = setTimeout(() => controller.abort(), TIMEOUT_MS);
|
|
59
|
+
try {
|
|
60
|
+
const res = await fetch(url, {
|
|
61
|
+
method: 'POST',
|
|
62
|
+
// An agent's own call says who it is (lib/owner-authority.js isAgentCall): its pin, never a secret.
|
|
63
|
+
headers: { 'Content-Type': 'application/json', 'X-Synabun-Terminal': String(process.env.SYNABUN_TERMINAL_SESSION || 'antigravity').slice(0, 200) },
|
|
64
|
+
body: JSON.stringify({ token, payload: { toolCall: payload?.toolCall || null, conversationId: payload?.conversationId || null, stepIdx: payload?.stepIdx ?? null } }),
|
|
65
|
+
signal: controller.signal,
|
|
66
|
+
});
|
|
67
|
+
const body = await res.json().catch(() => null);
|
|
68
|
+
if (!res.ok || !body || typeof body.decision !== 'string') { refuse(`SynaBun did not answer for this call (HTTP ${res.status}), so it is refused.`); return; }
|
|
69
|
+
if (body.decision === 'deny') { answer({ decision: 'deny', reason: String(body.reason || 'SynaBun refused this call.') }); return; }
|
|
70
|
+
answer(body.decision === 'allow' ? { decision: 'allow' } : { decision: 'ask' });
|
|
71
|
+
} catch (error) {
|
|
72
|
+
refuse(`SynaBun could not be reached to check this call (${error?.name === 'AbortError' ? 'timed out' : String(error?.message || error).slice(0, 120)}), so it is refused.`);
|
|
73
|
+
} finally {
|
|
74
|
+
clearTimeout(timer);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
main().catch((error) => refuse(`the check failed (${String(error?.message || error).slice(0, 120)}).`));
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
// ═══════════════════════════════════════════
|
|
2
|
+
// SynaBun — Antigravity tool policy: what the PreToolUse hook of a SynaBun home asks
|
|
3
|
+
// ═══════════════════════════════════════════
|
|
4
|
+
//
|
|
5
|
+
// Every Antigravity brain and run SynaBun starts has a hook (lib/antigravity/policy-hook.mjs) that
|
|
6
|
+
// Antigravity runs before each tool call. The hook sends the call to this process
|
|
7
|
+
// (POST /api/antigravity/policy, loopback only) with its home's token; the token names the brain or
|
|
8
|
+
// run that registered a checker here, and the checker answers:
|
|
9
|
+
// { decision: 'deny', reason } refused: the model reads the reason ("tool call denied by pre-tool
|
|
10
|
+
// hook: …") and its turn goes on
|
|
11
|
+
// { decision: 'ask' } allowed by policy, approval by the usual permission request
|
|
12
|
+
// (session/request_permission: the brain's card, the run's broker)
|
|
13
|
+
// { decision: 'allow' } allowed by policy, no approval needed
|
|
14
|
+
// A token nobody registered (a run that ended, a restarted server) is refused: a home is never used
|
|
15
|
+
// without the process that wrote it watching. A checker that throws refuses too (fail closed).
|
|
16
|
+
|
|
17
|
+
import { randomBytes, timingSafeEqual } from 'node:crypto';
|
|
18
|
+
import { acpCall } from './tool-call.js';
|
|
19
|
+
|
|
20
|
+
export const POLICY_TOKEN_RE = /^agp_[A-Za-z0-9_-]{32,64}$/;
|
|
21
|
+
const DECISIONS = new Set(['deny', 'ask', 'allow']);
|
|
22
|
+
const MAX_REASON = 2000;
|
|
23
|
+
|
|
24
|
+
function sameToken(a, b) {
|
|
25
|
+
const x = Buffer.from(String(a || ''));
|
|
26
|
+
const y = Buffer.from(String(b || ''));
|
|
27
|
+
return x.length === y.length && timingSafeEqual(x, y);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** A checker's answer as the hook prints it ({ decision, reason? }); anything else is a refusal. */
|
|
31
|
+
export function normalizePolicyAnswer(answer) {
|
|
32
|
+
const decision = DECISIONS.has(answer?.decision) ? answer.decision : 'deny';
|
|
33
|
+
if (decision !== 'deny') return { decision };
|
|
34
|
+
const reason = String(answer?.reason || 'SynaBun refused this call.').replace(/\s+/g, ' ').trim().slice(0, MAX_REASON);
|
|
35
|
+
return { decision, reason };
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function createAntigravityPolicyRegistry({ log = () => {} } = {}) {
|
|
39
|
+
const entries = new Map(); // token → { check, label }
|
|
40
|
+
|
|
41
|
+
/** Register a checker ((call, payload) → answer | Promise<answer>) → { token, dispose() }. */
|
|
42
|
+
function register(check, { label = 'antigravity' } = {}) {
|
|
43
|
+
if (typeof check !== 'function') throw new Error('An Antigravity policy needs a checker');
|
|
44
|
+
const token = `agp_${randomBytes(32).toString('base64url')}`;
|
|
45
|
+
entries.set(token, { check, label });
|
|
46
|
+
return { token, dispose: () => { entries.delete(token); } };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** The answer for one hook payload ({ toolCall: { name, args }, conversationId, … }) under `token`. */
|
|
50
|
+
async function decide(token, payload = {}) {
|
|
51
|
+
const raw = String(token || '');
|
|
52
|
+
let entry = null;
|
|
53
|
+
if (POLICY_TOKEN_RE.test(raw)) {
|
|
54
|
+
for (const [known, value] of entries) if (sameToken(known, raw)) { entry = value; break; }
|
|
55
|
+
}
|
|
56
|
+
if (!entry) return { decision: 'deny', reason: 'SynaBun no longer runs this Antigravity session (its run ended or the server restarted), so nothing it does is allowed. End the turn.' };
|
|
57
|
+
const toolCall = payload?.toolCall;
|
|
58
|
+
if (!toolCall || typeof toolCall !== 'object' || Array.isArray(toolCall) || typeof toolCall.name !== 'string' || !toolCall.name.trim()) {
|
|
59
|
+
return { decision: 'deny', reason: 'SynaBun received no valid tool call, so it is refused.' };
|
|
60
|
+
}
|
|
61
|
+
try {
|
|
62
|
+
const call = acpCall(payload);
|
|
63
|
+
return normalizePolicyAnswer(await entry.check(call, payload));
|
|
64
|
+
} catch (error) {
|
|
65
|
+
log(`antigravity policy ${entry.label}: ${error?.message || error}`);
|
|
66
|
+
return { decision: 'deny', reason: `SynaBun could not check this call (${String(error?.message || error).slice(0, 200)}), so it is refused.` };
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return { register, decide, get size() { return entries.size; } };
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** The one registry of this process (server.js mounts its route; brains and runs register here). */
|
|
74
|
+
export const defaultAntigravityPolicy = createAntigravityPolicyRegistry();
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
// ═══════════════════════════════════════════
|
|
2
|
+
// SynaBun — what an Antigravity tool call is, read one way everywhere
|
|
3
|
+
// ═══════════════════════════════════════════
|
|
4
|
+
//
|
|
5
|
+
// Antigravity describes a tool call in two shapes: an ACP tool call (session/update tool_call,
|
|
6
|
+
// session/request_permission: { toolCallId, name, kind, title, locations, rawInput }) and the
|
|
7
|
+
// payload of a PreToolUse hook ({ toolCall: { name, args } }, no kind). Both name the tool by
|
|
8
|
+
// Antigravity's own word (read_file, run_command, write_to_file, call_mcp_tool …); an MCP call
|
|
9
|
+
// names its server and tool in its arguments ({ ServerName, ToolName, Arguments }), a command
|
|
10
|
+
// its line in CommandLine. Measured on agy 1.4.12 (docs/antigravity-sidepanel.md → Assistant).
|
|
11
|
+
//
|
|
12
|
+
// acpCall(value) either shape → { id, name, kind, title, args, locations, mcp, command }
|
|
13
|
+
// acpToolName(call) the name SynaBun's policies read: mcp__<server>__<tool> for an MCP call
|
|
14
|
+
// acpUiToolName(call) the name the Assistant panel shows: <server>_<tool> (SynaBun_agent_route) for MCP
|
|
15
|
+
// acpToolKind(call) ACP kind, from the call or from the tool's name when the hook payload has none
|
|
16
|
+
// acpWebTool(call) Antigravity's own web search, URL reading or browser (the browser policy refuses it)
|
|
17
|
+
// acpToolPaths(call) every path the call names
|
|
18
|
+
//
|
|
19
|
+
// Pure: no I/O.
|
|
20
|
+
|
|
21
|
+
export const ACP_MCP_TOOL = 'call_mcp_tool';
|
|
22
|
+
|
|
23
|
+
// Antigravity's own tools, by what they do (the names its agent and its hooks use).
|
|
24
|
+
const READ_TOOLS = new Set([
|
|
25
|
+
'read_file', 'view_file', 'view_file_outline', 'view_code_item', 'view_content_chunk', 'list_dir', 'list_directory',
|
|
26
|
+
'grep_search', 'find_by_name', 'find', 'codebase_search', 'code_search', 'read_resource', 'list_resources',
|
|
27
|
+
'read_terminal', 'command_status', 'read_notebook', 'trajectory_search', 'internal_search', 'retrieve_memory',
|
|
28
|
+
'find_all_references',
|
|
29
|
+
]);
|
|
30
|
+
const EDIT_TOOLS = new Set([
|
|
31
|
+
'write_to_file', 'write_file', 'create_file', 'replace_file_content', 'multi_replace_file_content', 'edit_file',
|
|
32
|
+
'apply_patch', 'propose_code', 'file_change', 'edit_notebook', 'write_blob',
|
|
33
|
+
]);
|
|
34
|
+
const DELETE_TOOLS = new Set(['delete_file', 'delete_directory']);
|
|
35
|
+
const MOVE_TOOLS = new Set(['move_file', 'move', 'rename_file']);
|
|
36
|
+
const EXECUTE_TOOLS = new Set(['run_command', 'shell_exec', 'send_command_input', 'execute_notebook', 'run_extension_code']);
|
|
37
|
+
// Antigravity's own web: search, URL reading, its browser and browser subagent.
|
|
38
|
+
const WEB_TOOLS = new Set([
|
|
39
|
+
'search_web', 'read_url_content', 'execute_url', 'open_browser_url', 'read_browser_page', 'browser_subagent', 'list_browser_pages',
|
|
40
|
+
'capture_browser_screenshot', 'capture_browser_console_logs', 'execute_browser_javascript', 'click_browser_pixel',
|
|
41
|
+
]);
|
|
42
|
+
const THINK_TOOLS = new Set(['task_boundary', 'notify_user', 'ask_question', 'suggested_responses', 'checkpoint']);
|
|
43
|
+
|
|
44
|
+
const PATH_KEYS = ['path', 'Path', 'file_path', 'filePath', 'filepath', 'AbsolutePath', 'TargetFile', 'DirectoryPath', 'SearchPath', 'SearchDirectory', 'target', 'dest', 'destination', 'Destination', 'newPath', 'new_path', 'source', 'Source', 'from', 'to', 'oldPath', 'old_path'];
|
|
45
|
+
const COMMAND_KEYS = ['CommandLine', 'command', 'cmd'];
|
|
46
|
+
|
|
47
|
+
const asObject = (value) => (value && typeof value === 'object' && !Array.isArray(value) ? value : {});
|
|
48
|
+
const text = (value) => (typeof value === 'string' ? value : '');
|
|
49
|
+
|
|
50
|
+
/** The MCP server, tool and arguments of an Antigravity MCP call, else null. */
|
|
51
|
+
export function acpMcpTarget(nameOrCall, rawArgs) {
|
|
52
|
+
const name = typeof nameOrCall === 'string' ? nameOrCall : text(nameOrCall?.name);
|
|
53
|
+
const args = asObject(typeof nameOrCall === 'string' ? rawArgs : (nameOrCall?.rawInput ?? nameOrCall?.args));
|
|
54
|
+
const server = text(args.ServerName || args.serverName || args.server).trim();
|
|
55
|
+
const tool = text(args.ToolName || args.toolName || args.tool).trim();
|
|
56
|
+
if (name !== ACP_MCP_TOOL && !(server && tool && /mcp/i.test(name || text(nameOrCall?.title)))) return null;
|
|
57
|
+
if (!server || !tool) return null;
|
|
58
|
+
let inner = args.Arguments ?? args.arguments ?? {};
|
|
59
|
+
if (typeof inner === 'string') inner = JSON.parse(inner);
|
|
60
|
+
if (!inner || typeof inner !== 'object' || Array.isArray(inner)) throw new Error('MCP arguments must be an object');
|
|
61
|
+
return { server, tool, args: inner };
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Either shape as one: { id, name, kind, title, args, locations, mcp, command }. `name` is Antigravity's own
|
|
66
|
+
* word for the tool ('' when the call names none: an older agy, a stand-in), `kind` the ACP kind (from the
|
|
67
|
+
* name when the shape has none), `mcp` the MCP target ({ server, tool, args }) or null.
|
|
68
|
+
*/
|
|
69
|
+
export function acpCall(value) {
|
|
70
|
+
const source = asObject(value);
|
|
71
|
+
const inner = source.toolCall && typeof source.toolCall === 'object' ? source.toolCall : source;
|
|
72
|
+
const args = asObject(inner.rawInput ?? inner.args ?? inner.input);
|
|
73
|
+
const name = text(inner.name).trim();
|
|
74
|
+
const mcp = acpMcpTarget(name || text(inner.title), args) || (name ? null : acpMcpTarget({ name: ACP_MCP_TOOL, rawInput: args }));
|
|
75
|
+
const call = {
|
|
76
|
+
id: text(inner.toolCallId) || null,
|
|
77
|
+
name,
|
|
78
|
+
kind: '',
|
|
79
|
+
title: text(inner.title),
|
|
80
|
+
args,
|
|
81
|
+
locations: Array.isArray(inner.locations) ? inner.locations : [],
|
|
82
|
+
mcp,
|
|
83
|
+
command: '',
|
|
84
|
+
};
|
|
85
|
+
call.kind = acpToolKind({ ...call, kind: text(inner.kind) });
|
|
86
|
+
for (const key of COMMAND_KEYS) {
|
|
87
|
+
const v = args[key];
|
|
88
|
+
if (typeof v === 'string' && v.trim()) { call.command = v; break; }
|
|
89
|
+
if (Array.isArray(v) && v.length) { call.command = v.map(String).join(' '); break; }
|
|
90
|
+
}
|
|
91
|
+
return call;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** The ACP kind of a call: its own when it has one (and it is not an MCP call), else read from its name. */
|
|
95
|
+
export function acpToolKind(call) {
|
|
96
|
+
const named = text(call?.name).toLowerCase();
|
|
97
|
+
if (call?.mcp || named === ACP_MCP_TOOL) return 'mcp';
|
|
98
|
+
const own = text(call?.kind).toLowerCase();
|
|
99
|
+
if (own && own !== 'other') return own;
|
|
100
|
+
if (READ_TOOLS.has(named)) return named.includes('search') || named.startsWith('find') ? 'search' : 'read';
|
|
101
|
+
if (EDIT_TOOLS.has(named)) return 'edit';
|
|
102
|
+
if (DELETE_TOOLS.has(named)) return 'delete';
|
|
103
|
+
if (MOVE_TOOLS.has(named)) return 'move';
|
|
104
|
+
if (EXECUTE_TOOLS.has(named)) return 'execute';
|
|
105
|
+
if (WEB_TOOLS.has(named) || /^browser_/.test(named)) return 'fetch';
|
|
106
|
+
if (THINK_TOOLS.has(named)) return 'think';
|
|
107
|
+
return own || 'other';
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** The name SynaBun's policies read: mcp__<server>__<tool> for an MCP call (the Claude spelling), else Antigravity's word. */
|
|
111
|
+
export function acpToolName(value) {
|
|
112
|
+
const call = value?.args && 'mcp' in value ? value : acpCall(value);
|
|
113
|
+
if (call.mcp) return `mcp__${call.mcp.server}__${call.mcp.tool}`;
|
|
114
|
+
return call.name || call.title || call.kind || 'tool';
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/** The name the Assistant panel shows: <server>_<tool> for an MCP call (SynaBun_agent_route, as OpenCode's), else Antigravity's word. */
|
|
118
|
+
export function acpUiToolName(value) {
|
|
119
|
+
const call = value?.args && 'mcp' in value ? value : acpCall(value);
|
|
120
|
+
if (call.mcp) return `${call.mcp.server}_${call.mcp.tool}`;
|
|
121
|
+
return call.name || call.kind || 'tool';
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/** Whether this is Antigravity's own web search, URL reading or browser (never SynaBun's browser tools). */
|
|
125
|
+
export function acpWebTool(value) {
|
|
126
|
+
const call = value?.args && 'mcp' in value ? value : acpCall(value);
|
|
127
|
+
if (call.mcp) return false;
|
|
128
|
+
const named = call.name.toLowerCase();
|
|
129
|
+
return WEB_TOOLS.has(named) || /^browser_/.test(named) || (!named && call.kind === 'fetch');
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/** Every path the call names, including nested path-like values in an MCP call's arguments. */
|
|
133
|
+
export function acpToolPaths(value) {
|
|
134
|
+
const call = value?.args && 'mcp' in value ? value : acpCall(value);
|
|
135
|
+
const out = [];
|
|
136
|
+
for (const location of call.locations) if (typeof location?.path === 'string' && location.path) out.push(location.path);
|
|
137
|
+
if (call.mcp) {
|
|
138
|
+
let nodes = 0;
|
|
139
|
+
const visit = (value, key = '', depth = 0) => {
|
|
140
|
+
if (++nodes > 10000 || depth > 32) throw new Error('MCP arguments exceed the path inspection limit');
|
|
141
|
+
if (typeof value === 'string') {
|
|
142
|
+
if (PATH_KEYS.includes(key) || /[\\/]|^(?:[~.]|\$\{?HOME\}?)/.test(value.trim())) out.push(value.trim());
|
|
143
|
+
} else if (Array.isArray(value)) {
|
|
144
|
+
for (const item of value) visit(item, key, depth + 1);
|
|
145
|
+
} else if (value && typeof value === 'object') {
|
|
146
|
+
for (const [childKey, child] of Object.entries(value)) visit(child, childKey, depth + 1);
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
visit(call.mcp.args);
|
|
150
|
+
} else {
|
|
151
|
+
for (const key of PATH_KEYS) {
|
|
152
|
+
const v = call.args[key];
|
|
153
|
+
if (typeof v === 'string' && v) out.push(v);
|
|
154
|
+
else if (Array.isArray(v)) for (const item of v) if (typeof item === 'string' && item) out.push(item);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return [...new Set(out)];
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/** Whether a call only reads (Antigravity's read and search tools), for plan mode and the read-only level. */
|
|
161
|
+
export function acpReadOnlyKind(kind) {
|
|
162
|
+
return kind === 'read' || kind === 'search' || kind === 'think';
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* The call as the arguments a host-agnostic policy reads: an MCP call's own arguments, a command as `command`
|
|
167
|
+
* (and its working folder as `cwd`), paths as `file_path`; the rest as Antigravity sent them.
|
|
168
|
+
*/
|
|
169
|
+
export function acpPolicyInput(value) {
|
|
170
|
+
const call = value?.args && 'mcp' in value ? value : acpCall(value);
|
|
171
|
+
if (call.mcp) return { ...call.mcp.args };
|
|
172
|
+
const out = { ...call.args };
|
|
173
|
+
if (call.command && typeof out.command !== 'string') out.command = call.command;
|
|
174
|
+
if (typeof call.args.Cwd === 'string' && call.args.Cwd && typeof out.cwd !== 'string') out.cwd = call.args.Cwd;
|
|
175
|
+
const paths = acpToolPaths(call);
|
|
176
|
+
if (paths.length && typeof out.file_path !== 'string') out.file_path = paths[0];
|
|
177
|
+
return out;
|
|
178
|
+
}
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
// ═══════════════════════════════════════════
|
|
2
|
+
// SynaBun — Antigravity's conversations, read where agy keeps them (never written)
|
|
3
|
+
// ═══════════════════════════════════════════
|
|
4
|
+
//
|
|
5
|
+
// agy (1.4.x) keeps each conversation under <gemini dir>/antigravity-cli/:
|
|
6
|
+
// brain/<conversation id>/.system_generated/logs/transcript.jsonl
|
|
7
|
+
// one JSON line per step, appended as the steps happen: { step_index, source, type, status, created_at,
|
|
8
|
+
// content, thinking?, tool_calls?, input_tokens?, output_tokens? }. A person's message is USER_EXPLICIT /
|
|
9
|
+
// USER_INPUT, its words inside <USER_REQUEST> (agy adds <ADDITIONAL_METADATA> and <USER_SETTINGS_CHANGE>
|
|
10
|
+
// blocks around them); the model's answer is MODEL / PLANNER_RESPONSE (`content`; `thinking` is its
|
|
11
|
+
// reasoning and is never read; `tool_calls` [{ name, args }]); a tool's output is MODEL / GENERIC; SYSTEM /
|
|
12
|
+
// SYSTEM_MESSAGE is agy's own.
|
|
13
|
+
// conversation_summaries.db
|
|
14
|
+
// SQLite, one row per conversation: its title, its folders (`workspace_uris`, a JSON list of file: URIs, the
|
|
15
|
+
// first being where it runs), when it changed, and its parent when it is a subagent's.
|
|
16
|
+
// conversations/<id>.db the steps again, as protobuf (no schema: never read).
|
|
17
|
+
// Measured on agy 1.4.12 (docs/antigravity-sidepanel.md → Conversations in SynaBun).
|
|
18
|
+
//
|
|
19
|
+
// The index is opened read-only with SQLite's immutable flag: nothing is created beside it (no -wal or -shm), and a
|
|
20
|
+
// change agy has not checkpointed yet is simply not seen until it has. A conversation the index does not name yet
|
|
21
|
+
// has no folder: memory keeps it without a project, and Resume shows it once the index names it.
|
|
22
|
+
//
|
|
23
|
+
// Where: the user's own gemini dir (~/.gemini: the side panel's and a terminal agy's; Resume lists these and the
|
|
24
|
+
// panel can load them again) and every SynaBun home (lib/antigravity/home.js: an Assistant brain's or a dispatched
|
|
25
|
+
// run's; kept for memory only, since only the gemini dir that holds a conversation can load it). A folder or a
|
|
26
|
+
// transcript that is a link is never followed, and a transcript is read only up to MAX_TRANSCRIPT_BYTES.
|
|
27
|
+
|
|
28
|
+
import { closeSync, fstatSync, lstatSync, openSync, readdirSync, readSync } from 'node:fs';
|
|
29
|
+
import { homedir } from 'node:os';
|
|
30
|
+
import { join } from 'node:path';
|
|
31
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
32
|
+
import { DatabaseSync } from 'node:sqlite';
|
|
33
|
+
import { stripGreetingNote } from '../../public/shared/agy/agy-greeting.js';
|
|
34
|
+
|
|
35
|
+
/** agy's own folder inside a gemini dir (`--gemini-dir <dir>` keeps it there too). */
|
|
36
|
+
export const AGY_DATA_DIR = 'antigravity-cli';
|
|
37
|
+
/** A transcript bigger than this is read up to here (its first steps; the rest is left out). */
|
|
38
|
+
export const MAX_TRANSCRIPT_BYTES = 50 * 1024 * 1024;
|
|
39
|
+
/** What a conversation id may look like (agy's are UUIDs); anything else in brain/ is not a conversation. */
|
|
40
|
+
export const CONVERSATION_ID_RE = /^[A-Za-z0-9][A-Za-z0-9._-]{5,127}$/;
|
|
41
|
+
/** The SynaBun homes that hold conversations of their own (a model-list home holds none worth keeping). */
|
|
42
|
+
const HOME_RE = /^(?:brain|run)-[A-Za-z0-9_-]+$/;
|
|
43
|
+
|
|
44
|
+
/** The transcript of a conversation in a gemini dir. */
|
|
45
|
+
export function transcriptPath(geminiDir, sessionId) {
|
|
46
|
+
return join(geminiDir, AGY_DATA_DIR, 'brain', sessionId, '.system_generated', 'logs', 'transcript.jsonl');
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const isDir = (path) => { try { const stat = lstatSync(path); return stat.isDirectory() && !stat.isSymbolicLink(); } catch { return false; } };
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* The gemini dirs whose conversations SynaBun reads: the user's (`kind: 'user'`), then each SynaBun home under
|
|
53
|
+
* `homesRoot` (`kind: 'synabun'`). A missing folder is simply not there.
|
|
54
|
+
*/
|
|
55
|
+
export function antigravityStores({ home = homedir(), homesRoot = null } = {}) {
|
|
56
|
+
const stores = [];
|
|
57
|
+
const user = join(home, '.gemini');
|
|
58
|
+
if (isDir(join(user, AGY_DATA_DIR))) stores.push({ dir: user, kind: 'user' });
|
|
59
|
+
if (homesRoot && isDir(homesRoot)) {
|
|
60
|
+
let names = [];
|
|
61
|
+
try { names = readdirSync(homesRoot).sort(); } catch { names = []; }
|
|
62
|
+
for (const name of names) {
|
|
63
|
+
const dir = join(homesRoot, name);
|
|
64
|
+
// A home is SynaBun's own folder: one that is a link (to anywhere) is not one.
|
|
65
|
+
if (HOME_RE.test(name) && isDir(dir) && isDir(join(dir, AGY_DATA_DIR))) stores.push({ dir, kind: 'synabun' });
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return stores;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** A folder from a file: URI (agy's workspace_uris), or null. */
|
|
72
|
+
export function folderOfUri(uri) {
|
|
73
|
+
try {
|
|
74
|
+
const url = new URL(String(uri || ''));
|
|
75
|
+
if (url.protocol !== 'file:') return null;
|
|
76
|
+
const path = fileURLToPath(url);
|
|
77
|
+
return path || null;
|
|
78
|
+
} catch { return null; }
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** agy's time ("2026-10-31 07:08:50.511446+00:00", the zero time for none) as ISO, or null. */
|
|
82
|
+
export function indexTime(value) {
|
|
83
|
+
const text = String(value || '').trim();
|
|
84
|
+
if (!text || text.startsWith('0001-01-01')) return null;
|
|
85
|
+
const at = Date.parse(text.replace(' ', 'T').replace(/(\.\d{3})\d+/, '$1'));
|
|
86
|
+
return Number.isFinite(at) ? new Date(at).toISOString() : null;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* conversation_summaries.db of one agy folder, as `Map(id → { title, cwd, folders, updatedAt, parentId, steps })`.
|
|
91
|
+
* Empty when there is none or it cannot be read (a title and a folder are extras: the transcript is the record).
|
|
92
|
+
*/
|
|
93
|
+
export function readAntigravityIndex(dataDir, { Database = DatabaseSync } = {}) {
|
|
94
|
+
const index = new Map();
|
|
95
|
+
const file = join(dataDir, 'conversation_summaries.db');
|
|
96
|
+
try { const stat = lstatSync(file); if (!stat.isFile() || stat.isSymbolicLink()) return index; } catch { return index; }
|
|
97
|
+
let db = null;
|
|
98
|
+
try {
|
|
99
|
+
db = new Database(`${pathToFileURL(file).href}?immutable=1`, { readOnly: true });
|
|
100
|
+
const rows = db.prepare(`SELECT conversation_id, title, workspace_uris, last_modified_time, parent_conversation_id, step_count
|
|
101
|
+
FROM conversation_summaries`).all();
|
|
102
|
+
for (const row of rows) {
|
|
103
|
+
const id = String(row.conversation_id || '');
|
|
104
|
+
if (!CONVERSATION_ID_RE.test(id)) continue;
|
|
105
|
+
let uris = [];
|
|
106
|
+
try { const parsed = JSON.parse(String(row.workspace_uris || '[]')); if (Array.isArray(parsed)) uris = parsed; } catch { uris = []; }
|
|
107
|
+
const folders = uris.map(folderOfUri).filter(Boolean);
|
|
108
|
+
index.set(id, {
|
|
109
|
+
title: String(row.title || '').trim(),
|
|
110
|
+
cwd: folders[0] || null,
|
|
111
|
+
folders,
|
|
112
|
+
updatedAt: indexTime(row.last_modified_time),
|
|
113
|
+
parentId: String(row.parent_conversation_id || '') || null,
|
|
114
|
+
steps: Number(row.step_count) || 0,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
} catch { /* an index being written, an older layout: no extras */ }
|
|
118
|
+
finally { try { db?.close(); } catch { /* closed */ } }
|
|
119
|
+
return index;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Every conversation with a transcript in these stores: `{ sessionId, store, geminiDir, transcript, size, mtimeMs,
|
|
124
|
+
* title, cwd, folders, updatedAt, parentId }`. A subagent's conversation (one with a parent) is its parent's work
|
|
125
|
+
* and is left out, as Claude Code's sidechains are.
|
|
126
|
+
*/
|
|
127
|
+
export function listAntigravityConversations(stores, { readIndex = readAntigravityIndex } = {}) {
|
|
128
|
+
const out = [];
|
|
129
|
+
const seen = new Set();
|
|
130
|
+
for (const store of Array.isArray(stores) ? stores : []) {
|
|
131
|
+
const dataDir = join(store.dir, AGY_DATA_DIR);
|
|
132
|
+
const brain = join(dataDir, 'brain');
|
|
133
|
+
if (!isDir(brain)) continue;
|
|
134
|
+
let ids = [];
|
|
135
|
+
try { ids = readdirSync(brain).filter((name) => CONVERSATION_ID_RE.test(name)); } catch { ids = []; }
|
|
136
|
+
if (!ids.length) continue;
|
|
137
|
+
const index = readIndex(dataDir);
|
|
138
|
+
for (const id of ids) {
|
|
139
|
+
if (seen.has(id) || !isDir(join(brain, id))) continue;
|
|
140
|
+
const meta = index.get(id) || null;
|
|
141
|
+
if (meta?.parentId) continue;
|
|
142
|
+
const transcript = transcriptPath(store.dir, id);
|
|
143
|
+
let stat;
|
|
144
|
+
try { stat = lstatSync(transcript); } catch { continue; }
|
|
145
|
+
if (!stat.isFile() || stat.isSymbolicLink() || stat.size <= 0) continue;
|
|
146
|
+
seen.add(id);
|
|
147
|
+
out.push({
|
|
148
|
+
sessionId: id, store: store.kind, geminiDir: store.dir, transcript, size: stat.size, mtimeMs: stat.mtimeMs,
|
|
149
|
+
title: meta?.title || '', cwd: meta?.cwd || null, folders: meta?.folders || [], updatedAt: meta?.updatedAt || null, parentId: null,
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return out;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/** One conversation of the user's own store by id (the panel's and Resume's), or null. */
|
|
157
|
+
export function findUserConversation(sessionId, { home = homedir(), readIndex = readAntigravityIndex } = {}) {
|
|
158
|
+
if (!CONVERSATION_ID_RE.test(String(sessionId || ''))) return null;
|
|
159
|
+
const stores = antigravityStores({ home }).filter((store) => store.kind === 'user');
|
|
160
|
+
const dir = stores[0]?.dir;
|
|
161
|
+
if (!dir) return null;
|
|
162
|
+
const transcript = transcriptPath(dir, sessionId);
|
|
163
|
+
let stat;
|
|
164
|
+
try { stat = lstatSync(transcript); } catch { return null; }
|
|
165
|
+
if (!stat.isFile() || stat.isSymbolicLink() || !isDir(join(dir, AGY_DATA_DIR, 'brain', sessionId))) return null;
|
|
166
|
+
const meta = readIndex(join(dir, AGY_DATA_DIR)).get(sessionId) || null;
|
|
167
|
+
return { sessionId, store: 'user', geminiDir: dir, transcript, size: stat.size, mtimeMs: stat.mtimeMs, title: meta?.title || '', cwd: meta?.cwd || null, folders: meta?.folders || [], updatedAt: meta?.updatedAt || null, parentId: meta?.parentId || null };
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* A transcript's text, read without following a link and up to `maxBytes` (a cut line at the end is left out by
|
|
172
|
+
* the parser). '' when it cannot be read.
|
|
173
|
+
*/
|
|
174
|
+
export function readTranscriptText(path, { maxBytes = MAX_TRANSCRIPT_BYTES } = {}) {
|
|
175
|
+
let fd = null;
|
|
176
|
+
try {
|
|
177
|
+
const stat = lstatSync(path);
|
|
178
|
+
if (!stat.isFile() || stat.isSymbolicLink()) return '';
|
|
179
|
+
fd = openSync(path, 'r');
|
|
180
|
+
const size = Math.min(fstatSync(fd).size, maxBytes);
|
|
181
|
+
const buffer = Buffer.alloc(size);
|
|
182
|
+
let read = 0;
|
|
183
|
+
while (read < size) {
|
|
184
|
+
const n = readSync(fd, buffer, read, size - read, read);
|
|
185
|
+
if (!n) break;
|
|
186
|
+
read += n;
|
|
187
|
+
}
|
|
188
|
+
return buffer.subarray(0, read).toString('utf8');
|
|
189
|
+
} catch { return ''; }
|
|
190
|
+
finally { if (fd !== null) { try { closeSync(fd); } catch { /* closed */ } } }
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const META_BLOCKS = /<(ADDITIONAL_METADATA|USER_SETTINGS_CHANGE|EPHEMERAL_MESSAGE|SYSTEM_MESSAGE)>[\s\S]*?<\/\1>/g;
|
|
194
|
+
|
|
195
|
+
/** What a person typed, out of agy's USER_INPUT `content` (its own blocks and SynaBun's greeting note left out). */
|
|
196
|
+
export function antigravityUserWords(content) {
|
|
197
|
+
const text = String(content ?? '');
|
|
198
|
+
const request = /<USER_REQUEST>\r?\n?([\s\S]*?)\r?\n?<\/USER_REQUEST>/.exec(text);
|
|
199
|
+
const words = request ? request[1] : text.replace(META_BLOCKS, '');
|
|
200
|
+
return stripGreetingNote(words).trim();
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/** One transcript line as a message: { role: 'user' | 'assistant' | 'tool_result', text, at, step, tools } or null. */
|
|
204
|
+
export function antigravityStepMessage(record) {
|
|
205
|
+
if (!record || typeof record !== 'object') return null;
|
|
206
|
+
const at = typeof record.created_at === 'string' && Number.isFinite(Date.parse(record.created_at)) ? new Date(record.created_at).toISOString() : null;
|
|
207
|
+
const step = Number.isInteger(record.step_index) ? record.step_index : null;
|
|
208
|
+
if (record.type === 'USER_INPUT' && record.source === 'USER_EXPLICIT') {
|
|
209
|
+
const text = antigravityUserWords(record.content);
|
|
210
|
+
return text ? { role: 'user', text, at, step, tools: [] } : null;
|
|
211
|
+
}
|
|
212
|
+
if (record.type === 'PLANNER_RESPONSE' && record.source === 'MODEL') {
|
|
213
|
+
const tools = (Array.isArray(record.tool_calls) ? record.tool_calls : [])
|
|
214
|
+
.filter((call) => call && typeof call.name === 'string' && call.name)
|
|
215
|
+
.map((call) => ({ name: call.name, input: call.args ?? {} }));
|
|
216
|
+
const text = typeof record.content === 'string' ? record.content.trim() : '';
|
|
217
|
+
return text || tools.length ? { role: 'assistant', text, at, step, tools } : null;
|
|
218
|
+
}
|
|
219
|
+
if (record.type === 'GENERIC' && record.source === 'MODEL' && typeof record.content === 'string' && record.content.trim()) {
|
|
220
|
+
return { role: 'tool_result', text: record.content, at, step, tools: [], error: record.status === 'ERROR' };
|
|
221
|
+
}
|
|
222
|
+
return null;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* A transcript's text as the conversation: `{ records, messages, firstPrompt, messageCount, created, modified }`.
|
|
227
|
+
* `records` are the parsed lines (for memory capture); `messages` the person's and the model's turns and the tool
|
|
228
|
+
* output, in order; `messageCount` counts the person's and the model's messages that say something.
|
|
229
|
+
*/
|
|
230
|
+
export function parseAntigravityTranscript(text) {
|
|
231
|
+
const records = [];
|
|
232
|
+
const messages = [];
|
|
233
|
+
for (const line of String(text || '').split('\n')) {
|
|
234
|
+
if (!line.trim()) continue;
|
|
235
|
+
let record;
|
|
236
|
+
try { record = JSON.parse(line); } catch { continue; }
|
|
237
|
+
if (!record || typeof record !== 'object' || Array.isArray(record)) continue;
|
|
238
|
+
records.push(record);
|
|
239
|
+
const message = antigravityStepMessage(record);
|
|
240
|
+
if (message) messages.push(message);
|
|
241
|
+
}
|
|
242
|
+
const said = messages.filter((m) => (m.role === 'user' || m.role === 'assistant') && m.text);
|
|
243
|
+
const times = messages.map((m) => m.at).filter(Boolean).sort();
|
|
244
|
+
return {
|
|
245
|
+
records,
|
|
246
|
+
messages,
|
|
247
|
+
firstPrompt: said.find((m) => m.role === 'user')?.text.replace(/\s+/g, ' ').slice(0, 200) || '',
|
|
248
|
+
messageCount: said.length,
|
|
249
|
+
created: times[0] || null,
|
|
250
|
+
modified: times[times.length - 1] || null,
|
|
251
|
+
};
|
|
252
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// ═══════════════════════════════════════════
|
|
2
|
+
// SynaBun — Antigravity: one turn's tokens out of ACP's session totals
|
|
3
|
+
// ═══════════════════════════════════════════
|
|
4
|
+
//
|
|
5
|
+
// ACP's `usage` block on a session/prompt answer counts the whole session
|
|
6
|
+
// ("total input tokens across all turns"), so a turn's own tokens are the
|
|
7
|
+
// difference from the previous answer. A counter that went down means the
|
|
8
|
+
// agent started counting again (a new process, a reloaded session): that
|
|
9
|
+
// answer is a turn of its own. The five-class reading of a block is
|
|
10
|
+
// lib/assistant-usage.js antigravityUsageTokens.
|
|
11
|
+
|
|
12
|
+
const FIELDS = Object.freeze(['inputTokens', 'outputTokens', 'thoughtTokens', 'cachedReadTokens', 'cachedWriteTokens', 'totalTokens']);
|
|
13
|
+
const SNAKE = Object.freeze({ inputTokens: 'input_tokens', outputTokens: 'output_tokens', thoughtTokens: 'thought_tokens', cachedReadTokens: 'cached_read_tokens', cachedWriteTokens: 'cached_write_tokens', totalTokens: 'total_tokens' });
|
|
14
|
+
|
|
15
|
+
function count(value) {
|
|
16
|
+
const n = Number(value);
|
|
17
|
+
return Number.isFinite(n) && n > 0 ? Math.trunc(n) : 0;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** An ACP usage block in camelCase with every field a count (null when there is none). */
|
|
21
|
+
export function normalizeAcpUsage(usage) {
|
|
22
|
+
if (!usage || typeof usage !== 'object') return null;
|
|
23
|
+
const out = {};
|
|
24
|
+
let any = false;
|
|
25
|
+
for (const key of FIELDS) {
|
|
26
|
+
const value = usage[key] ?? usage[SNAKE[key]];
|
|
27
|
+
if (value !== undefined && value !== null) any = true;
|
|
28
|
+
out[key] = count(value);
|
|
29
|
+
}
|
|
30
|
+
return any ? out : null;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** The turn's own usage: `current` minus `previous` (both session totals), or `current` after a reset. */
|
|
34
|
+
export function acpTurnUsage(current, previous) {
|
|
35
|
+
const now = normalizeAcpUsage(current);
|
|
36
|
+
if (!now) return null;
|
|
37
|
+
const before = normalizeAcpUsage(previous);
|
|
38
|
+
if (!before) return now;
|
|
39
|
+
if (FIELDS.some((key) => now[key] < before[key])) return now;
|
|
40
|
+
const out = {};
|
|
41
|
+
for (const key of FIELDS) out[key] = now[key] - before[key];
|
|
42
|
+
return out;
|
|
43
|
+
}
|