synabun 1.3.0 → 2.0.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 +205 -662
- package/LICENSE-COMMERCIAL.md +33 -0
- package/NOTICE +17 -0
- package/README.md +175 -853
- package/THIRD-PARTY-LICENSES.md +136 -0
- package/benchmarks/browser-live-results.json +79 -0
- package/benchmarks/browser-v2-results.json +258 -0
- package/benchmarks/fixtures/browser/README.md +57 -0
- package/benchmarks/fixtures/browser/page-state.json +132 -0
- package/benchmarks/fixtures/browser/social.json +92 -0
- package/benchmarks/fixtures/browser/target.json +319 -0
- package/benchmarks/fixtures/desktop/README.md +58 -0
- package/benchmarks/fixtures/desktop/abstention.json +59 -0
- package/benchmarks/fixtures/desktop/adversarial.json +22 -0
- package/benchmarks/fixtures/desktop/forbidden.json +93 -0
- package/benchmarks/fixtures/desktop/generate.mjs +1023 -0
- package/benchmarks/fixtures/desktop/target.json +136 -0
- package/bin/synabun.js +30 -0
- package/docs/whatsapp.md +325 -0
- package/hooks/claude-code/post-plan.mjs +613 -391
- package/hooks/claude-code/post-remember.mjs +246 -122
- package/hooks/claude-code/pre-compact.mjs +171 -110
- package/hooks/claude-code/pre-task.mjs +133 -0
- package/hooks/claude-code/pre-websearch.mjs +15 -4
- package/hooks/claude-code/prompt-origin.mjs +94 -0
- package/hooks/claude-code/prompt-submit.mjs +1244 -861
- package/hooks/claude-code/session-start.mjs +114 -156
- package/hooks/claude-code/shared.mjs +1228 -368
- package/hooks/claude-code/state.mjs +167 -0
- package/hooks/claude-code/stop.mjs +515 -140
- package/hooks/claude-code/subagent-start.mjs +154 -0
- package/hooks/claude-code/subagent-stop.mjs +102 -0
- package/hooks/claude-code/task-gate.mjs +150 -0
- package/launcher.mjs +40 -0
- package/lib/claude-hooks.js +137 -0
- package/lib/claude-usage-audit.js +141 -0
- package/lib/client-config-repair.js +145 -0
- package/lib/data-home-migration.js +502 -0
- package/lib/desktop-pwa.js +206 -0
- package/lib/external-tools.js +221 -0
- package/lib/first-launch-protection.js +245 -0
- package/lib/packaged-runtime.js +110 -0
- package/lib/paths.d.ts +21 -0
- package/lib/paths.js +103 -0
- package/lib/start-launcher.js +1309 -0
- package/mcp-server/dist/config.d.ts +22 -0
- package/mcp-server/dist/config.d.ts.map +1 -0
- package/mcp-server/dist/config.js +109 -0
- package/mcp-server/dist/config.js.map +1 -0
- package/mcp-server/dist/http.d.ts +30 -0
- package/mcp-server/dist/http.d.ts.map +1 -0
- package/mcp-server/dist/http.js +276 -0
- package/mcp-server/dist/http.js.map +1 -0
- package/mcp-server/dist/index.d.ts +48 -0
- package/mcp-server/dist/index.d.ts.map +1 -0
- package/mcp-server/dist/index.js +538 -0
- package/mcp-server/dist/index.js.map +1 -0
- package/mcp-server/dist/preload-http.d.ts +3 -0
- package/mcp-server/dist/preload-http.d.ts.map +1 -0
- package/mcp-server/dist/preload-http.js +28 -0
- package/mcp-server/dist/preload-http.js.map +1 -0
- package/mcp-server/dist/preload.d.ts +3 -0
- package/mcp-server/dist/preload.d.ts.map +1 -0
- package/mcp-server/dist/preload.js +32 -0
- package/mcp-server/dist/preload.js.map +1 -0
- package/mcp-server/dist/scripts/migrate-qdrant-to-sqlite.d.ts +19 -0
- package/mcp-server/dist/scripts/migrate-qdrant-to-sqlite.d.ts.map +1 -0
- package/mcp-server/dist/scripts/migrate-qdrant-to-sqlite.js +403 -0
- package/mcp-server/dist/scripts/migrate-qdrant-to-sqlite.js.map +1 -0
- package/mcp-server/dist/scripts/setup-embeddings.d.ts +3 -0
- package/mcp-server/dist/scripts/setup-embeddings.d.ts.map +1 -0
- package/mcp-server/dist/scripts/setup-embeddings.js +15 -0
- package/mcp-server/dist/scripts/setup-embeddings.js.map +1 -0
- package/mcp-server/dist/services/assistant-judgments.d.ts +79 -0
- package/mcp-server/dist/services/assistant-judgments.d.ts.map +1 -0
- package/mcp-server/dist/services/assistant-judgments.js +128 -0
- package/mcp-server/dist/services/assistant-judgments.js.map +1 -0
- package/mcp-server/dist/services/browser-assist-gate.d.ts +314 -0
- package/mcp-server/dist/services/browser-assist-gate.d.ts.map +1 -0
- package/mcp-server/dist/services/browser-assist-gate.js +344 -0
- package/mcp-server/dist/services/browser-assist-gate.js.map +1 -0
- package/mcp-server/dist/services/browser-assist.d.ts +104 -0
- package/mcp-server/dist/services/browser-assist.d.ts.map +1 -0
- package/mcp-server/dist/services/browser-assist.js +282 -0
- package/mcp-server/dist/services/browser-assist.js.map +1 -0
- package/mcp-server/dist/services/browser-bench.d.ts +772 -0
- package/mcp-server/dist/services/browser-bench.d.ts.map +1 -0
- package/mcp-server/dist/services/browser-bench.js +424 -0
- package/mcp-server/dist/services/browser-bench.js.map +1 -0
- package/mcp-server/dist/services/browser-judgments.d.ts +196 -0
- package/mcp-server/dist/services/browser-judgments.d.ts.map +1 -0
- package/mcp-server/dist/services/browser-judgments.js +363 -0
- package/mcp-server/dist/services/browser-judgments.js.map +1 -0
- package/mcp-server/dist/services/browser-risk.d.ts +166 -0
- package/mcp-server/dist/services/browser-risk.d.ts.map +1 -0
- package/mcp-server/dist/services/browser-risk.js +458 -0
- package/mcp-server/dist/services/browser-risk.js.map +1 -0
- package/mcp-server/dist/services/categories.d.ts +61 -0
- package/mcp-server/dist/services/categories.d.ts.map +1 -0
- package/mcp-server/dist/services/categories.js +377 -0
- package/mcp-server/dist/services/categories.js.map +1 -0
- package/mcp-server/dist/services/codex-config-heal.d.ts +49 -0
- package/mcp-server/dist/services/codex-config-heal.d.ts.map +1 -0
- package/mcp-server/dist/services/codex-config-heal.js +346 -0
- package/mcp-server/dist/services/codex-config-heal.js.map +1 -0
- package/mcp-server/dist/services/desktop-assist-gate.d.ts +198 -0
- package/mcp-server/dist/services/desktop-assist-gate.d.ts.map +1 -0
- package/mcp-server/dist/services/desktop-assist-gate.js +202 -0
- package/mcp-server/dist/services/desktop-assist-gate.js.map +1 -0
- package/mcp-server/dist/services/desktop-assist.d.ts +104 -0
- package/mcp-server/dist/services/desktop-assist.d.ts.map +1 -0
- package/mcp-server/dist/services/desktop-assist.js +266 -0
- package/mcp-server/dist/services/desktop-assist.js.map +1 -0
- package/mcp-server/dist/services/desktop-bench.d.ts +553 -0
- package/mcp-server/dist/services/desktop-bench.d.ts.map +1 -0
- package/mcp-server/dist/services/desktop-bench.js +311 -0
- package/mcp-server/dist/services/desktop-bench.js.map +1 -0
- package/mcp-server/dist/services/desktop-client.d.ts +23 -0
- package/mcp-server/dist/services/desktop-client.d.ts.map +1 -0
- package/mcp-server/dist/services/desktop-client.js +79 -0
- package/mcp-server/dist/services/desktop-client.js.map +1 -0
- package/mcp-server/dist/services/desktop-judgments.d.ts +125 -0
- package/mcp-server/dist/services/desktop-judgments.d.ts.map +1 -0
- package/mcp-server/dist/services/desktop-judgments.js +177 -0
- package/mcp-server/dist/services/desktop-judgments.js.map +1 -0
- package/mcp-server/dist/services/desktop-risk.d.ts +283 -0
- package/mcp-server/dist/services/desktop-risk.d.ts.map +1 -0
- package/mcp-server/dist/services/desktop-risk.js +605 -0
- package/mcp-server/dist/services/desktop-risk.js.map +1 -0
- package/mcp-server/dist/services/discord.d.ts +112 -0
- package/mcp-server/dist/services/discord.d.ts.map +1 -0
- package/mcp-server/dist/services/discord.js +477 -0
- package/mcp-server/dist/services/discord.js.map +1 -0
- package/mcp-server/dist/services/edit-stale.d.ts +81 -0
- package/mcp-server/dist/services/edit-stale.d.ts.map +1 -0
- package/mcp-server/dist/services/edit-stale.js +358 -0
- package/mcp-server/dist/services/edit-stale.js.map +1 -0
- package/mcp-server/dist/services/embedding-service.d.ts +16 -0
- package/mcp-server/dist/services/embedding-service.d.ts.map +1 -0
- package/mcp-server/dist/services/embedding-service.js +126 -0
- package/mcp-server/dist/services/embedding-service.js.map +1 -0
- package/mcp-server/dist/services/embedding-worker.d.ts +2 -0
- package/mcp-server/dist/services/embedding-worker.d.ts.map +1 -0
- package/mcp-server/dist/services/embedding-worker.js +52 -0
- package/mcp-server/dist/services/embedding-worker.js.map +1 -0
- package/mcp-server/dist/services/fb-regions.d.ts +71 -0
- package/mcp-server/dist/services/fb-regions.d.ts.map +1 -0
- package/mcp-server/dist/services/fb-regions.js +211 -0
- package/mcp-server/dist/services/fb-regions.js.map +1 -0
- package/mcp-server/dist/services/file-checksums.d.ts +22 -0
- package/mcp-server/dist/services/file-checksums.d.ts.map +1 -0
- package/mcp-server/dist/services/file-checksums.js +55 -0
- package/mcp-server/dist/services/file-checksums.js.map +1 -0
- package/mcp-server/dist/services/file-excerpt.d.ts +24 -0
- package/mcp-server/dist/services/file-excerpt.d.ts.map +1 -0
- package/mcp-server/dist/services/file-excerpt.js +65 -0
- package/mcp-server/dist/services/file-excerpt.js.map +1 -0
- package/mcp-server/dist/services/identity.d.ts +124 -0
- package/mcp-server/dist/services/identity.d.ts.map +1 -0
- package/mcp-server/dist/services/identity.js +241 -0
- package/mcp-server/dist/services/identity.js.map +1 -0
- package/mcp-server/dist/services/local-embeddings.d.ts +2 -0
- package/mcp-server/dist/services/local-embeddings.d.ts.map +1 -0
- package/mcp-server/dist/services/local-embeddings.js +3 -0
- package/mcp-server/dist/services/local-embeddings.js.map +1 -0
- package/mcp-server/dist/services/memory-client.d.ts +4 -0
- package/mcp-server/dist/services/memory-client.d.ts.map +1 -0
- package/mcp-server/dist/services/memory-client.js +27 -0
- package/mcp-server/dist/services/memory-client.js.map +1 -0
- package/mcp-server/dist/services/memory-judge-backfill.d.ts +135 -0
- package/mcp-server/dist/services/memory-judge-backfill.d.ts.map +1 -0
- package/mcp-server/dist/services/memory-judge-backfill.js +510 -0
- package/mcp-server/dist/services/memory-judge-backfill.js.map +1 -0
- package/mcp-server/dist/services/memory-judgments.d.ts +362 -0
- package/mcp-server/dist/services/memory-judgments.d.ts.map +1 -0
- package/mcp-server/dist/services/memory-judgments.js +674 -0
- package/mcp-server/dist/services/memory-judgments.js.map +1 -0
- package/mcp-server/dist/services/memory-maintenance.d.ts +108 -0
- package/mcp-server/dist/services/memory-maintenance.d.ts.map +1 -0
- package/mcp-server/dist/services/memory-maintenance.js +403 -0
- package/mcp-server/dist/services/memory-maintenance.js.map +1 -0
- package/mcp-server/dist/services/memory-retrieval.d.ts +66 -0
- package/mcp-server/dist/services/memory-retrieval.d.ts.map +1 -0
- package/mcp-server/dist/services/memory-retrieval.js +412 -0
- package/mcp-server/dist/services/memory-retrieval.js.map +1 -0
- package/mcp-server/dist/services/memory-schema.d.ts +16 -0
- package/mcp-server/dist/services/memory-schema.d.ts.map +1 -0
- package/mcp-server/dist/services/memory-schema.js +282 -0
- package/mcp-server/dist/services/memory-schema.js.map +1 -0
- package/mcp-server/dist/services/memory-sessions.d.ts +24 -0
- package/mcp-server/dist/services/memory-sessions.d.ts.map +1 -0
- package/mcp-server/dist/services/memory-sessions.js +110 -0
- package/mcp-server/dist/services/memory-sessions.js.map +1 -0
- package/mcp-server/dist/services/memory-triage.d.ts +60 -0
- package/mcp-server/dist/services/memory-triage.d.ts.map +1 -0
- package/mcp-server/dist/services/memory-triage.js +189 -0
- package/mcp-server/dist/services/memory-triage.js.map +1 -0
- package/mcp-server/dist/services/memory-verification.d.ts +24 -0
- package/mcp-server/dist/services/memory-verification.d.ts.map +1 -0
- package/mcp-server/dist/services/memory-verification.js +92 -0
- package/mcp-server/dist/services/memory-verification.js.map +1 -0
- package/mcp-server/dist/services/memory-writer.d.ts +26 -0
- package/mcp-server/dist/services/memory-writer.d.ts.map +1 -0
- package/mcp-server/dist/services/memory-writer.js +126 -0
- package/mcp-server/dist/services/memory-writer.js.map +1 -0
- package/mcp-server/dist/services/neural-interface.d.ts +439 -0
- package/mcp-server/dist/services/neural-interface.d.ts.map +1 -0
- package/mcp-server/dist/services/neural-interface.js +1135 -0
- package/mcp-server/dist/services/neural-interface.js.map +1 -0
- package/mcp-server/dist/services/profiles.d.ts +120 -0
- package/mcp-server/dist/services/profiles.d.ts.map +1 -0
- package/mcp-server/dist/services/profiles.js +387 -0
- package/mcp-server/dist/services/profiles.js.map +1 -0
- package/mcp-server/dist/services/secret-gate.d.ts +29 -0
- package/mcp-server/dist/services/secret-gate.d.ts.map +1 -0
- package/mcp-server/dist/services/secret-gate.js +43 -0
- package/mcp-server/dist/services/secret-gate.js.map +1 -0
- package/mcp-server/dist/services/server-instructions.d.ts +10 -0
- package/mcp-server/dist/services/server-instructions.d.ts.map +1 -0
- package/mcp-server/dist/services/server-instructions.js +101 -0
- package/mcp-server/dist/services/server-instructions.js.map +1 -0
- package/mcp-server/dist/services/sqlite.d.ts +235 -0
- package/mcp-server/dist/services/sqlite.d.ts.map +1 -0
- package/mcp-server/dist/services/sqlite.js +1185 -0
- package/mcp-server/dist/services/sqlite.js.map +1 -0
- package/mcp-server/dist/services/typesafe-bench.d.ts +99 -0
- package/mcp-server/dist/services/typesafe-bench.d.ts.map +1 -0
- package/mcp-server/dist/services/typesafe-bench.js +218 -0
- package/mcp-server/dist/services/typesafe-bench.js.map +1 -0
- package/mcp-server/dist/services/typesafe-config.d.ts +342 -0
- package/mcp-server/dist/services/typesafe-config.d.ts.map +1 -0
- package/mcp-server/dist/services/typesafe-config.js +746 -0
- package/mcp-server/dist/services/typesafe-config.js.map +1 -0
- package/mcp-server/dist/services/typesafe.d.ts +213 -0
- package/mcp-server/dist/services/typesafe.d.ts.map +1 -0
- package/mcp-server/dist/services/typesafe.js +330 -0
- package/mcp-server/dist/services/typesafe.js.map +1 -0
- package/mcp-server/dist/services/vector-cache.d.ts +68 -0
- package/mcp-server/dist/services/vector-cache.d.ts.map +1 -0
- package/mcp-server/dist/services/vector-cache.js +271 -0
- package/mcp-server/dist/services/vector-cache.js.map +1 -0
- package/mcp-server/dist/services/whiteboard-geometry.d.ts +305 -0
- package/mcp-server/dist/services/whiteboard-geometry.d.ts.map +1 -0
- package/mcp-server/dist/services/whiteboard-geometry.js +666 -0
- package/mcp-server/dist/services/whiteboard-geometry.js.map +1 -0
- package/mcp-server/dist/tools/agents.d.ts +212 -0
- package/mcp-server/dist/tools/agents.d.ts.map +1 -0
- package/mcp-server/dist/tools/agents.js +407 -0
- package/mcp-server/dist/tools/agents.js.map +1 -0
- package/mcp-server/dist/tools/bluesky.d.ts +39 -0
- package/mcp-server/dist/tools/bluesky.d.ts.map +1 -0
- package/mcp-server/dist/tools/bluesky.js +1144 -0
- package/mcp-server/dist/tools/bluesky.js.map +1 -0
- package/mcp-server/dist/tools/browser-advanced.d.ts +58 -0
- package/mcp-server/dist/tools/browser-advanced.d.ts.map +1 -0
- package/mcp-server/dist/tools/browser-advanced.js +106 -0
- package/mcp-server/dist/tools/browser-advanced.js.map +1 -0
- package/mcp-server/dist/tools/browser-batch.d.ts +99 -0
- package/mcp-server/dist/tools/browser-batch.d.ts.map +1 -0
- package/mcp-server/dist/tools/browser-batch.js +187 -0
- package/mcp-server/dist/tools/browser-batch.js.map +1 -0
- package/mcp-server/dist/tools/browser-cheatsheet.d.ts +21 -0
- package/mcp-server/dist/tools/browser-cheatsheet.d.ts.map +1 -0
- package/mcp-server/dist/tools/browser-cheatsheet.js +144 -0
- package/mcp-server/dist/tools/browser-cheatsheet.js.map +1 -0
- package/mcp-server/dist/tools/browser-interact.d.ts +239 -0
- package/mcp-server/dist/tools/browser-interact.d.ts.map +1 -0
- package/mcp-server/dist/tools/browser-interact.js +300 -0
- package/mcp-server/dist/tools/browser-interact.js.map +1 -0
- package/mcp-server/dist/tools/browser-navigate.d.ts +90 -0
- package/mcp-server/dist/tools/browser-navigate.d.ts.map +1 -0
- package/mcp-server/dist/tools/browser-navigate.js +142 -0
- package/mcp-server/dist/tools/browser-navigate.js.map +1 -0
- package/mcp-server/dist/tools/browser-observe.d.ts +561 -0
- package/mcp-server/dist/tools/browser-observe.d.ts.map +1 -0
- package/mcp-server/dist/tools/browser-observe.js +2009 -0
- package/mcp-server/dist/tools/browser-observe.js.map +1 -0
- package/mcp-server/dist/tools/browser.d.ts +34 -0
- package/mcp-server/dist/tools/browser.d.ts.map +1 -0
- package/mcp-server/dist/tools/browser.js +112 -0
- package/mcp-server/dist/tools/browser.js.map +1 -0
- package/mcp-server/dist/tools/card-tools.d.ts +82 -0
- package/mcp-server/dist/tools/card-tools.d.ts.map +1 -0
- package/mcp-server/dist/tools/card-tools.js +137 -0
- package/mcp-server/dist/tools/card-tools.js.map +1 -0
- package/mcp-server/dist/tools/card.d.ts +8 -0
- package/mcp-server/dist/tools/card.d.ts.map +1 -0
- package/mcp-server/dist/tools/card.js +16 -0
- package/mcp-server/dist/tools/card.js.map +1 -0
- package/mcp-server/dist/tools/category.d.ts +32 -0
- package/mcp-server/dist/tools/category.d.ts.map +1 -0
- package/mcp-server/dist/tools/category.js +290 -0
- package/mcp-server/dist/tools/category.js.map +1 -0
- package/mcp-server/dist/tools/choice.d.ts +160 -0
- package/mcp-server/dist/tools/choice.d.ts.map +1 -0
- package/mcp-server/dist/tools/choice.js +80 -0
- package/mcp-server/dist/tools/choice.js.map +1 -0
- package/mcp-server/dist/tools/computer.d.ts +71 -0
- package/mcp-server/dist/tools/computer.d.ts.map +1 -0
- package/mcp-server/dist/tools/computer.js +174 -0
- package/mcp-server/dist/tools/computer.js.map +1 -0
- package/mcp-server/dist/tools/discord-channel.d.ts +44 -0
- package/mcp-server/dist/tools/discord-channel.d.ts.map +1 -0
- package/mcp-server/dist/tools/discord-channel.js +236 -0
- package/mcp-server/dist/tools/discord-channel.js.map +1 -0
- package/mcp-server/dist/tools/discord-guild.d.ts +20 -0
- package/mcp-server/dist/tools/discord-guild.d.ts.map +1 -0
- package/mcp-server/dist/tools/discord-guild.js +138 -0
- package/mcp-server/dist/tools/discord-guild.js.map +1 -0
- package/mcp-server/dist/tools/discord-member.d.ts +26 -0
- package/mcp-server/dist/tools/discord-member.d.ts.map +1 -0
- package/mcp-server/dist/tools/discord-member.js +122 -0
- package/mcp-server/dist/tools/discord-member.js.map +1 -0
- package/mcp-server/dist/tools/discord-message.d.ts +36 -0
- package/mcp-server/dist/tools/discord-message.d.ts.map +1 -0
- package/mcp-server/dist/tools/discord-message.js +184 -0
- package/mcp-server/dist/tools/discord-message.js.map +1 -0
- package/mcp-server/dist/tools/discord-onboarding.d.ts +32 -0
- package/mcp-server/dist/tools/discord-onboarding.d.ts.map +1 -0
- package/mcp-server/dist/tools/discord-onboarding.js +179 -0
- package/mcp-server/dist/tools/discord-onboarding.js.map +1 -0
- package/mcp-server/dist/tools/discord-role.d.ts +34 -0
- package/mcp-server/dist/tools/discord-role.d.ts.map +1 -0
- package/mcp-server/dist/tools/discord-role.js +178 -0
- package/mcp-server/dist/tools/discord-role.js.map +1 -0
- package/mcp-server/dist/tools/discord-thread.d.ts +28 -0
- package/mcp-server/dist/tools/discord-thread.d.ts.map +1 -0
- package/mcp-server/dist/tools/discord-thread.js +88 -0
- package/mcp-server/dist/tools/discord-thread.js.map +1 -0
- package/mcp-server/dist/tools/discord-webhook.d.ts +32 -0
- package/mcp-server/dist/tools/discord-webhook.d.ts.map +1 -0
- package/mcp-server/dist/tools/discord-webhook.js +154 -0
- package/mcp-server/dist/tools/discord-webhook.js.map +1 -0
- package/mcp-server/dist/tools/discord.d.ts +7 -0
- package/mcp-server/dist/tools/discord.d.ts.map +1 -0
- package/mcp-server/dist/tools/discord.js +25 -0
- package/mcp-server/dist/tools/discord.js.map +1 -0
- package/mcp-server/dist/tools/fb-groups.d.ts +98 -0
- package/mcp-server/dist/tools/fb-groups.d.ts.map +1 -0
- package/mcp-server/dist/tools/fb-groups.js +369 -0
- package/mcp-server/dist/tools/fb-groups.js.map +1 -0
- package/mcp-server/dist/tools/forget.d.ts +14 -0
- package/mcp-server/dist/tools/forget.d.ts.map +1 -0
- package/mcp-server/dist/tools/forget.js +26 -0
- package/mcp-server/dist/tools/forget.js.map +1 -0
- package/mcp-server/dist/tools/git-tools.d.ts +24 -0
- package/mcp-server/dist/tools/git-tools.d.ts.map +1 -0
- package/mcp-server/dist/tools/git-tools.js +107 -0
- package/mcp-server/dist/tools/git-tools.js.map +1 -0
- package/mcp-server/dist/tools/git.d.ts +7 -0
- package/mcp-server/dist/tools/git.d.ts.map +1 -0
- package/mcp-server/dist/tools/git.js +11 -0
- package/mcp-server/dist/tools/git.js.map +1 -0
- package/mcp-server/dist/tools/gsc/experience.d.ts +135 -0
- package/mcp-server/dist/tools/gsc/experience.d.ts.map +1 -0
- package/mcp-server/dist/tools/gsc/experience.js +351 -0
- package/mcp-server/dist/tools/gsc/experience.js.map +1 -0
- package/mcp-server/dist/tools/gsc/helpers.d.ts +78 -0
- package/mcp-server/dist/tools/gsc/helpers.d.ts.map +1 -0
- package/mcp-server/dist/tools/gsc/helpers.js +258 -0
- package/mcp-server/dist/tools/gsc/helpers.js.map +1 -0
- package/mcp-server/dist/tools/gsc/indexing.d.ts +121 -0
- package/mcp-server/dist/tools/gsc/indexing.d.ts.map +1 -0
- package/mcp-server/dist/tools/gsc/indexing.js +357 -0
- package/mcp-server/dist/tools/gsc/indexing.js.map +1 -0
- package/mcp-server/dist/tools/gsc/inspect.d.ts +78 -0
- package/mcp-server/dist/tools/gsc/inspect.d.ts.map +1 -0
- package/mcp-server/dist/tools/gsc/inspect.js +321 -0
- package/mcp-server/dist/tools/gsc/inspect.js.map +1 -0
- package/mcp-server/dist/tools/gsc/navigate.d.ts +44 -0
- package/mcp-server/dist/tools/gsc/navigate.d.ts.map +1 -0
- package/mcp-server/dist/tools/gsc/navigate.js +197 -0
- package/mcp-server/dist/tools/gsc/navigate.js.map +1 -0
- package/mcp-server/dist/tools/gsc/performance.d.ts +84 -0
- package/mcp-server/dist/tools/gsc/performance.d.ts.map +1 -0
- package/mcp-server/dist/tools/gsc/performance.js +274 -0
- package/mcp-server/dist/tools/gsc/performance.js.map +1 -0
- package/mcp-server/dist/tools/gsc/settings.d.ts +153 -0
- package/mcp-server/dist/tools/gsc/settings.d.ts.map +1 -0
- package/mcp-server/dist/tools/gsc/settings.js +425 -0
- package/mcp-server/dist/tools/gsc/settings.js.map +1 -0
- package/mcp-server/dist/tools/gsc.d.ts +7 -0
- package/mcp-server/dist/tools/gsc.d.ts.map +1 -0
- package/mcp-server/dist/tools/gsc.js +51 -0
- package/mcp-server/dist/tools/gsc.js.map +1 -0
- package/mcp-server/dist/tools/image-tools.d.ts +24 -0
- package/mcp-server/dist/tools/image-tools.d.ts.map +1 -0
- package/mcp-server/dist/tools/image-tools.js +80 -0
- package/mcp-server/dist/tools/image-tools.js.map +1 -0
- package/mcp-server/dist/tools/image.d.ts +10 -0
- package/mcp-server/dist/tools/image.d.ts.map +1 -0
- package/mcp-server/dist/tools/image.js +14 -0
- package/mcp-server/dist/tools/image.js.map +1 -0
- package/mcp-server/dist/tools/leonardo-browser-tools.d.ts +97 -0
- package/mcp-server/dist/tools/leonardo-browser-tools.d.ts.map +1 -0
- package/mcp-server/dist/tools/leonardo-browser-tools.js +228 -0
- package/mcp-server/dist/tools/leonardo-browser-tools.js.map +1 -0
- package/mcp-server/dist/tools/leonardo.d.ts +13 -0
- package/mcp-server/dist/tools/leonardo.d.ts.map +1 -0
- package/mcp-server/dist/tools/leonardo.js +21 -0
- package/mcp-server/dist/tools/leonardo.js.map +1 -0
- package/mcp-server/dist/tools/loop.d.ts +30 -0
- package/mcp-server/dist/tools/loop.d.ts.map +1 -0
- package/mcp-server/dist/tools/loop.js +401 -0
- package/mcp-server/dist/tools/loop.js.map +1 -0
- package/mcp-server/dist/tools/memories.d.ts +56 -0
- package/mcp-server/dist/tools/memories.d.ts.map +1 -0
- package/mcp-server/dist/tools/memories.js +171 -0
- package/mcp-server/dist/tools/memories.js.map +1 -0
- package/mcp-server/dist/tools/morelogin.d.ts +24 -0
- package/mcp-server/dist/tools/morelogin.d.ts.map +1 -0
- package/mcp-server/dist/tools/morelogin.js +79 -0
- package/mcp-server/dist/tools/morelogin.js.map +1 -0
- package/mcp-server/dist/tools/profile.d.ts +17 -0
- package/mcp-server/dist/tools/profile.d.ts.map +1 -0
- package/mcp-server/dist/tools/profile.js +114 -0
- package/mcp-server/dist/tools/profile.js.map +1 -0
- package/mcp-server/dist/tools/recall.d.ts +71 -0
- package/mcp-server/dist/tools/recall.d.ts.map +1 -0
- package/mcp-server/dist/tools/recall.js +147 -0
- package/mcp-server/dist/tools/recall.js.map +1 -0
- package/mcp-server/dist/tools/reflect.d.ts +56 -0
- package/mcp-server/dist/tools/reflect.d.ts.map +1 -0
- package/mcp-server/dist/tools/reflect.js +157 -0
- package/mcp-server/dist/tools/reflect.js.map +1 -0
- package/mcp-server/dist/tools/remember.d.ts +62 -0
- package/mcp-server/dist/tools/remember.d.ts.map +1 -0
- package/mcp-server/dist/tools/remember.js +201 -0
- package/mcp-server/dist/tools/remember.js.map +1 -0
- package/mcp-server/dist/tools/response.d.ts +23 -0
- package/mcp-server/dist/tools/response.d.ts.map +1 -0
- package/mcp-server/dist/tools/response.js +24 -0
- package/mcp-server/dist/tools/response.js.map +1 -0
- package/mcp-server/dist/tools/restore.d.ts +14 -0
- package/mcp-server/dist/tools/restore.d.ts.map +1 -0
- package/mcp-server/dist/tools/restore.js +23 -0
- package/mcp-server/dist/tools/restore.js.map +1 -0
- package/mcp-server/dist/tools/style-guide-tools.d.ts +51 -0
- package/mcp-server/dist/tools/style-guide-tools.d.ts.map +1 -0
- package/mcp-server/dist/tools/style-guide-tools.js +231 -0
- package/mcp-server/dist/tools/style-guide-tools.js.map +1 -0
- package/mcp-server/dist/tools/style-guide.d.ts +8 -0
- package/mcp-server/dist/tools/style-guide.d.ts.map +1 -0
- package/mcp-server/dist/tools/style-guide.js +12 -0
- package/mcp-server/dist/tools/style-guide.js.map +1 -0
- package/mcp-server/dist/tools/sync.d.ts +20 -0
- package/mcp-server/dist/tools/sync.d.ts.map +1 -0
- package/mcp-server/dist/tools/sync.js +156 -0
- package/mcp-server/dist/tools/sync.js.map +1 -0
- package/mcp-server/dist/tools/tictactoe-tools.d.ts +18 -0
- package/mcp-server/dist/tools/tictactoe-tools.d.ts.map +1 -0
- package/mcp-server/dist/tools/tictactoe-tools.js +78 -0
- package/mcp-server/dist/tools/tictactoe-tools.js.map +1 -0
- package/mcp-server/dist/tools/tictactoe.d.ts +7 -0
- package/mcp-server/dist/tools/tictactoe.d.ts.map +1 -0
- package/mcp-server/dist/tools/tictactoe.js +11 -0
- package/mcp-server/dist/tools/tictactoe.js.map +1 -0
- package/mcp-server/dist/tools/utils.d.ts +19 -0
- package/mcp-server/dist/tools/utils.d.ts.map +1 -0
- package/mcp-server/dist/tools/utils.js +54 -0
- package/mcp-server/dist/tools/utils.js.map +1 -0
- package/mcp-server/dist/tools/whiteboard-format.d.ts +88 -0
- package/mcp-server/dist/tools/whiteboard-format.d.ts.map +1 -0
- package/mcp-server/dist/tools/whiteboard-format.js +337 -0
- package/mcp-server/dist/tools/whiteboard-format.js.map +1 -0
- package/mcp-server/dist/tools/whiteboard-tools.d.ts +326 -0
- package/mcp-server/dist/tools/whiteboard-tools.d.ts.map +1 -0
- package/mcp-server/dist/tools/whiteboard-tools.js +222 -0
- package/mcp-server/dist/tools/whiteboard-tools.js.map +1 -0
- package/mcp-server/dist/tools/whiteboard.d.ts +8 -0
- package/mcp-server/dist/tools/whiteboard.d.ts.map +1 -0
- package/mcp-server/dist/tools/whiteboard.js +16 -0
- package/mcp-server/dist/tools/whiteboard.js.map +1 -0
- package/mcp-server/dist/tools/youtube/analytics.d.ts +46 -0
- package/mcp-server/dist/tools/youtube/analytics.d.ts.map +1 -0
- package/mcp-server/dist/tools/youtube/analytics.js +83 -0
- package/mcp-server/dist/tools/youtube/analytics.js.map +1 -0
- package/mcp-server/dist/tools/youtube/dedup.d.ts +35 -0
- package/mcp-server/dist/tools/youtube/dedup.d.ts.map +1 -0
- package/mcp-server/dist/tools/youtube/dedup.js +56 -0
- package/mcp-server/dist/tools/youtube/dedup.js.map +1 -0
- package/mcp-server/dist/tools/youtube/download.d.ts +31 -0
- package/mcp-server/dist/tools/youtube/download.d.ts.map +1 -0
- package/mcp-server/dist/tools/youtube/download.js +30 -0
- package/mcp-server/dist/tools/youtube/download.js.map +1 -0
- package/mcp-server/dist/tools/youtube/helpers.d.ts +66 -0
- package/mcp-server/dist/tools/youtube/helpers.d.ts.map +1 -0
- package/mcp-server/dist/tools/youtube/helpers.js +143 -0
- package/mcp-server/dist/tools/youtube/helpers.js.map +1 -0
- package/mcp-server/dist/tools/youtube/media.d.ts +43 -0
- package/mcp-server/dist/tools/youtube/media.d.ts.map +1 -0
- package/mcp-server/dist/tools/youtube/media.js +97 -0
- package/mcp-server/dist/tools/youtube/media.js.map +1 -0
- package/mcp-server/dist/tools/youtube/metadata.d.ts +33 -0
- package/mcp-server/dist/tools/youtube/metadata.d.ts.map +1 -0
- package/mcp-server/dist/tools/youtube/metadata.js +106 -0
- package/mcp-server/dist/tools/youtube/metadata.js.map +1 -0
- package/mcp-server/dist/tools/youtube/navigate.d.ts +30 -0
- package/mcp-server/dist/tools/youtube/navigate.d.ts.map +1 -0
- package/mcp-server/dist/tools/youtube/navigate.js +71 -0
- package/mcp-server/dist/tools/youtube/navigate.js.map +1 -0
- package/mcp-server/dist/tools/youtube/playlist.d.ts +29 -0
- package/mcp-server/dist/tools/youtube/playlist.d.ts.map +1 -0
- package/mcp-server/dist/tools/youtube/playlist.js +128 -0
- package/mcp-server/dist/tools/youtube/playlist.js.map +1 -0
- package/mcp-server/dist/tools/youtube/schedule.d.ts +31 -0
- package/mcp-server/dist/tools/youtube/schedule.d.ts.map +1 -0
- package/mcp-server/dist/tools/youtube/schedule.js +147 -0
- package/mcp-server/dist/tools/youtube/schedule.js.map +1 -0
- package/mcp-server/dist/tools/youtube/source.d.ts +36 -0
- package/mcp-server/dist/tools/youtube/source.d.ts.map +1 -0
- package/mcp-server/dist/tools/youtube/source.js +85 -0
- package/mcp-server/dist/tools/youtube/source.js.map +1 -0
- package/mcp-server/dist/tools/youtube/upload.d.ts +53 -0
- package/mcp-server/dist/tools/youtube/upload.d.ts.map +1 -0
- package/mcp-server/dist/tools/youtube/upload.js +255 -0
- package/mcp-server/dist/tools/youtube/upload.js.map +1 -0
- package/mcp-server/dist/tools/youtube.d.ts +12 -0
- package/mcp-server/dist/tools/youtube.d.ts.map +1 -0
- package/mcp-server/dist/tools/youtube.js +38 -0
- package/mcp-server/dist/tools/youtube.js.map +1 -0
- package/mcp-server/dist/tui.d.ts +3 -0
- package/mcp-server/dist/tui.d.ts.map +1 -0
- package/mcp-server/dist/tui.js +806 -0
- package/mcp-server/dist/tui.js.map +1 -0
- package/mcp-server/dist/types.d.ts +77 -0
- package/mcp-server/dist/types.d.ts.map +1 -0
- package/mcp-server/dist/types.js +2 -0
- package/mcp-server/dist/types.js.map +1 -0
- package/mcp-server/package-lock.json +4798 -0
- package/mcp-server/package.json +55 -38
- package/mcp-server/run.mjs +12 -2
- package/mcp-server/src/config.ts +48 -3
- package/mcp-server/src/http.ts +296 -93
- package/mcp-server/src/index.ts +546 -203
- package/mcp-server/src/preload-http.ts +19 -18
- package/mcp-server/src/preload.ts +19 -18
- package/mcp-server/src/scripts/setup-embeddings.ts +9 -0
- package/mcp-server/src/services/assistant-judgments.ts +157 -0
- package/mcp-server/src/services/browser-assist-gate.ts +383 -0
- package/mcp-server/src/services/browser-assist.ts +267 -0
- package/mcp-server/src/services/browser-bench.ts +477 -0
- package/mcp-server/src/services/browser-judgments.ts +414 -0
- package/mcp-server/src/services/browser-risk.ts +484 -0
- package/mcp-server/src/services/categories.ts +36 -19
- package/mcp-server/src/services/codex-config-heal.ts +403 -0
- package/mcp-server/src/services/desktop-assist-gate.ts +251 -0
- package/mcp-server/src/services/desktop-assist.ts +308 -0
- package/mcp-server/src/services/desktop-bench.ts +372 -0
- package/mcp-server/src/services/desktop-client.ts +76 -0
- package/mcp-server/src/services/desktop-judgments.ts +218 -0
- package/mcp-server/src/services/desktop-risk.ts +743 -0
- package/mcp-server/src/services/edit-stale.ts +299 -0
- package/mcp-server/src/services/embedding-service.ts +108 -0
- package/mcp-server/src/services/embedding-worker.ts +46 -0
- package/mcp-server/src/services/fb-regions.ts +221 -0
- package/mcp-server/src/services/file-checksums.ts +26 -9
- package/mcp-server/src/services/file-excerpt.ts +59 -0
- package/mcp-server/src/services/identity.ts +291 -0
- package/mcp-server/src/services/local-embeddings.ts +2 -77
- package/mcp-server/src/services/memory-client.ts +23 -0
- package/mcp-server/src/services/memory-judge-backfill.ts +462 -0
- package/mcp-server/src/services/memory-judgments.ts +901 -0
- package/mcp-server/src/services/memory-maintenance.ts +360 -0
- package/mcp-server/src/services/memory-retrieval.ts +349 -0
- package/mcp-server/src/services/memory-schema.ts +280 -0
- package/mcp-server/src/services/memory-sessions.ts +87 -0
- package/mcp-server/src/services/memory-triage.ts +182 -0
- package/mcp-server/src/services/memory-verification.ts +68 -0
- package/mcp-server/src/services/memory-writer.ts +125 -0
- package/mcp-server/src/services/neural-interface.ts +1217 -73
- package/mcp-server/src/services/profiles.ts +428 -0
- package/mcp-server/src/services/secret-gate.ts +52 -0
- package/mcp-server/src/services/server-instructions.ts +122 -0
- package/mcp-server/src/services/sqlite.ts +1456 -823
- package/mcp-server/src/services/typesafe-bench.ts +247 -0
- package/mcp-server/src/services/typesafe-config.ts +790 -0
- package/mcp-server/src/services/typesafe.ts +390 -0
- package/mcp-server/src/services/vector-cache.ts +255 -0
- package/mcp-server/src/services/whiteboard-geometry.ts +711 -0
- package/mcp-server/src/tools/agents.ts +539 -0
- package/mcp-server/src/tools/bluesky.ts +1186 -0
- package/mcp-server/src/tools/browser-advanced.ts +15 -6
- package/mcp-server/src/tools/browser-batch.ts +178 -0
- package/mcp-server/src/tools/browser-cheatsheet.ts +155 -0
- package/mcp-server/src/tools/browser-interact.ts +362 -255
- package/mcp-server/src/tools/browser-navigate.ts +164 -77
- package/mcp-server/src/tools/browser-observe.ts +2222 -1330
- package/mcp-server/src/tools/browser.ts +181 -107
- package/mcp-server/src/tools/card.ts +7 -5
- package/mcp-server/src/tools/choice.ts +103 -0
- package/mcp-server/src/tools/computer.ts +190 -0
- package/mcp-server/src/tools/discord.ts +10 -23
- package/mcp-server/src/tools/fb-groups.ts +387 -0
- package/mcp-server/src/tools/forget.ts +1 -1
- package/mcp-server/src/tools/git.ts +3 -1
- package/mcp-server/src/tools/gsc/experience.ts +440 -0
- package/mcp-server/src/tools/gsc/helpers.ts +288 -0
- package/mcp-server/src/tools/gsc/indexing.ts +495 -0
- package/mcp-server/src/tools/gsc/inspect.ts +391 -0
- package/mcp-server/src/tools/gsc/navigate.ts +236 -0
- package/mcp-server/src/tools/gsc/performance.ts +352 -0
- package/mcp-server/src/tools/gsc/settings.ts +564 -0
- package/mcp-server/src/tools/gsc.ts +95 -0
- package/mcp-server/src/tools/image.ts +3 -1
- package/mcp-server/src/tools/leonardo-browser-tools.ts +47 -37
- package/mcp-server/src/tools/leonardo.ts +7 -5
- package/mcp-server/src/tools/loop.ts +118 -25
- package/mcp-server/src/tools/memories.ts +65 -5
- package/mcp-server/src/tools/morelogin.ts +81 -0
- package/mcp-server/src/tools/profile.ts +122 -0
- package/mcp-server/src/tools/recall.ts +105 -261
- package/mcp-server/src/tools/reflect.ts +171 -145
- package/mcp-server/src/tools/remember.ts +223 -115
- package/mcp-server/src/tools/style-guide-tools.ts +250 -0
- package/mcp-server/src/tools/style-guide.ts +16 -0
- package/mcp-server/src/tools/sync.ts +66 -9
- package/mcp-server/src/tools/tictactoe.ts +3 -1
- package/mcp-server/src/tools/utils.ts +22 -0
- package/mcp-server/src/tools/whiteboard-format.ts +394 -0
- package/mcp-server/src/tools/whiteboard-tools.ts +191 -183
- package/mcp-server/src/tools/whiteboard.ts +7 -5
- package/mcp-server/src/tools/youtube/analytics.ts +106 -0
- package/mcp-server/src/tools/youtube/dedup.ts +57 -0
- package/mcp-server/src/tools/youtube/download.ts +41 -0
- package/mcp-server/src/tools/youtube/helpers.ts +183 -0
- package/mcp-server/src/tools/youtube/media.ts +109 -0
- package/mcp-server/src/tools/youtube/metadata.ts +112 -0
- package/mcp-server/src/tools/youtube/navigate.ts +81 -0
- package/mcp-server/src/tools/youtube/playlist.ts +134 -0
- package/mcp-server/src/tools/youtube/schedule.ts +158 -0
- package/mcp-server/src/tools/youtube/source.ts +101 -0
- package/mcp-server/src/tools/youtube/upload.ts +296 -0
- package/mcp-server/src/tools/youtube.ts +47 -0
- package/mcp-server/src/tui.ts +8 -9
- package/neural-interface/games/TicTacToe/1.svg +1 -0
- package/neural-interface/games/TicTacToe/2.svg +1 -0
- package/neural-interface/games/TicTacToe/3.svg +1 -0
- package/neural-interface/games/TicTacToe/4.svg +1 -0
- package/neural-interface/games/TicTacToe/5.svg +1 -0
- package/neural-interface/games/TicTacToe/6.svg +1 -0
- package/neural-interface/games/TicTacToe/7.svg +1 -0
- package/neural-interface/games/TicTacToe/8.svg +1 -0
- package/neural-interface/games/TicTacToe/9.svg +1 -0
- package/neural-interface/games/TicTacToe/Board.svg +1 -0
- package/neural-interface/games/TicTacToe/Circle.svg +1 -0
- package/neural-interface/games/TicTacToe/Cross.svg +1 -0
- package/neural-interface/i18n/en.json +7022 -0
- package/neural-interface/i18n/pt-BR.json +7026 -0
- package/neural-interface/lib/assistant-api.js +1005 -0
- package/neural-interface/lib/assistant-attachments.js +121 -0
- package/neural-interface/lib/assistant-brains/claude.js +207 -0
- package/neural-interface/lib/assistant-brains/codex-browser-policy-hook.mjs +43 -0
- package/neural-interface/lib/assistant-brains/codex-route-gate-hook.mjs +56 -0
- package/neural-interface/lib/assistant-brains/codex.js +213 -0
- package/neural-interface/lib/assistant-brains/opencode-browser-policy.js +47 -0
- package/neural-interface/lib/assistant-brains/opencode-route-gate.js +62 -0
- package/neural-interface/lib/assistant-brains/opencode.js +320 -0
- package/neural-interface/lib/assistant-budget.js +318 -0
- package/neural-interface/lib/assistant-catalog.js +731 -0
- package/neural-interface/lib/assistant-clarify.js +664 -0
- package/neural-interface/lib/assistant-config.js +232 -0
- package/neural-interface/lib/assistant-dispatch.js +2744 -0
- package/neural-interface/lib/assistant-envelope.js +582 -0
- package/neural-interface/lib/assistant-evidence.js +236 -0
- package/neural-interface/lib/assistant-hidden-models.js +272 -0
- package/neural-interface/lib/assistant-jev.js +117 -0
- package/neural-interface/lib/assistant-judgments.js +111 -0
- package/neural-interface/lib/assistant-media.js +335 -0
- package/neural-interface/lib/assistant-memory.js +398 -0
- package/neural-interface/lib/assistant-persona.js +444 -0
- package/neural-interface/lib/assistant-plan-permissions.js +448 -0
- package/neural-interface/lib/assistant-playbooks/design.md +87 -0
- package/neural-interface/lib/assistant-playbooks.js +72 -0
- package/neural-interface/lib/assistant-pricing.js +159 -0
- package/neural-interface/lib/assistant-route-gate-codex.js +163 -0
- package/neural-interface/lib/assistant-route-gate.js +212 -0
- package/neural-interface/lib/assistant-router.js +1324 -0
- package/neural-interface/lib/assistant-runtime.js +3337 -0
- package/neural-interface/lib/assistant-task-prompt.js +472 -0
- package/neural-interface/lib/assistant-usage.js +1688 -0
- package/neural-interface/lib/augmented-path.js +70 -0
- package/neural-interface/lib/automation-storage-migration.js +54 -0
- package/neural-interface/lib/backup-service.js +851 -0
- package/neural-interface/lib/backup-zip-reader.js +262 -0
- package/neural-interface/lib/browser-assist-api.js +41 -0
- package/neural-interface/lib/browser-console.js +176 -0
- package/neural-interface/lib/browser-execution.js +241 -0
- package/neural-interface/lib/browser-extraction.js +191 -0
- package/neural-interface/lib/browser-language.js +83 -0
- package/neural-interface/lib/browser-screenshot.js +399 -0
- package/neural-interface/lib/browser-semantic-context.js +639 -0
- package/neural-interface/lib/browser-snapshots.js +192 -0
- package/neural-interface/lib/browser-tab-recovery.js +119 -0
- package/neural-interface/lib/browser-targets.js +70 -0
- package/neural-interface/lib/browser-tool-policy.js +926 -0
- package/neural-interface/lib/claude-accounts.js +230 -0
- package/neural-interface/lib/claude-agent-bridge.js +3203 -0
- package/neural-interface/lib/claude-bypass-policy.js +99 -0
- package/neural-interface/lib/claude-executable.js +241 -0
- package/neural-interface/lib/claude-history.js +429 -0
- package/neural-interface/lib/claude-model-catalog.js +444 -0
- package/neural-interface/lib/claude-panel-requests.js +165 -0
- package/neural-interface/lib/claude-panel-session.js +272 -0
- package/neural-interface/lib/claude-permission-rules.js +153 -0
- package/neural-interface/lib/claude-session-cleanup.js +71 -0
- package/neural-interface/lib/claude-session-list.js +82 -0
- package/neural-interface/lib/claude-session-ops.js +140 -0
- package/neural-interface/lib/claude-settings-view.js +51 -0
- package/neural-interface/lib/claude-skin-connect.js +79 -0
- package/neural-interface/lib/claude-stall-policy.js +7 -0
- package/neural-interface/lib/claude-temporary.js +435 -0
- package/neural-interface/lib/cli-update-planner.js +312 -0
- package/neural-interface/lib/codex-capabilities.d.ts +41 -0
- package/neural-interface/lib/codex-capabilities.js +148 -0
- package/neural-interface/lib/codex-collaboration-mode.js +17 -0
- package/neural-interface/lib/codex-compat-rpc.js +241 -0
- package/neural-interface/lib/codex-mcp-approvals.js +56 -0
- package/neural-interface/lib/codex-mcp-apps.js +47 -0
- package/neural-interface/lib/codex-model-context.js +202 -0
- package/neural-interface/lib/codex-plan-store.js +71 -0
- package/neural-interface/lib/codex-request-journal.js +242 -0
- package/neural-interface/lib/codex-runtime-path.js +213 -0
- package/neural-interface/lib/codex-session-catalog.js +231 -0
- package/neural-interface/lib/codex-session-settings.js +46 -0
- package/neural-interface/lib/codex-sidepanel-permissions.js +110 -0
- package/neural-interface/lib/codex-thread-history.js +165 -0
- package/neural-interface/lib/codex-user-verification.js +34 -0
- package/neural-interface/lib/codex-writer-lifecycle.js +152 -0
- package/neural-interface/lib/confined-fs.js +256 -0
- package/neural-interface/lib/db.js +922 -0
- package/neural-interface/lib/design-md.js +9 -0
- package/neural-interface/lib/desktop/api.js +92 -0
- package/neural-interface/lib/desktop/audit.js +62 -0
- package/neural-interface/lib/desktop/build.js +423 -0
- package/neural-interface/lib/desktop/config.js +606 -0
- package/neural-interface/lib/desktop/coords.js +76 -0
- package/neural-interface/lib/desktop/fake-helper.js +1192 -0
- package/neural-interface/lib/desktop/frames.js +77 -0
- package/neural-interface/lib/desktop/grants.js +84 -0
- package/neural-interface/lib/desktop/guards.js +170 -0
- package/neural-interface/lib/desktop/helper/SynabunDesktop.swift +3056 -0
- package/neural-interface/lib/desktop/lease.js +51 -0
- package/neural-interface/lib/desktop/manager.js +545 -0
- package/neural-interface/lib/desktop/press-contexts.js +103 -0
- package/neural-interface/lib/desktop/protocol.js +495 -0
- package/neural-interface/lib/desktop/service.js +1202 -0
- package/neural-interface/lib/effort-levels.js +148 -0
- package/neural-interface/lib/event-loop-monitor.js +67 -0
- package/neural-interface/lib/exec-loop-command.js +209 -0
- package/neural-interface/lib/folder-picker.ps1 +77 -0
- package/neural-interface/lib/http-guards.js +287 -0
- package/neural-interface/lib/jsonl-lines.js +94 -0
- package/neural-interface/lib/loop-logger.js +127 -0
- package/neural-interface/lib/mcp-client-config.js +133 -0
- package/neural-interface/lib/mcp-installer.js +487 -0
- package/neural-interface/lib/mcp-profile-refresh-coordinator.js +78 -0
- package/neural-interface/lib/mcp-profile-servers.js +120 -0
- package/neural-interface/lib/memo-cache.js +84 -0
- package/neural-interface/lib/memory-api.js +758 -0
- package/neural-interface/lib/memory-map-api.js +1150 -0
- package/neural-interface/lib/memory-map-layout.js +872 -0
- package/neural-interface/lib/memory-map-worker.js +165 -0
- package/neural-interface/lib/memory-session-capture.js +81 -0
- package/neural-interface/lib/memory-timers.js +62 -0
- package/neural-interface/lib/morelogin.js +301 -0
- package/neural-interface/lib/native-binary-runtime.js +382 -0
- package/neural-interface/lib/native-loop-goal.js +33 -0
- package/neural-interface/lib/native-loop-providers.js +1002 -0
- package/neural-interface/lib/native-loop-runtime.js +747 -0
- package/neural-interface/lib/offline-page.js +54 -0
- package/neural-interface/lib/opencode-hidden-models.js +113 -0
- package/neural-interface/lib/opencode-history.js +253 -0
- package/neural-interface/lib/opencode-runtime-config.js +58 -0
- package/neural-interface/lib/opencode-v2-client.js +486 -0
- package/neural-interface/lib/opencode-v2-ws-requests.js +955 -0
- package/neural-interface/lib/path-confine.js +213 -0
- package/neural-interface/lib/plugin-installer.js +264 -0
- package/neural-interface/lib/project-storage.js +766 -0
- package/neural-interface/lib/pty-host/core.js +603 -0
- package/neural-interface/lib/pty-host/flow.js +43 -0
- package/neural-interface/lib/pty-host/host.js +47 -0
- package/neural-interface/lib/pty-host/manager.js +360 -0
- package/neural-interface/lib/pty-host/protocol.js +81 -0
- package/neural-interface/lib/pty-host/snapshot.js +133 -0
- package/neural-interface/lib/remote-policy.js +582 -0
- package/neural-interface/lib/rulesets/api.js +175 -0
- package/neural-interface/lib/rulesets/fs-safe.js +245 -0
- package/neural-interface/lib/rulesets/installer.js +1453 -0
- package/neural-interface/lib/rulesets/json-edit.js +186 -0
- package/neural-interface/lib/rulesets/lock.js +170 -0
- package/neural-interface/lib/rulesets/managed-text.js +314 -0
- package/neural-interface/lib/rulesets/normalise.js +24 -0
- package/neural-interface/lib/rulesets/render.js +84 -0
- package/neural-interface/lib/schedule-launch-intent.js +40 -0
- package/neural-interface/lib/session-cache-builder.js +524 -0
- package/neural-interface/lib/session-chunker.js +344 -0
- package/neural-interface/lib/session-indexer.js +327 -0
- package/neural-interface/lib/session-title-generator.js +232 -0
- package/neural-interface/lib/skill-prompt-bridge.js +11 -0
- package/neural-interface/lib/style-guide/api.js +375 -0
- package/neural-interface/lib/style-guide/color.js +352 -0
- package/neural-interface/lib/style-guide/export-css.js +99 -0
- package/neural-interface/lib/style-guide/export-dtcg.js +209 -0
- package/neural-interface/lib/style-guide/export-tailwind.js +102 -0
- package/neural-interface/lib/style-guide/fonts.json +227 -0
- package/neural-interface/lib/style-guide/import.js +1268 -0
- package/neural-interface/lib/style-guide/pointers.js +103 -0
- package/neural-interface/lib/style-guide/presets.js +232 -0
- package/neural-interface/lib/style-guide/render-design-md.js +319 -0
- package/neural-interface/lib/style-guide/schema.js +848 -0
- package/neural-interface/lib/style-guide/security.js +43 -0
- package/neural-interface/lib/style-guide/store.js +491 -0
- package/neural-interface/lib/style-guide/summary.js +106 -0
- package/neural-interface/lib/style-guide/tokens.js +170 -0
- package/neural-interface/lib/synabun-update-plan.js +324 -0
- package/neural-interface/lib/synabun-version.js +179 -0
- package/neural-interface/lib/system-restore.js +99 -0
- package/neural-interface/lib/terminal-env.js +86 -0
- package/neural-interface/lib/ui-blob-store.js +106 -0
- package/neural-interface/lib/vector-cache.js +2 -0
- package/neural-interface/lib/virtual-socket.js +60 -0
- package/neural-interface/lib/whatsapp/api.js +146 -0
- package/neural-interface/lib/whatsapp/auth-store.js +389 -0
- package/neural-interface/lib/whatsapp/baileys-adapter.js +457 -0
- package/neural-interface/lib/whatsapp/brain.js +128 -0
- package/neural-interface/lib/whatsapp/bridge.js +1499 -0
- package/neural-interface/lib/whatsapp/cards.js +519 -0
- package/neural-interface/lib/whatsapp/commands.js +92 -0
- package/neural-interface/lib/whatsapp/config.js +291 -0
- package/neural-interface/lib/whatsapp/connector/entry.mjs +25 -0
- package/neural-interface/lib/whatsapp/connector/manifest.json +6 -0
- package/neural-interface/lib/whatsapp/connector/npm-shrinkwrap.json +717 -0
- package/neural-interface/lib/whatsapp/connector/package.json +8 -0
- package/neural-interface/lib/whatsapp/fake-baileys.js +444 -0
- package/neural-interface/lib/whatsapp/format.js +552 -0
- package/neural-interface/lib/whatsapp/host-core.js +1225 -0
- package/neural-interface/lib/whatsapp/host.js +119 -0
- package/neural-interface/lib/whatsapp/identity.js +288 -0
- package/neural-interface/lib/whatsapp/inbound.js +149 -0
- package/neural-interface/lib/whatsapp/installer.js +562 -0
- package/neural-interface/lib/whatsapp/manager.js +638 -0
- package/neural-interface/lib/whatsapp/paths.js +81 -0
- package/neural-interface/lib/whatsapp/protocol.js +327 -0
- package/neural-interface/lib/whatsapp/qr-svg.js +57 -0
- package/neural-interface/lib/whatsapp/redact.js +130 -0
- package/neural-interface/lib/whatsapp/service.js +1305 -0
- package/neural-interface/lib/whatsapp/vendor/qrcodegen.js +848 -0
- package/neural-interface/package-lock.json +4431 -0
- package/neural-interface/package.json +58 -27
- package/neural-interface/public/apple-touch-icon.png +0 -0
- package/neural-interface/public/category-logos/synabun.png +0 -0
- package/neural-interface/public/claude.svg +1 -0
- package/neural-interface/public/favicon-16x16.png +0 -0
- package/neural-interface/public/favicon-32x32.png +0 -0
- package/neural-interface/public/icon-192.png +0 -0
- package/neural-interface/public/icon-512.png +0 -0
- package/neural-interface/public/index.html +32 -182
- package/neural-interface/public/index2d.html +2 -2
- package/neural-interface/public/install-app.html +31 -0
- package/neural-interface/public/logo-synabun.png +0 -0
- package/neural-interface/public/logoHD.png +0 -0
- package/neural-interface/public/manifest.json +2 -0
- package/neural-interface/public/mcp.svg +4 -0
- package/neural-interface/public/offline.html +670 -299
- package/neural-interface/public/onboarding.html +804 -161
- package/neural-interface/public/opencode-logo-dark-square.svg +1 -0
- package/neural-interface/public/shared/agent-runtime-options.js +596 -0
- package/neural-interface/public/shared/api.js +339 -28
- package/neural-interface/public/shared/assistant/asst-accounts.js +318 -0
- package/neural-interface/public/shared/assistant/asst-agents-dock.js +296 -0
- package/neural-interface/public/shared/assistant/asst-api.js +270 -0
- package/neural-interface/public/shared/assistant/asst-brain-picker.js +744 -0
- package/neural-interface/public/shared/assistant/asst-budget.js +333 -0
- package/neural-interface/public/shared/assistant/asst-composer.js +656 -0
- package/neural-interface/public/shared/assistant/asst-computer.js +803 -0
- package/neural-interface/public/shared/assistant/asst-control.js +1018 -0
- package/neural-interface/public/shared/assistant/asst-hosts.js +262 -0
- package/neural-interface/public/shared/assistant/asst-mascot.js +313 -0
- package/neural-interface/public/shared/assistant/asst-menu.js +375 -0
- package/neural-interface/public/shared/assistant/asst-panel.js +1845 -0
- package/neural-interface/public/shared/assistant/asst-rack-styles.js +586 -0
- package/neural-interface/public/shared/assistant/asst-render.js +3305 -0
- package/neural-interface/public/shared/assistant/asst-route.js +1653 -0
- package/neural-interface/public/shared/assistant/asst-roving.js +75 -0
- package/neural-interface/public/shared/assistant/asst-sanitize.js +117 -0
- package/neural-interface/public/shared/assistant/asst-sidepanel-styles.js +488 -0
- package/neural-interface/public/shared/assistant/asst-sidepanel.js +675 -0
- package/neural-interface/public/shared/assistant/asst-slash.js +258 -0
- package/neural-interface/public/shared/assistant/asst-state.js +727 -0
- package/neural-interface/public/shared/assistant/asst-styles.js +1686 -0
- package/neural-interface/public/shared/assistant/asst-tool-kinds.js +1017 -0
- package/neural-interface/public/shared/assistant/asst-usage.js +444 -0
- package/neural-interface/public/shared/assistant/asst-ws.js +175 -0
- package/neural-interface/public/shared/automation-context.js +75 -0
- package/neural-interface/public/shared/blob-store.js +99 -0
- package/neural-interface/public/shared/cdx/cdx-capabilities.js +118 -0
- package/neural-interface/public/shared/cdx/cdx-cards.js +37 -0
- package/neural-interface/public/shared/cdx/cdx-commands.js +171 -0
- package/neural-interface/public/shared/cdx/cdx-context-menu.js +402 -0
- package/neural-interface/public/shared/cdx/cdx-context-model.js +220 -0
- package/neural-interface/public/shared/cdx/cdx-features.js +408 -0
- package/neural-interface/public/shared/cdx/cdx-icons.js +89 -0
- package/neural-interface/public/shared/cdx/cdx-mcp-app-host.js +414 -0
- package/neural-interface/public/shared/cdx/cdx-mcp-app-proxy.html +6 -0
- package/neural-interface/public/shared/cdx/cdx-mcp-app-proxy.js +56 -0
- package/neural-interface/public/shared/cdx/cdx-mcp-app.js +178 -0
- package/neural-interface/public/shared/cdx/cdx-model-catalog.js +120 -0
- package/neural-interface/public/shared/cdx/cdx-output-model.js +261 -0
- package/neural-interface/public/shared/cdx/cdx-output.js +382 -0
- package/neural-interface/public/shared/cdx/cdx-panel.js +1372 -0
- package/neural-interface/public/shared/cdx/cdx-plan.js +266 -0
- package/neural-interface/public/shared/cdx/cdx-protocol.js +682 -0
- package/neural-interface/public/shared/cdx/cdx-render.js +3381 -0
- package/neural-interface/public/shared/cdx/cdx-requests.js +1136 -0
- package/neural-interface/public/shared/cdx/cdx-styles.js +3251 -0
- package/neural-interface/public/shared/cdx/cdx-tabs.js +7992 -0
- package/neural-interface/public/shared/cdx/cdx-ws.js +363 -0
- package/neural-interface/public/shared/cli-status.js +169 -0
- package/neural-interface/public/shared/command-runner-model.js +30 -0
- package/neural-interface/public/shared/constants.js +22 -5
- package/neural-interface/public/shared/cp/cp-agents.js +186 -0
- package/neural-interface/public/shared/cp/cp-bash.js +252 -0
- package/neural-interface/public/shared/cp/cp-compose.js +159 -0
- package/neural-interface/public/shared/cp/cp-context-menu.js +309 -0
- package/neural-interface/public/shared/cp/cp-context-model.js +157 -0
- package/neural-interface/public/shared/cp/cp-context-window.js +80 -0
- package/neural-interface/public/shared/cp/cp-ctx.js +11 -0
- package/neural-interface/public/shared/cp/cp-diff.js +255 -0
- package/neural-interface/public/shared/cp/cp-event-rows.js +637 -0
- package/neural-interface/public/shared/cp/cp-events.js +846 -0
- package/neural-interface/public/shared/cp/cp-markdown.js +104 -0
- package/neural-interface/public/shared/cp/cp-permission-model.js +905 -0
- package/neural-interface/public/shared/cp/cp-permissions.js +626 -0
- package/neural-interface/public/shared/cp/cp-rehydrate.js +113 -0
- package/neural-interface/public/shared/cp/cp-restore.js +224 -0
- package/neural-interface/public/shared/cp/cp-session-model.js +338 -0
- package/neural-interface/public/shared/cp/cp-session-settings.js +254 -0
- package/neural-interface/public/shared/cp/cp-sessions.js +227 -0
- package/neural-interface/public/shared/cp/cp-statusline.js +153 -0
- package/neural-interface/public/shared/cp/cp-styles.js +349 -0
- package/neural-interface/public/shared/cp/cp-tasks-model.js +282 -0
- package/neural-interface/public/shared/cp/cp-tasks.js +107 -0
- package/neural-interface/public/shared/cp/cp-temporary-view.js +56 -0
- package/neural-interface/public/shared/cp/cp-temporary.js +231 -0
- package/neural-interface/public/shared/cp/cp-tool-cards.js +326 -0
- package/neural-interface/public/shared/cp/cp-tool-results.js +618 -0
- package/neural-interface/public/shared/cp/cp-usage-model.js +124 -0
- package/neural-interface/public/shared/graph-activity.js +68 -0
- package/neural-interface/public/shared/html-shell.js +116 -17
- package/neural-interface/public/shared/i18n.js +132 -34
- package/neural-interface/public/shared/node-positions-store.js +44 -0
- package/neural-interface/public/shared/ocp-hidden-models.js +116 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-approvals.js +355 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-autoaccept-button.js +35 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-automation-ownership.js +72 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-binding.js +280 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-caps.js +67 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-changes-logic.js +179 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-changes.js +164 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-childpanel.js +725 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-compact-button.js +75 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-composer-logic.js +1204 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-confirm-logic.js +117 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-confirm.js +59 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-context-gauge.js +252 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-context-menu.js +478 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-context-model.js +179 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-events.js +233 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-icons.js +30 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-manager.js +1065 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-mention-hints.js +182 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-modelpicker.js +655 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-panel.js +2636 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-plan.js +601 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-profile-inheritance.js +78 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-projectbar.js +649 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-providers.js +35 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-rehydrate.js +357 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-render-logic.js +189 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-render.js +1869 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-select.js +42 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-send-logic.js +117 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-send.js +1714 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-session-actions.js +468 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-session-widgets.js +63 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-sessions-logic.js +366 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-settings-link.js +19 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-slash-hints.js +343 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-state.js +746 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-status-logic.js +347 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-status.js +338 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-styles.js +3543 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-subagents-logic.js +482 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-tools-logic.js +351 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-tools.js +168 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-variantpicker.js +315 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-ws.js +545 -0
- package/neural-interface/public/shared/provider-icons.js +30 -0
- package/neural-interface/public/shared/pwa-install-page.js +34 -0
- package/neural-interface/public/shared/pwa-install.css +12 -0
- package/neural-interface/public/shared/pwa-install.js +28 -0
- package/neural-interface/public/shared/session-title.js +100 -0
- package/neural-interface/public/shared/settings/settings-ia.js +389 -0
- package/neural-interface/public/shared/settings/settings-kit.js +234 -0
- package/neural-interface/public/shared/settings/settings-rules.js +160 -0
- package/neural-interface/public/shared/settings/settings-search.js +463 -0
- package/neural-interface/public/shared/settings/settings-shell.js +570 -0
- package/neural-interface/public/shared/start-bridge.js +583 -0
- package/neural-interface/public/shared/state.js +5 -0
- package/neural-interface/public/shared/storage.js +50 -7
- package/neural-interface/public/shared/styleguide/sg-agents.js +42 -0
- package/neural-interface/public/shared/styleguide/sg-brand.js +4 -0
- package/neural-interface/public/shared/styleguide/sg-color-client.js +388 -0
- package/neural-interface/public/shared/styleguide/sg-colors.js +151 -0
- package/neural-interface/public/shared/styleguide/sg-components.js +35 -0
- package/neural-interface/public/shared/styleguide/sg-history.js +41 -0
- package/neural-interface/public/shared/styleguide/sg-icons-logo.js +38 -0
- package/neural-interface/public/shared/styleguide/sg-imagery.js +4 -0
- package/neural-interface/public/shared/styleguide/sg-import-export.js +48 -0
- package/neural-interface/public/shared/styleguide/sg-kit.js +284 -0
- package/neural-interface/public/shared/styleguide/sg-labels.js +318 -0
- package/neural-interface/public/shared/styleguide/sg-layout.js +4 -0
- package/neural-interface/public/shared/styleguide/sg-motion.js +5 -0
- package/neural-interface/public/shared/styleguide/sg-panel.js +237 -0
- package/neural-interface/public/shared/styleguide/sg-preview.js +138 -0
- package/neural-interface/public/shared/styleguide/sg-rules.js +9 -0
- package/neural-interface/public/shared/styleguide/sg-shape.js +24 -0
- package/neural-interface/public/shared/styleguide/sg-state.js +132 -0
- package/neural-interface/public/shared/styleguide/sg-typography.js +125 -0
- package/neural-interface/public/shared/styles.css +8614 -1477
- package/neural-interface/public/shared/synabun-mascot.js +1625 -0
- package/neural-interface/public/shared/synabun-ticker.js +376 -0
- package/neural-interface/public/shared/term-ready.js +307 -0
- package/neural-interface/public/shared/term-renderer.js +343 -0
- package/neural-interface/public/shared/ui-assistant-panel.js +10 -0
- package/neural-interface/public/shared/ui-assistant.js +77 -0
- package/neural-interface/public/shared/ui-automation-studio.js +5105 -3573
- package/neural-interface/public/shared/ui-claude-panel.js +11685 -6333
- package/neural-interface/public/shared/ui-codex-panel.js +12 -0
- package/neural-interface/public/shared/ui-command-runner.js +251 -468
- package/neural-interface/public/shared/ui-cost-widget.js +55 -34
- package/neural-interface/public/shared/ui-detail.js +77 -14
- package/neural-interface/public/shared/ui-explorer.js +360 -181
- package/neural-interface/public/shared/ui-file-explorer.js +485 -107
- package/neural-interface/public/shared/ui-help.js +2 -2
- package/neural-interface/public/shared/ui-image-gallery.js +45 -21
- package/neural-interface/public/shared/ui-judgments.js +1346 -0
- package/neural-interface/public/shared/ui-keybinds.js +3 -2
- package/neural-interface/public/shared/ui-link.js +105 -51
- package/neural-interface/public/shared/ui-loading.js +222 -11
- package/neural-interface/public/shared/ui-memory-maintenance.js +111 -0
- package/neural-interface/public/shared/ui-menubar.js +100 -31
- package/neural-interface/public/shared/ui-native-loop-router-state.js +94 -0
- package/neural-interface/public/shared/ui-native-loop-router.js +493 -0
- package/neural-interface/public/shared/ui-native-window-id.js +7 -0
- package/neural-interface/public/shared/ui-navbar.js +357 -222
- package/neural-interface/public/shared/ui-notifications.js +58 -12
- package/neural-interface/public/shared/ui-opencode-panel-v2.js +17 -0
- package/neural-interface/public/shared/ui-panels.js +15 -7
- package/neural-interface/public/shared/ui-resume.js +823 -653
- package/neural-interface/public/shared/ui-schedule-queue.js +172 -0
- package/neural-interface/public/shared/ui-schedules-studio.js +1882 -0
- package/neural-interface/public/shared/ui-scroll-follow.js +194 -0
- package/neural-interface/public/shared/ui-sessions.js +789 -34
- package/neural-interface/public/shared/ui-settings.js +5774 -2194
- package/neural-interface/public/shared/ui-sidepanel-layout.js +109 -0
- package/neural-interface/public/shared/ui-sidepanel-runtime.js +19 -0
- package/neural-interface/public/shared/ui-sidepanel-session-entry.js +40 -0
- package/neural-interface/public/shared/ui-sidepanel-sessions.js +221 -0
- package/neural-interface/public/shared/ui-sidepanel-state.js +131 -0
- package/neural-interface/public/shared/ui-sidepanel-tray.js +547 -0
- package/neural-interface/public/shared/ui-sidepanel-windows.js +387 -0
- package/neural-interface/public/shared/ui-skills.js +18 -32
- package/neural-interface/public/shared/ui-styleguide.js +35 -0
- package/neural-interface/public/shared/ui-sync.js +87 -0
- package/neural-interface/public/shared/ui-terminal.js +7863 -6385
- package/neural-interface/public/shared/ui-tool-updates.js +292 -0
- package/neural-interface/public/shared/ui-tooltip.js +156 -15
- package/neural-interface/public/shared/ui-tutorial-draw.js +119 -683
- package/neural-interface/public/shared/ui-tutorial-layout.js +135 -0
- package/neural-interface/public/shared/ui-tutorial-steps.js +59 -2209
- package/neural-interface/public/shared/ui-tutorial.css +102 -0
- package/neural-interface/public/shared/ui-tutorial.js +557 -1076
- package/neural-interface/public/shared/ui-update.js +420 -68
- package/neural-interface/public/shared/ui-whatsapp.js +941 -0
- package/neural-interface/public/shared/ui-whiteboard.js +1076 -233
- package/neural-interface/public/shared/ui-workspaces.js +2 -1
- package/neural-interface/public/shared/utils.js +58 -0
- package/neural-interface/public/shared/vterm-buffer.js +15 -5
- package/neural-interface/public/shared/whatsapp/wa-phone.js +65 -0
- package/neural-interface/public/shared/whatsapp/wa-view.js +411 -0
- package/neural-interface/public/sidepanel-session.html +18 -0
- package/neural-interface/public/sw.js +10 -2
- package/neural-interface/public/synabun.png +0 -0
- package/neural-interface/public/variant/2d/graph.js +1707 -1635
- package/neural-interface/public/variant/2d/lasso.js +2 -1
- package/neural-interface/public/variant/2d/layout.js +595 -594
- package/neural-interface/public/variant/2d/main.js +557 -521
- package/neural-interface/public/variant/2d/settings-gfx.js +18 -24
- package/neural-interface/public/variant/3d/main.js +517 -500
- package/neural-interface/public/variant/3d/map-controls.js +144 -0
- package/neural-interface/public/variant/3d/map-data.js +251 -0
- package/neural-interface/public/variant/3d/map-labels.js +241 -0
- package/neural-interface/public/variant/3d/map-pick.js +90 -0
- package/neural-interface/public/variant/3d/map-renderer.js +521 -0
- package/neural-interface/public/variant/3d/map-shaders.js +158 -0
- package/neural-interface/public/variant/3d/map-view.js +618 -0
- package/neural-interface/public/vendor/three/manifest.json +3 -0
- package/neural-interface/public/vendor/three/three-0.169.0.min.js +3844 -0
- package/neural-interface/public/vendor/xterm/manifest.json +3 -0
- package/neural-interface/public/vendor/xterm/xterm-6.0.0.css +285 -0
- package/neural-interface/public/vendor/xterm/xterm-6.0.0.min.js +192 -0
- package/neural-interface/scripts/build-vendor.mjs +64 -0
- package/neural-interface/scripts/codex-protocol-fixture.mjs +83 -0
- package/neural-interface/scripts/rebuild-pty.js +39 -22
- package/neural-interface/scripts/vendor-three-entry.js +24 -0
- package/neural-interface/scripts/vendor-xterm-entry.js +8 -0
- package/neural-interface/server.js +33983 -15000
- package/neural-interface/skins/default/skin.css +90 -0
- package/neural-interface/skins/default/skin.json +8 -0
- package/neural-interface/templates/rulesets/README.md +9 -0
- package/neural-interface/templates/rulesets/claude.md +3 -0
- package/neural-interface/templates/rulesets/codex.md +2 -0
- package/neural-interface/templates/rulesets/coexistence.md +6 -0
- package/neural-interface/templates/rulesets/core.md +26 -0
- package/neural-interface/templates/rulesets/cursor.md +2 -0
- package/neural-interface/templates/rulesets/gemini.md +2 -0
- package/neural-interface/templates/rulesets/legacy-hashes.json +227 -0
- package/neural-interface/templates/rulesets/manifest.json +12 -0
- package/neural-interface/templates/rulesets/opencode.md +2 -0
- package/package.json +131 -53
- package/postinstall.js +55 -26
- package/preuninstall.js +187 -0
- package/scripts/restore-data-home-from-backup.mjs +239 -0
- package/setup.js +872 -260
- package/skills/leonardo/SKILL.md +19 -10
- package/skills/leonardo/modules/image-prompter.md +18 -12
- package/skills/leonardo/modules/video-prompter.md +19 -13
- package/skills/synabun/SKILL.md +209 -185
- package/skills/synabun/icon.png +0 -0
- package/skills/synabun/modules/audit.md +380 -374
- package/skills/synabun/modules/changelog.md +15 -6
- package/skills/synabun/modules/idea.md +148 -144
- package/skills/synabun/modules/memorize.md +13 -4
- package/skills/synabun/modules/schedule.md +198 -0
- package/skills/synabun/synabunicon.png +0 -0
- package/updater.cmd +31 -0
- package/updater.mjs +382 -0
- package/updater.sh +29 -0
- package/hooks/claude-code/test-user-learning.mjs +0 -531
- package/neural-interface/public/claude-chat.css +0 -878
- package/neural-interface/public/claude-chat.html +0 -92
- package/neural-interface/public/claude-chat.js +0 -1168
- package/neural-interface/public/index-legacy.html +0 -14677
- package/neural-interface/public/index2d-legacy.html +0 -8193
- package/neural-interface/public/shared/html-term-renderer.js +0 -1022
- package/neural-interface/public/variant/3d/background.js +0 -884
- package/neural-interface/public/variant/3d/camera.js +0 -661
- package/neural-interface/public/variant/3d/gfx.js +0 -116
- package/neural-interface/public/variant/3d/graph.js +0 -2399
- package/neural-interface/public/variant/3d/settings-gfx.js +0 -228
- package/neural-interface/templates/CLAUDE-template.md +0 -211
|
@@ -4,10 +4,98 @@
|
|
|
4
4
|
* which manages Playwright sessions, CDP screencast, stealth, etc.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
8
|
+
import { randomUUID } from 'node:crypto';
|
|
9
|
+
|
|
10
|
+
import {
|
|
11
|
+
type CallerIdentity,
|
|
12
|
+
getIdentity,
|
|
13
|
+
effectivePins,
|
|
14
|
+
terminalIdFor,
|
|
15
|
+
callerRole,
|
|
16
|
+
setReleaseHook,
|
|
17
|
+
peekStdioIdentity,
|
|
18
|
+
isHttpMode,
|
|
19
|
+
} from './identity.js';
|
|
20
|
+
|
|
7
21
|
const BASE_URL = process.env.NEURAL_INTERFACE_URL
|
|
8
22
|
|| `http://localhost:${process.env.NEURAL_PORT || '3344'}`;
|
|
9
23
|
const DEFAULT_TIMEOUT = 10_000;
|
|
10
24
|
const LONG_TIMEOUT = 30_000;
|
|
25
|
+
const SESSION_CREATE_TIMEOUT = 70_000;
|
|
26
|
+
// Existing engagement spacing can consume 90 seconds before the click begins.
|
|
27
|
+
const CLICK_TIMEOUT = 120_000;
|
|
28
|
+
|
|
29
|
+
export function isBrowserV2Enabled(): boolean {
|
|
30
|
+
return process.env.SYNABUN_BROWSER_V2 !== '0';
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
type BrowserRoute = { sessionId: string; tabId?: string };
|
|
34
|
+
const resolvedRoutes = new WeakMap<CallerIdentity, { key: string; route: BrowserRoute; sessionId?: string; tabId?: string; autoCreate?: { url?: string }; platform?: boolean }>();
|
|
35
|
+
const resolutionRefresh = new AsyncLocalStorage<boolean>();
|
|
36
|
+
export interface BrowserBatchContext {
|
|
37
|
+
route: BrowserRoute;
|
|
38
|
+
errors: NiResponse[];
|
|
39
|
+
}
|
|
40
|
+
const browserCancellation = new AsyncLocalStorage<{ signal: AbortSignal; scope: 'browser' | 'batch' }>();
|
|
41
|
+
export function runWithBrowserCancellation<T>(signal: AbortSignal | undefined, run: () => T, scope: 'browser' | 'batch' = 'browser'): T {
|
|
42
|
+
return signal ? browserCancellation.run({ signal, scope }, run) : run();
|
|
43
|
+
}
|
|
44
|
+
const batchContext = new AsyncLocalStorage<BrowserBatchContext>();
|
|
45
|
+
export function runBrowserBatchContext<T>(context: BrowserBatchContext, run: () => T): T {
|
|
46
|
+
return batchContext.run(context, run);
|
|
47
|
+
}
|
|
48
|
+
/** Inside a browser_batch step. Browser assistance is off there: a batch is a known sequence. */
|
|
49
|
+
export function inBrowserBatch(): boolean {
|
|
50
|
+
return batchContext.getStore() !== undefined;
|
|
51
|
+
}
|
|
52
|
+
/** The MCP caller's cancellation signal, so an advisory judgment ends with the tool call that asked for it. */
|
|
53
|
+
export function currentBrowserSignal(): AbortSignal | undefined {
|
|
54
|
+
return browserCancellation.getStore()?.signal;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function browserMetric(record: Record<string, unknown>): void {
|
|
58
|
+
if (process.env.SYNABUN_BROWSER_METRICS === '1') {
|
|
59
|
+
console.error(JSON.stringify({ source: 'browser-client', ...record }));
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Platform tools (BlueSky, X, Facebook, YouTube, …) always act on normal pages, so
|
|
64
|
+
// inside this scope resolution requires the default browser: an explicit session
|
|
65
|
+
// the server says does not serve it is dropped for the default one.
|
|
66
|
+
const platformRoute = new AsyncLocalStorage<boolean>();
|
|
67
|
+
export function withPlatformRoute<T>(run: () => T): T {
|
|
68
|
+
return platformRoute.run(true, run);
|
|
69
|
+
}
|
|
70
|
+
function inPlatformRoute(): boolean {
|
|
71
|
+
return platformRoute.getStore() === true;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// The default browser as the Neural Interface last described it (its
|
|
75
|
+
// X-Synabun-Browser-Default header on every /api/browser response: connect mode
|
|
76
|
+
// and MoreLogin env). Part of every route key, so a change of browser settings
|
|
77
|
+
// drops every cached route of this process; the server in-process calls
|
|
78
|
+
// noteBrowserDefault when the settings are saved.
|
|
79
|
+
let browserDefault = '';
|
|
80
|
+
export function noteBrowserDefault(signature: string | null | undefined): void {
|
|
81
|
+
if (typeof signature === 'string' && signature !== browserDefault) browserDefault = signature;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function routeKey(id: CallerIdentity, sessionId?: string, tabId?: string, wantsDefaultBrowser = false): string {
|
|
85
|
+
const pins = effectivePins(id);
|
|
86
|
+
// Only an explicit id resolves differently for page-opening and platform calls
|
|
87
|
+
// (resolveSessionUncached may drop it), so only then do they get their own slot.
|
|
88
|
+
return JSON.stringify([sessionId, tabId, pins.browserSessionId, pins.browserTabId,
|
|
89
|
+
id.state.ancestorPinnedSession, id.state.ancestorPinnedTab, sessionId ? wantsDefaultBrowser : null, browserDefault]);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export function isBrowserFastMode(): boolean {
|
|
93
|
+
return process.env.SYNABUN_BROWSER_FAST === '1';
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export function isBrowserCompactMode(): boolean {
|
|
97
|
+
return process.env.SYNABUN_BROWSER_COMPACT === '1' || isBrowserFastMode();
|
|
98
|
+
}
|
|
11
99
|
|
|
12
100
|
export interface BrowserSessionInfo {
|
|
13
101
|
id: string;
|
|
@@ -15,49 +103,373 @@ export interface BrowserSessionInfo {
|
|
|
15
103
|
title: string;
|
|
16
104
|
createdAt: number;
|
|
17
105
|
clients: number;
|
|
106
|
+
loopOwned?: boolean;
|
|
107
|
+
interactiveOwned?: boolean;
|
|
108
|
+
agentOwned?: boolean;
|
|
109
|
+
persistent?: boolean;
|
|
110
|
+
activeTabId?: string | null;
|
|
111
|
+
tabs?: Array<{ id: string; url?: string; title?: string; active?: boolean }>;
|
|
112
|
+
/** ownerKey → tabId for every automation that owns a tab in this session.
|
|
113
|
+
* Used to tell a pristine (manual) session apart from one another automation
|
|
114
|
+
* already drives, so we never adopt-and-collide with its tab. */
|
|
115
|
+
tabOwners?: Record<string, string>;
|
|
116
|
+
profileMode?: string;
|
|
117
|
+
moreloginEnvId?: string | null;
|
|
118
|
+
/** Server's verdict (sessionServesMoreLoginDefault): may this session carry normal
|
|
119
|
+
* pages? False only while MoreLogin is the default; absent on older servers. */
|
|
120
|
+
servesDefault?: boolean;
|
|
18
121
|
}
|
|
19
122
|
|
|
20
|
-
interface NiResponse {
|
|
123
|
+
export interface NiResponse {
|
|
21
124
|
ok?: boolean;
|
|
22
125
|
error?: string;
|
|
126
|
+
tabRecovered?: boolean;
|
|
127
|
+
sessionInvalidated?: boolean;
|
|
23
128
|
[key: string]: unknown;
|
|
24
129
|
}
|
|
25
130
|
|
|
26
|
-
async function
|
|
131
|
+
async function requestOnce(
|
|
27
132
|
method: string,
|
|
28
133
|
path: string,
|
|
29
134
|
body?: Record<string, unknown>,
|
|
30
135
|
timeout = DEFAULT_TIMEOUT
|
|
31
136
|
): Promise<NiResponse> {
|
|
137
|
+
const cancellation = browserCancellation.getStore();
|
|
138
|
+
const callerSignal = cancellation?.signal;
|
|
139
|
+
const cancellationCode = cancellation?.scope === 'batch' ? 'BATCH_CANCELLED' : 'BROWSER_CANCELLED';
|
|
140
|
+
const cancellationLabel = cancellation?.scope === 'batch' ? 'Browser batch' : 'Browser request';
|
|
141
|
+
if (callerSignal?.aborted) return { error: `${cancellationLabel} cancelled before the request started.`, code: cancellationCode, actionStarted: false };
|
|
142
|
+
const requestId = randomUUID();
|
|
143
|
+
const startedAt = performance.now();
|
|
144
|
+
const deadline = Date.now() + timeout;
|
|
145
|
+
let responseBytes = 0;
|
|
146
|
+
let estimatedTextTokens = 0;
|
|
147
|
+
let status: number | undefined;
|
|
32
148
|
const controller = new AbortController();
|
|
149
|
+
const cancel = () => controller.abort();
|
|
150
|
+
callerSignal?.addEventListener('abort', cancel, { once: true });
|
|
151
|
+
if (callerSignal?.aborted) cancel();
|
|
152
|
+
let sent = false;
|
|
33
153
|
const timer = setTimeout(() => controller.abort(), timeout);
|
|
34
154
|
|
|
35
155
|
try {
|
|
156
|
+
const headers: Record<string, string> = { 'Content-Type': 'application/json' };
|
|
157
|
+
// Per-caller routing identity: the server maps this to the caller's owned
|
|
158
|
+
// tab (_tabOwners) so tab-less browser calls never land on another
|
|
159
|
+
// automation's tab. Derived per-request over HTTP, per-process for stdio.
|
|
160
|
+
headers['X-Synabun-Terminal'] = terminalIdFor(getIdentity());
|
|
161
|
+
// Assistant runtimes forward their role so /api/assistant/* can tell an
|
|
162
|
+
// orchestrator apart from a worker run (workers must never dispatch).
|
|
163
|
+
const role = callerRole();
|
|
164
|
+
if (role) headers['X-Synabun-Role'] = role;
|
|
165
|
+
headers['X-Synabun-Request-Id'] = requestId;
|
|
166
|
+
headers['X-Synabun-Deadline'] = String(deadline);
|
|
167
|
+
// Lets the server refuse advisory payloads and auto-heal for a batch step on its own authority.
|
|
168
|
+
if (batchContext.getStore()) headers['X-Synabun-Batch'] = '1';
|
|
36
169
|
const opts: RequestInit = {
|
|
37
170
|
method,
|
|
38
|
-
headers
|
|
171
|
+
headers,
|
|
39
172
|
signal: controller.signal,
|
|
40
173
|
};
|
|
41
174
|
if (body && method !== 'GET') {
|
|
42
175
|
opts.body = JSON.stringify(body);
|
|
43
176
|
}
|
|
177
|
+
if (callerSignal?.aborted) return { error: `${cancellationLabel} cancelled before the request started.`, code: cancellationCode, actionStarted: false };
|
|
178
|
+
sent = true;
|
|
44
179
|
const res = await fetch(`${BASE_URL}${path}`, opts);
|
|
45
|
-
|
|
180
|
+
status = res.status;
|
|
181
|
+
noteBrowserDefault(res.headers?.get?.('X-Synabun-Browser-Default'));
|
|
182
|
+
const responseText = await res.text();
|
|
183
|
+
const data = JSON.parse(responseText) as NiResponse;
|
|
184
|
+
if (process.env.SYNABUN_BROWSER_METRICS === '1') {
|
|
185
|
+
responseBytes = Buffer.byteLength(responseText, 'utf8');
|
|
186
|
+
// Approximation, not provider-billed usage; exclude base64 image fields.
|
|
187
|
+
const { image: _image, screenshot: _screenshot, data: _data, ...textFields } = data;
|
|
188
|
+
estimatedTextTokens = Math.ceil(JSON.stringify(textFields).length / 4);
|
|
189
|
+
}
|
|
46
190
|
if (!res.ok && !data.error) {
|
|
47
191
|
data.error = `HTTP ${res.status}`;
|
|
48
192
|
}
|
|
49
193
|
return data;
|
|
50
194
|
} catch (err: unknown) {
|
|
51
195
|
const msg = err instanceof Error ? err.message : String(err);
|
|
52
|
-
if (
|
|
53
|
-
return { error:
|
|
196
|
+
if (callerSignal?.aborted) {
|
|
197
|
+
return { error: `${cancellationLabel} cancelled; inspect the page before retrying.`, code: cancellationCode, ...(sent ? { outcome: 'uncertain' } : { actionStarted: false }) };
|
|
198
|
+
}
|
|
199
|
+
if (controller.signal.aborted || /abort/i.test(msg)) {
|
|
200
|
+
return { error: `Request timed out after ${timeout}ms; outcome may be uncertain. Inspect the page before retrying.`, code: 'REQUEST_TIMEOUT', outcome: 'uncertain' };
|
|
54
201
|
}
|
|
55
|
-
return { error: `Neural Interface unreachable: ${msg}. Is the Neural Interface server running
|
|
202
|
+
return { error: `Neural Interface unreachable: ${msg}. Is the Neural Interface server running?`, code: 'TRANSPORT_ERROR', outcome: 'uncertain' };
|
|
56
203
|
} finally {
|
|
57
204
|
clearTimeout(timer);
|
|
205
|
+
callerSignal?.removeEventListener('abort', cancel);
|
|
206
|
+
if (path.startsWith('/api/browser/')) {
|
|
207
|
+
browserMetric({ requestId, phase: 'http', method,
|
|
208
|
+
operation: path.split('?')[0].replace(/\/sessions\/[^/]+/, '/sessions/:id'),
|
|
209
|
+
durationMs: Math.round((performance.now() - startedAt) * 100) / 100,
|
|
210
|
+
status, responseBytes, estimatedTextTokens });
|
|
211
|
+
}
|
|
58
212
|
}
|
|
59
213
|
}
|
|
60
214
|
|
|
215
|
+
async function request(
|
|
216
|
+
method: string,
|
|
217
|
+
path: string,
|
|
218
|
+
body?: Record<string, unknown>,
|
|
219
|
+
timeout = DEFAULT_TIMEOUT,
|
|
220
|
+
): Promise<NiResponse> {
|
|
221
|
+
const result = await requestOnce(method, path, body, timeout);
|
|
222
|
+
const context = batchContext.getStore();
|
|
223
|
+
const missingRoute = result.actionStarted === false
|
|
224
|
+
&& (result.code === 'SESSION_NOT_FOUND' || result.code === 'TAB_NOT_FOUND');
|
|
225
|
+
const match = /^\/api\/browser\/sessions\/([^/?]+)\/(.+)$/.exec(path);
|
|
226
|
+
if (isBrowserV2Enabled() && missingRoute && match) {
|
|
227
|
+
const id = getIdentity();
|
|
228
|
+
const cached = resolvedRoutes.get(id);
|
|
229
|
+
resolvedRoutes.delete(id);
|
|
230
|
+
// Batches are pinned to their original tab and never recover midway.
|
|
231
|
+
const pinnedSession = effectivePins(id).browserSessionId || id.state.ancestorPinnedSession;
|
|
232
|
+
if (!context && cached?.route.sessionId === match[1]
|
|
233
|
+
&& (!cached.sessionId || cached.sessionId === pinnedSession)) {
|
|
234
|
+
// Clear unpinned fast-mode state too: a force-refresh must not reuse it.
|
|
235
|
+
if (id.state.interactiveSessionId === match[1]) {
|
|
236
|
+
id.state.interactiveSessionId = null;
|
|
237
|
+
id.state.interactiveTabId = null;
|
|
238
|
+
}
|
|
239
|
+
if (id.state.affinitySessionId === match[1]) id.state.affinitySessionId = null;
|
|
240
|
+
const refreshed = await resolutionRefresh.run(true, () => resolveSession(
|
|
241
|
+
cached.sessionId, cached.autoCreate, cached.tabId, { platform: cached.platform === true },
|
|
242
|
+
));
|
|
243
|
+
if (!('error' in refreshed)) {
|
|
244
|
+
const nextPath = path.replace(`/sessions/${match[1]}/`, `/sessions/${refreshed.sessionId}/`);
|
|
245
|
+
const nextBody = body ? { ...body, tabId: refreshed.tabId } : undefined;
|
|
246
|
+
const url = new URL(nextPath, BASE_URL);
|
|
247
|
+
if (refreshed.tabId) url.searchParams.set('tabId', refreshed.tabId);
|
|
248
|
+
else url.searchParams.delete('tabId');
|
|
249
|
+
return requestOnce(method, `${url.pathname}${url.search}`, nextBody, timeout);
|
|
250
|
+
}
|
|
251
|
+
// Recovery failed: report why (e.g. "MoreLogin connect failed: …"), not the
|
|
252
|
+
// bare "Session not found" that triggered it. Nothing was started.
|
|
253
|
+
return { ...result, error: refreshed.error, recoveryFailed: true };
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
// The server refused a session that does not serve the default browser (the
|
|
257
|
+
// settings changed under a cached route): forget it, so the next call resolves
|
|
258
|
+
// the default browser. Not retried here: the page the call meant is in the other browser.
|
|
259
|
+
if (result.code === 'NOT_DEFAULT_BROWSER' && match) {
|
|
260
|
+
const id = getIdentity();
|
|
261
|
+
resolvedRoutes.delete(id);
|
|
262
|
+
if (id.state.interactiveSessionId === match[1]) {
|
|
263
|
+
id.state.interactiveSessionId = null;
|
|
264
|
+
id.state.interactiveTabId = null;
|
|
265
|
+
}
|
|
266
|
+
if (id.state.affinitySessionId === match[1]) id.state.affinitySessionId = null;
|
|
267
|
+
}
|
|
268
|
+
if (context && result.error) context.errors.push(result);
|
|
269
|
+
else if (context && typeof result.snapshotError === 'string') {
|
|
270
|
+
context.errors.push({ error: result.snapshotError, code: 'SNAPSHOT_FAILED' });
|
|
271
|
+
}
|
|
272
|
+
return result;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Best-effort reconciliation for an MCP process that changed its own tool
|
|
277
|
+
* profile. Only sidepanel/automation children carry an explicit terminal id;
|
|
278
|
+
* standalone CLI processes stay process-local without contacting Neural
|
|
279
|
+
* Interface. The server derives the owning runtime from X-Synabun-Terminal.
|
|
280
|
+
*/
|
|
281
|
+
export type RuntimeMcpProfileReport = {
|
|
282
|
+
reported: boolean;
|
|
283
|
+
hostRefresh: 'scheduled' | 'notification' | 'not-needed' | 'unavailable';
|
|
284
|
+
runtimeKind?: 'opencode' | 'codex' | 'loop';
|
|
285
|
+
correlationId?: string;
|
|
286
|
+
error?: string;
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
export async function reportRuntimeMcpProfile(
|
|
290
|
+
profile: string,
|
|
291
|
+
options: { catalogMode?: 'profiled' | 'deferred' } = {}
|
|
292
|
+
): Promise<RuntimeMcpProfileReport> {
|
|
293
|
+
if (!String(process.env.SYNABUN_TERMINAL_SESSION || '').trim()) {
|
|
294
|
+
return { reported: false, hostRefresh: 'notification' };
|
|
295
|
+
}
|
|
296
|
+
const result = await request('POST', '/api/mcp/runtime-profile', {
|
|
297
|
+
profile,
|
|
298
|
+
catalogMode: options.catalogMode || 'profiled',
|
|
299
|
+
}, 2_000);
|
|
300
|
+
if (result.ok) {
|
|
301
|
+
const hostRefresh = result.hostRefresh === 'scheduled'
|
|
302
|
+
|| result.hostRefresh === 'notification'
|
|
303
|
+
|| result.hostRefresh === 'not-needed'
|
|
304
|
+
? result.hostRefresh
|
|
305
|
+
: 'unavailable';
|
|
306
|
+
const runtimeKind = result.runtimeKind === 'opencode' || result.runtimeKind === 'codex' || result.runtimeKind === 'loop'
|
|
307
|
+
? result.runtimeKind
|
|
308
|
+
: undefined;
|
|
309
|
+
return {
|
|
310
|
+
reported: true,
|
|
311
|
+
hostRefresh,
|
|
312
|
+
runtimeKind,
|
|
313
|
+
correlationId: typeof result.correlationId === 'string' ? result.correlationId : undefined,
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
return {
|
|
317
|
+
reported: false,
|
|
318
|
+
hostRefresh: 'unavailable',
|
|
319
|
+
error: typeof result.error === 'string' ? result.error : 'Runtime profile report failed',
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// All per-caller identity state (recovery cache, session affinity, interactive
|
|
324
|
+
// tab cache, ancestor-PID pins) lives on the CallerIdentity object resolved by
|
|
325
|
+
// getIdentity() — per HTTP caller over the HTTP transport, a per-process
|
|
326
|
+
// singleton for stdio. Module-level versions of this state were the root cause
|
|
327
|
+
// of cross-automation tab collisions: every HTTP caller shared them.
|
|
328
|
+
|
|
329
|
+
// Join the ONE shared browser with a dedicated, owned tab (instead of launching a
|
|
330
|
+
// second browser on a persistent profile, which fails with "profile is locked").
|
|
331
|
+
async function acquireInteractive(id: CallerIdentity, url?: string): Promise<{ sessionId: string; tabId?: string } | { error: string }> {
|
|
332
|
+
const resp = await request('POST', '/api/browser/acquire', {
|
|
333
|
+
clientId: id.clientId,
|
|
334
|
+
url: url || 'about:blank',
|
|
335
|
+
}, SESSION_CREATE_TIMEOUT);
|
|
336
|
+
if (resp.error || !resp.sessionId) {
|
|
337
|
+
return { error: `Failed to acquire a shared browser tab: ${resp.error || 'no session returned'}` };
|
|
338
|
+
}
|
|
339
|
+
id.state.interactiveSessionId = resp.sessionId as string;
|
|
340
|
+
id.state.interactiveTabId = (resp.tabId as string) || null;
|
|
341
|
+
id.state.affinitySessionId = id.state.interactiveSessionId;
|
|
342
|
+
return { sessionId: id.state.interactiveSessionId, tabId: id.state.interactiveTabId || undefined };
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
function adoptCreatedSession(id: CallerIdentity, created: NiResponse, tabId?: string): { sessionId: string; tabId?: string } {
|
|
346
|
+
const sessionId = created.sessionId as string;
|
|
347
|
+
id.state.affinitySessionId = sessionId;
|
|
348
|
+
return { sessionId, tabId };
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// Pages (localhost included) only run where the server says the default browser
|
|
352
|
+
// is. Absent servesDefault (older server, or a managed / real-Chrome setup) keeps
|
|
353
|
+
// the previous behavior.
|
|
354
|
+
function servesDefault(s: BrowserSessionInfo): boolean {
|
|
355
|
+
return s.servesDefault !== false;
|
|
356
|
+
}
|
|
357
|
+
function describeSession(s: BrowserSessionInfo): string {
|
|
358
|
+
return `${s.profileMode || 'unknown'} mode${s.moreloginEnvId ? `, MoreLogin env ${s.moreloginEnvId}` : ''}`;
|
|
359
|
+
}
|
|
360
|
+
function describeDefault(list: NiResponse): string {
|
|
361
|
+
const def = list.defaultBrowser as { connectMode?: string | null; moreloginEnvId?: string | null } | undefined;
|
|
362
|
+
if (def?.connectMode === 'morelogin') return `MoreLogin${def.moreloginEnvId ? ` env ${def.moreloginEnvId}` : ''}`;
|
|
363
|
+
return 'the configured browser';
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// Best-effort release of an identity's owned tab, so the shared browser can be
|
|
367
|
+
// grace-reaped once no owners remain. Fire-and-forget — never blocks shutdown.
|
|
368
|
+
// Also registered as the identity-eviction hook (HTTP DELETE / idle TTL).
|
|
369
|
+
function releaseTabFor(id: CallerIdentity): void {
|
|
370
|
+
if (!id.state.interactiveSessionId) return;
|
|
371
|
+
try {
|
|
372
|
+
void fetch(`${BASE_URL}/api/browser/release`, {
|
|
373
|
+
method: 'POST',
|
|
374
|
+
headers: { 'Content-Type': 'application/json' },
|
|
375
|
+
body: JSON.stringify({ clientId: id.clientId }),
|
|
376
|
+
}).catch(() => {});
|
|
377
|
+
} catch { /* best-effort */ }
|
|
378
|
+
}
|
|
379
|
+
setReleaseHook(releaseTabFor);
|
|
380
|
+
|
|
381
|
+
// Process exit hooks only matter for stdio (one process per caller). In HTTP
|
|
382
|
+
// mode the NI server hosts many identities — their tabs are released by MCP
|
|
383
|
+
// session DELETE or idle eviction, and an NI shutdown takes the browser with it.
|
|
384
|
+
function releaseOnExit(): void {
|
|
385
|
+
if (isHttpMode()) return;
|
|
386
|
+
const stdio = peekStdioIdentity();
|
|
387
|
+
if (stdio) releaseTabFor(stdio);
|
|
388
|
+
}
|
|
389
|
+
process.once('exit', releaseOnExit);
|
|
390
|
+
|
|
391
|
+
// SIGTERM / SIGINT end a stdio server here: release its tab, exit 0. Served
|
|
392
|
+
// over HTTP, the process belongs to its host. The Neural Interface runs
|
|
393
|
+
// mcp-server/dist in process and owns these signals (server.js
|
|
394
|
+
// gracefulShutdown: WhatsApp Link, terminal host, then the database); this
|
|
395
|
+
// listener is registered before its listeners, so exiting here would preempt
|
|
396
|
+
// all of them. The mode is read when the signal arrives, not at import:
|
|
397
|
+
// server.js loads this module through its static imports, long before
|
|
398
|
+
// createMcpRoutes() calls markHttpMode(). A host with no listener of its own
|
|
399
|
+
// (the standalone dist/http.js) still exits here, because registering this
|
|
400
|
+
// listener already took Node's default exit on the signal away from it.
|
|
401
|
+
function exitOnSignal(signal: 'SIGTERM' | 'SIGINT'): () => void {
|
|
402
|
+
const onSignal = (): void => {
|
|
403
|
+
if (isHttpMode() && process.listeners(signal).some((listener) => listener !== onSignal)) return;
|
|
404
|
+
releaseOnExit();
|
|
405
|
+
process.exit(0);
|
|
406
|
+
};
|
|
407
|
+
return onSignal;
|
|
408
|
+
}
|
|
409
|
+
process.once('SIGTERM', exitOnSignal('SIGTERM'));
|
|
410
|
+
process.once('SIGINT', exitOnSignal('SIGINT'));
|
|
411
|
+
|
|
412
|
+
// Ancestor-PID fallback (Layer B). Walks the process tree once and caches the
|
|
413
|
+
// resolved loop pins on the identity. Used when codex/opencode strip
|
|
414
|
+
// SYNABUN_BROWSER_* env on MCP child spawn — we map our PID chain up to a known
|
|
415
|
+
// PTY and pull the loop's session/tab IDs from that loop's state file.
|
|
416
|
+
// Bounded retry instead of a permanent single-shot latch: a fast codex/opencode
|
|
417
|
+
// exec spawn can call MCP before its PTY is registered server-side, so the first
|
|
418
|
+
// ancestor lookup misses. Retry a few times until matched, then give up.
|
|
419
|
+
const ANCESTOR_MAX_ATTEMPTS = 4;
|
|
420
|
+
|
|
421
|
+
async function getAncestorPids(): Promise<number[]> {
|
|
422
|
+
const ppid = typeof process.ppid === 'number' ? process.ppid : 0;
|
|
423
|
+
if (!ppid) return [];
|
|
424
|
+
const pids: number[] = [ppid];
|
|
425
|
+
const isWin = process.platform === 'win32';
|
|
426
|
+
const { exec } = await import('node:child_process');
|
|
427
|
+
const runCmd = (cmd: string): Promise<string> => new Promise((resolve) => {
|
|
428
|
+
exec(cmd, { timeout: 1500, windowsHide: true }, (_err: unknown, stdout: string) => resolve(stdout || ''));
|
|
429
|
+
});
|
|
430
|
+
let current = ppid;
|
|
431
|
+
for (let i = 0; i < 6; i++) {
|
|
432
|
+
let parent = 0;
|
|
433
|
+
try {
|
|
434
|
+
if (isWin) {
|
|
435
|
+
const out = await runCmd(`wmic process where ProcessId=${current} get ParentProcessId /value`);
|
|
436
|
+
const m = /ParentProcessId=(\d+)/i.exec(out);
|
|
437
|
+
parent = m ? Number(m[1]) : 0;
|
|
438
|
+
} else {
|
|
439
|
+
const out = await runCmd(`ps -o ppid= -p ${current}`);
|
|
440
|
+
parent = Number(out.trim().split(/\s+/)[0]) || 0;
|
|
441
|
+
}
|
|
442
|
+
} catch { parent = 0; }
|
|
443
|
+
if (!parent || parent === 1 || parent === current) break;
|
|
444
|
+
pids.push(parent);
|
|
445
|
+
current = parent;
|
|
446
|
+
}
|
|
447
|
+
return pids;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
async function resolveFromAncestors(id: CallerIdentity): Promise<void> {
|
|
451
|
+
// Over HTTP this code runs in the Neural Interface's own process — walking
|
|
452
|
+
// OUR pid chain would resolve the NI server, not the caller. HTTP callers
|
|
453
|
+
// carry their identity in headers/Mcp-Session-Id instead.
|
|
454
|
+
if (id.source !== 'stdio') return;
|
|
455
|
+
if (id.state.ancestorPinnedSession) return; // already resolved
|
|
456
|
+
if (id.state.ancestorAttempts >= ANCESTOR_MAX_ATTEMPTS) return; // give up after N misses
|
|
457
|
+
id.state.ancestorAttempts++;
|
|
458
|
+
try {
|
|
459
|
+
const pids = await getAncestorPids();
|
|
460
|
+
if (pids.length === 0) return;
|
|
461
|
+
const resp = await request('POST', '/api/loop/resolve-from-ancestors', { pids }, 2000);
|
|
462
|
+
// Capture the owning terminalSessionId whenever a PTY matched (even if its
|
|
463
|
+
// loop file lacked browser pins) — it's needed for the X-Synabun-Terminal header.
|
|
464
|
+
if (resp.terminalSessionId) id.state.ancestorPinnedTerminal = resp.terminalSessionId as string;
|
|
465
|
+
if (resp.matched) {
|
|
466
|
+
id.state.ancestorPinnedSession = (resp.browserSessionId as string) || null;
|
|
467
|
+
id.state.ancestorPinnedTab = (resp.browserTabId as string) || null;
|
|
468
|
+
console.error(`[MCP] ancestor lookup matched: session=${id.state.ancestorPinnedSession} tab=${id.state.ancestorPinnedTab} terminal=${id.state.ancestorPinnedTerminal}`);
|
|
469
|
+
}
|
|
470
|
+
} catch { /* best-effort */ }
|
|
471
|
+
}
|
|
472
|
+
|
|
61
473
|
/**
|
|
62
474
|
* Resolve which session ID to use.
|
|
63
475
|
* - If sessionId provided, return it immediately (server returns 404 if invalid).
|
|
@@ -65,53 +477,286 @@ async function request(
|
|
|
65
477
|
* - If 0 sessions exist and autoCreate is true, create one.
|
|
66
478
|
* - If multiple sessions and no ID, return error listing them.
|
|
67
479
|
*/
|
|
68
|
-
|
|
480
|
+
async function resolveSessionUncached(
|
|
69
481
|
sessionId?: string,
|
|
70
|
-
autoCreate?: { url?: string }
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
482
|
+
autoCreate?: { url?: string },
|
|
483
|
+
tabId?: string,
|
|
484
|
+
platform = false,
|
|
485
|
+
): Promise<{ sessionId: string; tabId?: string } | { error: string }> {
|
|
486
|
+
// Per-caller identity: pins come from launch headers (HTTP) or live env
|
|
487
|
+
// (stdio); all caches below live on the identity, never module-level.
|
|
488
|
+
const id = getIdentity();
|
|
489
|
+
const pins = effectivePins(id);
|
|
490
|
+
// Every page tool runs in the default browser only. An explicit id the server
|
|
491
|
+
// says does not serve it (managed Chrome, or another MoreLogin env while
|
|
492
|
+
// MoreLogin is the default) is dropped for a navigation (localhost included)
|
|
493
|
+
// or a platform tool, and the default browser resolved instead; any other page
|
|
494
|
+
// tool is refused, since the page it names is in the other browser. The
|
|
495
|
+
// server refuses them too (NOT_DEFAULT_BROWSER).
|
|
496
|
+
const wantsDefaultBrowser = platform || !!autoCreate;
|
|
497
|
+
if (sessionId && sessionId !== (pins.browserSessionId || id.state.ancestorPinnedSession)) {
|
|
498
|
+
const listed = await request('GET', '/api/browser/sessions');
|
|
499
|
+
const named = ((listed.sessions || []) as BrowserSessionInfo[]).find(s => s.id === sessionId);
|
|
500
|
+
if (named && !servesDefault(named)) {
|
|
501
|
+
if (!wantsDefaultBrowser) {
|
|
502
|
+
return { error: `Browser session ${sessionId} is not the default browser (${describeSession(named)}; the default is ${describeDefault(listed)}), so SynaBun's browser tools do not act on it. Leave sessionId out: browser_navigate opens the page in the default browser.` };
|
|
503
|
+
}
|
|
504
|
+
console.error(`[MCP] not using session ${sessionId} (${describeSession(named)}) — resolving ${describeDefault(listed)}`);
|
|
505
|
+
sessionId = undefined;
|
|
506
|
+
tabId = undefined;
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
// Resolve tab ID from explicit param or pin.
|
|
511
|
+
// When a tab is pinned (loop/agent context), the pin wins even if the caller
|
|
512
|
+
// passes a different tabId — prevents tab-leak across loops.
|
|
513
|
+
// If pins are missing (codex/opencode env-strip case), try ancestor-PID
|
|
514
|
+
// lookup (stdio only) and use whatever the Neural Interface reports for our PTY.
|
|
515
|
+
if (!pins.browserSessionId && !pins.browserTabId && !sessionId) {
|
|
516
|
+
await resolveFromAncestors(id);
|
|
517
|
+
}
|
|
518
|
+
const pinnedTab = pins.browserTabId || id.state.ancestorPinnedTab || undefined;
|
|
519
|
+
const resolvedTabId = pinnedTab || tabId || undefined;
|
|
520
|
+
if (pinnedTab && tabId && tabId !== pinnedTab) {
|
|
521
|
+
console.error(`[MCP] tabId override ignored: pinned=${pinnedTab} requested=${tabId}`);
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
// Agent/loop-scoped browser session — set by the orchestrator to pin
|
|
525
|
+
// this caller to a specific browser session (multi-session isolation).
|
|
526
|
+
// If pinned session died, check recovery cache first, then auto-create.
|
|
527
|
+
const pinnedSession = pins.browserSessionId || id.state.ancestorPinnedSession || undefined;
|
|
528
|
+
// Loop prompts intentionally pass their injected sessionId/tabId on every
|
|
529
|
+
// call. Treat an explicit session that matches the pin as pinned traffic too;
|
|
530
|
+
// otherwise the old fast path skipped liveness checks and returned a stale
|
|
531
|
+
// tab forever after a renderer/page closed.
|
|
532
|
+
if (pinnedSession && (!sessionId || sessionId === pinnedSession)) {
|
|
533
|
+
// Check recovery cache first — avoids re-creating on every call after recovery.
|
|
534
|
+
// Return the RECOVERED tab, never the stale pinned tab (which 404s).
|
|
535
|
+
if (id.state.recoveredSessionId) {
|
|
536
|
+
const recheck = await request('GET', '/api/browser/sessions');
|
|
537
|
+
const alive = ((recheck.sessions || []) as BrowserSessionInfo[]).find(s => s.id === id.state.recoveredSessionId);
|
|
538
|
+
if (alive) return { sessionId: id.state.recoveredSessionId, tabId: id.state.recoveredTabId || undefined };
|
|
539
|
+
id.state.recoveredSessionId = null; // recovered session also died — try fresh recovery
|
|
540
|
+
id.state.recoveredTabId = null;
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
const check = await request('GET', '/api/browser/sessions');
|
|
544
|
+
const active = ((check.sessions || []) as BrowserSessionInfo[]).find(s => s.id === pinnedSession);
|
|
545
|
+
// A run's pinned browser must be the default one. Hard-fail rather than work
|
|
546
|
+
// in the wrong browser.
|
|
547
|
+
if (active && !servesDefault(active)) {
|
|
548
|
+
return { error: `Pinned browser session ${pinnedSession} is not the default browser (${describeSession(active)}; the default is ${describeDefault(check)}), so this run will not use it. Start the run again so it acquires the default browser.` };
|
|
549
|
+
}
|
|
550
|
+
if (active) {
|
|
551
|
+
// Also verify the resolved tab still exists in the session; if not, recover.
|
|
552
|
+
const tabList = active.tabs;
|
|
553
|
+
const tabAlive = !resolvedTabId || !tabList || tabList.some(t => t.id === resolvedTabId);
|
|
554
|
+
if (tabAlive) return { sessionId: pinnedSession, tabId: resolvedTabId };
|
|
555
|
+
console.error(`[MCP] Pinned tab ${resolvedTabId} not found in active session ${pinnedSession} — recovering`);
|
|
556
|
+
const terminalSessionId = pins.terminalSessionId || undefined;
|
|
557
|
+
const recovered = await request(
|
|
558
|
+
'POST',
|
|
559
|
+
'/api/loop/recover-browser',
|
|
560
|
+
terminalSessionId ? { terminalSessionId } : {},
|
|
561
|
+
SESSION_CREATE_TIMEOUT
|
|
562
|
+
);
|
|
563
|
+
if (!recovered.error && recovered.sessionId) {
|
|
564
|
+
id.state.recoveredSessionId = recovered.sessionId as string;
|
|
565
|
+
id.state.recoveredTabId = (recovered.tabId as string) || null;
|
|
566
|
+
return { sessionId: id.state.recoveredSessionId, tabId: id.state.recoveredTabId || undefined };
|
|
567
|
+
}
|
|
568
|
+
return { sessionId: pinnedSession, tabId: resolvedTabId }; // fall through to old tab (will fail gracefully)
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
// Pinned session is gone — rejoin the SHARED loop browser with a fresh owned
|
|
572
|
+
// tab (not an isolated new browser), and adopt the NEW tabId. Forwarding the
|
|
573
|
+
// stale pinned tab into a different session would 404 every subsequent call.
|
|
574
|
+
console.error(`[MCP] Pinned browser session ${pinnedSession} is gone — recovering via shared loop browser`);
|
|
575
|
+
const terminalSessionId = pins.terminalSessionId || undefined;
|
|
576
|
+
const recovered = await request(
|
|
577
|
+
'POST',
|
|
578
|
+
'/api/loop/recover-browser',
|
|
579
|
+
terminalSessionId ? { terminalSessionId } : {},
|
|
580
|
+
SESSION_CREATE_TIMEOUT
|
|
581
|
+
);
|
|
582
|
+
if (recovered.error || !recovered.sessionId) {
|
|
583
|
+
return { error: `Pinned browser session ${pinnedSession} is no longer available and recovery failed: ${recovered.error || 'no session returned'}` };
|
|
584
|
+
}
|
|
585
|
+
id.state.recoveredSessionId = recovered.sessionId as string;
|
|
586
|
+
id.state.recoveredTabId = (recovered.tabId as string) || null;
|
|
587
|
+
return { sessionId: id.state.recoveredSessionId, tabId: id.state.recoveredTabId || undefined };
|
|
77
588
|
}
|
|
78
589
|
|
|
79
590
|
if (sessionId) {
|
|
80
|
-
//
|
|
81
|
-
//
|
|
82
|
-
|
|
591
|
+
// Checked above against the default browser; the server 404s a session that
|
|
592
|
+
// does not exist. The route cache spares the check on the next calls.
|
|
593
|
+
id.state.affinitySessionId = sessionId;
|
|
594
|
+
return { sessionId, tabId: resolvedTabId };
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
// Reuse the dedicated tab THIS caller already acquired in the shared
|
|
598
|
+
// browser (set by a prior acquireInteractive). The X-Synabun-Terminal header routes
|
|
599
|
+
// tab-less calls to it, but returning the tabId keeps routing robust if the header
|
|
600
|
+
// is ever dropped. Re-acquired below if the underlying session has since died.
|
|
601
|
+
if (!sessionId && id.state.interactiveSessionId) {
|
|
602
|
+
if (isBrowserFastMode()) {
|
|
603
|
+
// Fast mode trusts the cache without a verify round-trip.
|
|
604
|
+
return { sessionId: id.state.interactiveSessionId, tabId: resolvedTabId || id.state.interactiveTabId || undefined };
|
|
605
|
+
}
|
|
606
|
+
const check = await request('GET', '/api/browser/sessions');
|
|
607
|
+
const alive = ((check.sessions || []) as BrowserSessionInfo[]).find(s => s.id === id.state.interactiveSessionId);
|
|
608
|
+
if (alive && servesDefault(alive)) return { sessionId: id.state.interactiveSessionId, tabId: resolvedTabId || id.state.interactiveTabId || undefined };
|
|
609
|
+
id.state.interactiveSessionId = null;
|
|
610
|
+
id.state.interactiveTabId = null; // session gone — fall through to re-acquire
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
// Codex fast mode favors one direct create call on first navigate. This avoids
|
|
614
|
+
// the list-sessions round trip that dominates short browser flows. If the profile
|
|
615
|
+
// is persistent, a second launchPersistentContext fails with "profile is locked" —
|
|
616
|
+
// fall back to acquiring a dedicated tab in the shared browser instead.
|
|
617
|
+
if (autoCreate && isBrowserFastMode()) {
|
|
618
|
+
const created = await request('POST', '/api/browser/sessions', {
|
|
619
|
+
url: autoCreate.url || 'about:blank',
|
|
620
|
+
}, SESSION_CREATE_TIMEOUT);
|
|
621
|
+
if (created.error) {
|
|
622
|
+
if (/lock/i.test(created.error)) return acquireInteractive(id, autoCreate.url);
|
|
623
|
+
return { error: `Failed to auto-create session: ${created.error}` };
|
|
624
|
+
}
|
|
625
|
+
return adoptCreatedSession(id, created, resolvedTabId);
|
|
83
626
|
}
|
|
84
627
|
|
|
85
|
-
// List sessions
|
|
628
|
+
// List sessions (single GET used for both affinity check and auto-selection)
|
|
86
629
|
const data = await request('GET', '/api/browser/sessions');
|
|
87
630
|
if (data.error) return { error: data.error };
|
|
88
|
-
const
|
|
631
|
+
const allSessions = (data.sessions || []) as BrowserSessionInfo[];
|
|
632
|
+
|
|
633
|
+
// Check affinity — reuse session this caller previously used/created
|
|
634
|
+
if (id.state.affinitySessionId) {
|
|
635
|
+
const affinityAlive = allSessions.find(s => s.id === id.state.affinitySessionId);
|
|
636
|
+
if (affinityAlive && servesDefault(affinityAlive)) {
|
|
637
|
+
return { sessionId: id.state.affinitySessionId, tabId: resolvedTabId };
|
|
638
|
+
}
|
|
639
|
+
id.state.affinitySessionId = null; // session gone (or not the default browser), clear affinity
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
// Interactive sessions (no pinned env var) must not grab loop/agent/interactive-owned
|
|
643
|
+
// sessions. Pinned sessions already returned above; explicit sessionId trusted above.
|
|
644
|
+
// Never adopt or auto-select a browser that is not the default one for normal pages.
|
|
645
|
+
const sessions = allSessions.filter(s => !s.loopOwned && !s.agentOwned && !s.interactiveOwned && servesDefault(s));
|
|
646
|
+
|
|
647
|
+
// Under a persistent profile, a second launchPersistentContext fails with "profile is
|
|
648
|
+
// locked", and any owned session means a shared persistent browser is already running.
|
|
649
|
+
// In those cases, don't try to spawn a separate browser — join the ONE shared browser
|
|
650
|
+
// with a dedicated, owned tab. For a clean profile with no owners, keep the historical
|
|
651
|
+
// separate-browser behavior (no lock, no regression).
|
|
652
|
+
const lockRisk = allSessions.some(s => s.persistent || s.loopOwned || s.agentOwned || s.interactiveOwned);
|
|
653
|
+
const autoCreateSession = async (): Promise<{ sessionId: string; tabId?: string } | { error: string }> => {
|
|
654
|
+
if (lockRisk) return acquireInteractive(id, autoCreate?.url);
|
|
655
|
+
const created = await request('POST', '/api/browser/sessions', {
|
|
656
|
+
url: autoCreate?.url || 'about:blank',
|
|
657
|
+
}, SESSION_CREATE_TIMEOUT);
|
|
658
|
+
if (created.error) {
|
|
659
|
+
if (/lock/i.test(created.error)) return acquireInteractive(id, autoCreate?.url);
|
|
660
|
+
return { error: `Failed to auto-create session: ${created.error}` };
|
|
661
|
+
}
|
|
662
|
+
return adoptCreatedSession(id, created, resolvedTabId);
|
|
663
|
+
};
|
|
664
|
+
|
|
665
|
+
// If autoCreate is available (browser_navigate) and unowned sessions exist but none
|
|
666
|
+
// are ours (no affinity), create/acquire our own instead of hijacking another caller's.
|
|
667
|
+
// This prevents sidepanel from grabbing the CLI's session and vice versa.
|
|
668
|
+
if (sessions.length > 0 && autoCreate) {
|
|
669
|
+
return autoCreateSession();
|
|
670
|
+
}
|
|
89
671
|
|
|
90
672
|
if (sessions.length === 1) {
|
|
91
|
-
|
|
673
|
+
// No autoCreate — caller wants to interact with an existing page (click, snapshot, etc.).
|
|
674
|
+
// Adopting is ONLY safe for a pristine, unowned session (e.g. a page the user opened
|
|
675
|
+
// manually in the NI UI). If ANOTHER automation already owns a tab here (it plain-created
|
|
676
|
+
// the session or acquired a tab — see _tabOwners), adopting makes us a tab-less freeloader
|
|
677
|
+
// that FAILS CLOSED (404) the moment the session goes multi-tab — the sidepanel-vs-CLI
|
|
678
|
+
// collision. In that case acquire our OWN dedicated tab in the shared browser instead.
|
|
679
|
+
const myTerminalId = terminalIdFor(id);
|
|
680
|
+
const loneOwners = sessions[0].tabOwners || {};
|
|
681
|
+
const ownedByOther = Object.keys(loneOwners).some(k => k !== id.clientId && k !== myTerminalId);
|
|
682
|
+
if (ownedByOther) {
|
|
683
|
+
return acquireInteractive(id, autoCreate?.url);
|
|
684
|
+
}
|
|
685
|
+
id.state.affinitySessionId = sessions[0].id;
|
|
686
|
+
return { sessionId: sessions[0].id, tabId: resolvedTabId };
|
|
92
687
|
}
|
|
93
688
|
|
|
94
689
|
if (sessions.length === 0) {
|
|
95
690
|
if (autoCreate) {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
691
|
+
return autoCreateSession();
|
|
692
|
+
}
|
|
693
|
+
const ownedCount = allSessions.length - sessions.length;
|
|
694
|
+
if (ownedCount > 0) {
|
|
695
|
+
// Active automations hold the shared browser and there is no unowned session for
|
|
696
|
+
// us. Don't grab their tab and don't error — acquire our OWN dedicated tab so even
|
|
697
|
+
// a tab-less first tool (snapshot/click) is isolated. about:blank is fine; a later
|
|
698
|
+
// navigate reuses this same owned tab via the X-Synabun-Terminal routing.
|
|
699
|
+
return acquireInteractive(id, undefined);
|
|
101
700
|
}
|
|
102
701
|
return { error: 'No browser sessions open. Use browser_session to create one first, or use browser_navigate with a URL to auto-create.' };
|
|
103
702
|
}
|
|
104
703
|
|
|
105
|
-
// Multiple sessions — require explicit ID
|
|
704
|
+
// Multiple available sessions — require explicit ID
|
|
106
705
|
const list = sessions.map(s => ` ${s.id} — ${s.title || s.url}`).join('\n');
|
|
107
706
|
return { error: `Multiple browser sessions open. Specify sessionId:\n${list}` };
|
|
108
707
|
}
|
|
109
708
|
|
|
709
|
+
/**
|
|
710
|
+
* Per-caller route cache. Only the server can declare an action safe to retry.
|
|
711
|
+
* `platform` (or a withPlatformRoute scope) marks a platform tool call: like a
|
|
712
|
+
* navigation, it only runs in the default browser.
|
|
713
|
+
*/
|
|
714
|
+
export async function resolveSession(
|
|
715
|
+
sessionId?: string,
|
|
716
|
+
autoCreate?: { url?: string },
|
|
717
|
+
tabId?: string,
|
|
718
|
+
opts: { platform?: boolean } = {},
|
|
719
|
+
): Promise<BrowserRoute | { error: string }> {
|
|
720
|
+
const context = batchContext.getStore();
|
|
721
|
+
if (context) return context.route;
|
|
722
|
+
const startedAt = performance.now();
|
|
723
|
+
const id = getIdentity();
|
|
724
|
+
const platform = opts.platform === true || inPlatformRoute();
|
|
725
|
+
const key = routeKey(id, sessionId, tabId, platform || !!autoCreate);
|
|
726
|
+
const cached = resolvedRoutes.get(id);
|
|
727
|
+
if (isBrowserV2Enabled() && !resolutionRefresh.getStore() && cached?.key === key) {
|
|
728
|
+
browserMetric({ phase: 'session-resolution', cached: true, durationMs: performance.now() - startedAt });
|
|
729
|
+
return { ...cached.route };
|
|
730
|
+
}
|
|
731
|
+
const result = await resolveSessionUncached(sessionId, autoCreate, tabId, platform);
|
|
732
|
+
if (!('error' in result)) resolvedRoutes.set(id, { key: routeKey(id, sessionId, tabId, platform || !!autoCreate), route: { ...result }, sessionId, tabId, autoCreate, platform });
|
|
733
|
+
browserMetric({ phase: 'session-resolution', cached: false, durationMs: performance.now() - startedAt });
|
|
734
|
+
return result;
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
/** Batches require a concrete tab owned by this caller, verified once up front. */
|
|
738
|
+
export async function resolveBatchRoute(sessionId?: string, tabId?: string): Promise<BrowserRoute | { error: string }> {
|
|
739
|
+
const resolved = await resolveSession(sessionId, undefined, tabId);
|
|
740
|
+
if ('error' in resolved) return resolved;
|
|
741
|
+
const result = await listSessions();
|
|
742
|
+
if (result.error) return { error: result.error };
|
|
743
|
+
const session = (result.sessions as BrowserSessionInfo[] | undefined)?.find(s => s.id === resolved.sessionId);
|
|
744
|
+
const id = getIdentity();
|
|
745
|
+
const ownedTabs = [session?.tabOwners?.[terminalIdFor(id)], session?.tabOwners?.[id.clientId]].filter(Boolean);
|
|
746
|
+
const ownedTab = resolved.tabId || ownedTabs[0];
|
|
747
|
+
if (!ownedTab || !ownedTabs.includes(ownedTab)) {
|
|
748
|
+
return { error: 'browser_batch requires a tab owned by this caller. Use browser_navigate to acquire a tab first.' };
|
|
749
|
+
}
|
|
750
|
+
return { sessionId: resolved.sessionId, tabId: ownedTab };
|
|
751
|
+
}
|
|
752
|
+
|
|
110
753
|
// ── Cache invalidation ──
|
|
111
754
|
|
|
112
|
-
export async function invalidateCache(reason: string): Promise<void> {
|
|
755
|
+
export async function invalidateCache(reason: string, id?: string): Promise<void> {
|
|
113
756
|
try {
|
|
114
|
-
|
|
757
|
+
// Passing the changed memory id lets the NI patch its link cache
|
|
758
|
+
// incrementally instead of recomputing all pairwise links.
|
|
759
|
+
await request('POST', '/api/cache/invalidate', { reason, id });
|
|
115
760
|
} catch {
|
|
116
761
|
// Fire-and-forget — don't block MCP tools if Neural Interface is down
|
|
117
762
|
}
|
|
@@ -126,7 +771,7 @@ export async function listSessions(): Promise<NiResponse> {
|
|
|
126
771
|
export async function createSession(url?: string): Promise<NiResponse> {
|
|
127
772
|
return request('POST', '/api/browser/sessions', {
|
|
128
773
|
url: url || 'about:blank',
|
|
129
|
-
});
|
|
774
|
+
}, SESSION_CREATE_TIMEOUT);
|
|
130
775
|
}
|
|
131
776
|
|
|
132
777
|
export async function closeSession(sessionId: string): Promise<NiResponse> {
|
|
@@ -135,104 +780,300 @@ export async function closeSession(sessionId: string): Promise<NiResponse> {
|
|
|
135
780
|
|
|
136
781
|
// ── Navigation ──
|
|
137
782
|
|
|
138
|
-
export async function navigate(
|
|
139
|
-
|
|
783
|
+
export async function navigate(
|
|
784
|
+
sessionId: string,
|
|
785
|
+
url: string,
|
|
786
|
+
tabId?: string,
|
|
787
|
+
returnSnapshot?: { mode?: string; selector?: string; viewport?: boolean },
|
|
788
|
+
snapshot?: 'diff' | 'full' | 'none',
|
|
789
|
+
snapshotOptions?: { baselineId?: string; snapshotMaxChars?: number },
|
|
790
|
+
assist?: { semanticContext?: boolean },
|
|
791
|
+
): Promise<NiResponse> {
|
|
792
|
+
return request('POST', `/api/browser/sessions/${sessionId}/navigate`, {
|
|
793
|
+
url,
|
|
794
|
+
...(isBrowserCompactMode() && { compact: true }),
|
|
795
|
+
...(snapshot && { snapshot }),
|
|
796
|
+
...(isBrowserV2Enabled() && { snapshotMaxChars: 12000 }),
|
|
797
|
+
...snapshotOptions,
|
|
798
|
+
...(returnSnapshot && { returnSnapshot }),
|
|
799
|
+
...(assist?.semanticContext && { semanticContext: true }),
|
|
800
|
+
...(tabId && { tabId }),
|
|
801
|
+
}, LONG_TIMEOUT);
|
|
140
802
|
}
|
|
141
803
|
|
|
142
|
-
export async function goBack(sessionId: string): Promise<NiResponse> {
|
|
143
|
-
return request('POST', `/api/browser/sessions/${sessionId}/back
|
|
804
|
+
export async function goBack(sessionId: string, tabId?: string): Promise<NiResponse> {
|
|
805
|
+
return request('POST', `/api/browser/sessions/${sessionId}/back`, { ...(isBrowserCompactMode() && { compact: true }), ...(tabId && { tabId }) });
|
|
144
806
|
}
|
|
145
807
|
|
|
146
|
-
export async function goForward(sessionId: string): Promise<NiResponse> {
|
|
147
|
-
return request('POST', `/api/browser/sessions/${sessionId}/forward
|
|
808
|
+
export async function goForward(sessionId: string, tabId?: string): Promise<NiResponse> {
|
|
809
|
+
return request('POST', `/api/browser/sessions/${sessionId}/forward`, { ...(isBrowserCompactMode() && { compact: true }), ...(tabId && { tabId }) });
|
|
148
810
|
}
|
|
149
811
|
|
|
150
|
-
export async function reload(sessionId: string): Promise<NiResponse> {
|
|
151
|
-
return request('POST', `/api/browser/sessions/${sessionId}/reload`,
|
|
812
|
+
export async function reload(sessionId: string, tabId?: string): Promise<NiResponse> {
|
|
813
|
+
return request('POST', `/api/browser/sessions/${sessionId}/reload`, { ...(isBrowserCompactMode() && { compact: true }), ...(tabId && { tabId }) }, LONG_TIMEOUT);
|
|
152
814
|
}
|
|
153
815
|
|
|
154
|
-
// ── Interaction (selector-based) ──
|
|
816
|
+
// ── Interaction (ref- or selector-based) ──
|
|
155
817
|
|
|
156
|
-
export async function click(
|
|
157
|
-
|
|
818
|
+
export async function click(
|
|
819
|
+
sessionId: string,
|
|
820
|
+
selector: string | undefined,
|
|
821
|
+
nthMatch?: number,
|
|
822
|
+
tabId?: string,
|
|
823
|
+
textHint?: string,
|
|
824
|
+
returnSnapshot?: { mode?: string; selector?: string; viewport?: boolean },
|
|
825
|
+
ref?: string,
|
|
826
|
+
snapshot?: 'diff' | 'full' | 'none',
|
|
827
|
+
snapshotOptions?: { baselineId?: string; snapshotMaxChars?: number },
|
|
828
|
+
assist?: boolean,
|
|
829
|
+
): Promise<NiResponse> {
|
|
830
|
+
return request('POST', `/api/browser/sessions/${sessionId}/click`, {
|
|
831
|
+
...(selector && { selector }),
|
|
832
|
+
...(ref && { ref }),
|
|
833
|
+
...(nthMatch !== undefined && { nthMatch }),
|
|
834
|
+
...(textHint && { textHint }),
|
|
835
|
+
...(assist && { assist: true }),
|
|
836
|
+
...(isBrowserCompactMode() && { compact: true }),
|
|
837
|
+
...(snapshot && { snapshot }),
|
|
838
|
+
...(isBrowserV2Enabled() && { snapshotMaxChars: 6000 }),
|
|
839
|
+
...snapshotOptions,
|
|
840
|
+
...(returnSnapshot && { returnSnapshot }),
|
|
841
|
+
...(tabId && { tabId }),
|
|
842
|
+
}, CLICK_TIMEOUT);
|
|
158
843
|
}
|
|
159
844
|
|
|
160
|
-
export async function fill(sessionId: string, selector: string, value: string, nthMatch?: number): Promise<NiResponse> {
|
|
161
|
-
return request('POST', `/api/browser/sessions/${sessionId}/fill`, { selector, value, ...(nthMatch !== undefined && { nthMatch }) });
|
|
845
|
+
export async function fill(sessionId: string, selector: string | undefined, value: string, nthMatch?: number, tabId?: string, textHint?: string, ref?: string, assist?: boolean): Promise<NiResponse> {
|
|
846
|
+
return request('POST', `/api/browser/sessions/${sessionId}/fill`, { ...(selector && { selector }), ...(ref && { ref }), value, ...(assist && { assist: true }), ...(nthMatch !== undefined && { nthMatch }), ...(textHint && { textHint }), ...(isBrowserCompactMode() && { compact: true }), ...(tabId && { tabId }) });
|
|
162
847
|
}
|
|
163
848
|
|
|
164
|
-
export async function type(sessionId: string, selector: string | null, text: string, nthMatch?: number): Promise<NiResponse> {
|
|
165
|
-
|
|
849
|
+
export async function type(sessionId: string, selector: string | null, text: string, nthMatch?: number, tabId?: string, textHint?: string, mode?: 'sequential' | 'insert' | 'paragraphs', ref?: string, assist?: boolean): Promise<NiResponse> {
|
|
850
|
+
// An explicit mode (including 'paragraphs') is always honored; only the unset case falls back to fast-mode insert.
|
|
851
|
+
const resolvedMode = mode || (isBrowserFastMode() ? 'insert' : 'sequential');
|
|
852
|
+
return request('POST', `/api/browser/sessions/${sessionId}/type`, { selector, ...(ref && { ref }), text, mode: resolvedMode, ...(assist && { assist: true }), ...(nthMatch !== undefined && { nthMatch }), ...(textHint && { textHint }), ...(isBrowserCompactMode() && { compact: true }), ...(tabId && { tabId }) });
|
|
166
853
|
}
|
|
167
854
|
|
|
168
|
-
export async function hover(sessionId: string, selector: string, nthMatch?: number): Promise<NiResponse> {
|
|
169
|
-
return request('POST', `/api/browser/sessions/${sessionId}/hover`, { selector, ...(nthMatch !== undefined && { nthMatch }) });
|
|
855
|
+
export async function hover(sessionId: string, selector: string | undefined, nthMatch?: number, tabId?: string, textHint?: string, ref?: string, assist?: boolean): Promise<NiResponse> {
|
|
856
|
+
return request('POST', `/api/browser/sessions/${sessionId}/hover`, { ...(selector && { selector }), ...(ref && { ref }), ...(assist && { assist: true }), ...(nthMatch !== undefined && { nthMatch }), ...(textHint && { textHint }), ...(isBrowserCompactMode() && { compact: true }), ...(tabId && { tabId }) });
|
|
170
857
|
}
|
|
171
858
|
|
|
172
|
-
export async function selectOption(sessionId: string, selector: string, value: string, nthMatch?: number): Promise<NiResponse> {
|
|
173
|
-
return request('POST', `/api/browser/sessions/${sessionId}/select`, { selector, value, ...(nthMatch !== undefined && { nthMatch }) });
|
|
859
|
+
export async function selectOption(sessionId: string, selector: string | undefined, value: string, nthMatch?: number, tabId?: string, ref?: string, textHint?: string, assist?: boolean): Promise<NiResponse> {
|
|
860
|
+
return request('POST', `/api/browser/sessions/${sessionId}/select`, { ...(selector && { selector }), ...(ref && { ref }), value, ...(textHint && { textHint }), ...(assist && { assist: true }), ...(nthMatch !== undefined && { nthMatch }), ...(isBrowserCompactMode() && { compact: true }), ...(tabId && { tabId }) });
|
|
174
861
|
}
|
|
175
862
|
|
|
176
|
-
export async function pressKey(sessionId: string, key: string): Promise<NiResponse> {
|
|
177
|
-
return request('POST', `/api/browser/sessions/${sessionId}/press`, { key });
|
|
863
|
+
export async function pressKey(sessionId: string, key: string, tabId?: string): Promise<NiResponse> {
|
|
864
|
+
return request('POST', `/api/browser/sessions/${sessionId}/press`, { key, ...(isBrowserCompactMode() && { compact: true }), ...(tabId && { tabId }) });
|
|
178
865
|
}
|
|
179
866
|
|
|
180
867
|
export async function scroll(
|
|
181
868
|
sessionId: string,
|
|
182
|
-
opts: { direction: string; distance?: number; selector?: string }
|
|
869
|
+
opts: { direction: string; distance?: number; selector?: string; ref?: string; snapshot?: 'diff' | 'full' | 'none'; baselineId?: string; snapshotMaxChars?: number; returnSnapshot?: { mode?: string; selector?: string; viewport?: boolean } },
|
|
870
|
+
tabId?: string
|
|
183
871
|
): Promise<NiResponse> {
|
|
184
|
-
return request('POST', `/api/browser/sessions/${sessionId}/scroll`, opts as Record<string, unknown
|
|
872
|
+
return request('POST', `/api/browser/sessions/${sessionId}/scroll`, { ...(isBrowserV2Enabled() && { snapshotMaxChars: 12000 }), ...opts, ...(isBrowserCompactMode() && { compact: true }), ...(tabId && { tabId }) } as Record<string, unknown>, LONG_TIMEOUT);
|
|
185
873
|
}
|
|
186
874
|
|
|
187
875
|
export async function upload(
|
|
188
876
|
sessionId: string,
|
|
189
|
-
selector: string,
|
|
877
|
+
selector: string | undefined,
|
|
190
878
|
filePaths: string[],
|
|
191
|
-
nthMatch?: number
|
|
879
|
+
nthMatch?: number,
|
|
880
|
+
tabId?: string,
|
|
881
|
+
ref?: string,
|
|
882
|
+
textHint?: string,
|
|
883
|
+
assist?: boolean,
|
|
192
884
|
): Promise<NiResponse> {
|
|
193
|
-
return request('POST', `/api/browser/sessions/${sessionId}/upload`, { selector, filePaths, ...(nthMatch !== undefined && { nthMatch }) }, LONG_TIMEOUT);
|
|
885
|
+
return request('POST', `/api/browser/sessions/${sessionId}/upload`, { ...(selector && { selector }), ...(ref && { ref }), filePaths, ...(textHint && { textHint }), ...(assist && { assist: true }), ...(nthMatch !== undefined && { nthMatch }), ...(isBrowserCompactMode() && { compact: true }), ...(tabId && { tabId }) }, LONG_TIMEOUT);
|
|
194
886
|
}
|
|
195
887
|
|
|
196
888
|
// ── Observation ──
|
|
197
889
|
|
|
198
|
-
export async function snapshot(
|
|
199
|
-
|
|
200
|
-
|
|
890
|
+
export async function snapshot(
|
|
891
|
+
sessionId: string,
|
|
892
|
+
selector?: string,
|
|
893
|
+
tabId?: string,
|
|
894
|
+
opts?: { mode?: string; viewport?: boolean; depth?: number; diff?: boolean; force?: boolean; maxChars?: number; baselineId?: string; includeFullText?: boolean }
|
|
895
|
+
): Promise<NiResponse> {
|
|
896
|
+
const hasOpts = !!(opts && (opts.mode || opts.viewport || opts.depth || opts.diff || opts.force || opts.maxChars || opts.baselineId || opts.includeFullText));
|
|
897
|
+
// Always POST when selector OR opts present (POST supports a body); GET only for bare defaults.
|
|
898
|
+
if (selector || hasOpts) {
|
|
899
|
+
return request('POST', `/api/browser/sessions/${sessionId}/snapshot`, {
|
|
900
|
+
...(selector && { selector }),
|
|
901
|
+
...(opts?.mode && { mode: opts.mode }),
|
|
902
|
+
...(opts?.viewport && { viewport: true }),
|
|
903
|
+
...(opts?.depth && { depth: opts.depth }),
|
|
904
|
+
...(opts?.diff && { diff: true }),
|
|
905
|
+
...(opts?.force && { force: true }),
|
|
906
|
+
...(opts?.maxChars && { maxChars: opts.maxChars }),
|
|
907
|
+
...(opts?.baselineId && { baselineId: opts.baselineId }),
|
|
908
|
+
// Intent ranking parses every ref of this capture even when only a diff is shown; never a second capture.
|
|
909
|
+
...(opts?.includeFullText && { includeFullText: true }),
|
|
910
|
+
...(tabId && { tabId }),
|
|
911
|
+
}, LONG_TIMEOUT);
|
|
912
|
+
}
|
|
913
|
+
const qs = tabId ? `?tabId=${tabId}` : '';
|
|
914
|
+
return request('GET', `/api/browser/sessions/${sessionId}/snapshot${qs}`);
|
|
201
915
|
}
|
|
202
916
|
|
|
203
|
-
export async function getContent(sessionId: string): Promise<NiResponse> {
|
|
204
|
-
|
|
917
|
+
export async function getContent(sessionId: string, tabId?: string, opts?: { maxChars?: number; offset?: number; selector?: string }): Promise<NiResponse> {
|
|
918
|
+
const params = new URLSearchParams();
|
|
919
|
+
if (tabId) params.set('tabId', tabId);
|
|
920
|
+
if (opts?.maxChars) params.set('maxChars', String(opts.maxChars));
|
|
921
|
+
if (opts?.offset) params.set('offset', String(opts.offset));
|
|
922
|
+
if (opts?.selector) params.set('selector', opts.selector);
|
|
923
|
+
const qs = params.size ? `?${params}` : '';
|
|
924
|
+
return request('GET', `/api/browser/sessions/${sessionId}/content${qs}`);
|
|
205
925
|
}
|
|
206
926
|
|
|
207
|
-
export async function getMarkdown(sessionId: string): Promise<NiResponse> {
|
|
208
|
-
|
|
927
|
+
export async function getMarkdown(sessionId: string, tabId?: string, opts?: { maxChars?: number; offset?: number; selector?: string }): Promise<NiResponse> {
|
|
928
|
+
const params = new URLSearchParams();
|
|
929
|
+
if (tabId) params.set('tabId', tabId);
|
|
930
|
+
if (opts?.maxChars) params.set('maxChars', String(opts.maxChars));
|
|
931
|
+
if (opts?.offset) params.set('offset', String(opts.offset));
|
|
932
|
+
if (opts?.selector) params.set('selector', opts.selector);
|
|
933
|
+
const qs = params.size ? `?${params}` : '';
|
|
934
|
+
return request('GET', `/api/browser/sessions/${sessionId}/markdown${qs}`, undefined, LONG_TIMEOUT);
|
|
209
935
|
}
|
|
210
936
|
|
|
211
937
|
export async function fetchMarkdown(url: string, timeout?: number): Promise<NiResponse> {
|
|
212
938
|
return request('POST', '/api/fetch-markdown', { url, timeout }, LONG_TIMEOUT);
|
|
213
939
|
}
|
|
214
940
|
|
|
215
|
-
export
|
|
216
|
-
|
|
941
|
+
export interface ScreenshotOptions {
|
|
942
|
+
maxWidth?: number;
|
|
943
|
+
quality?: number;
|
|
944
|
+
/** Viewport size for this capture only (CDP device metrics, cleared right after). */
|
|
945
|
+
width?: number;
|
|
946
|
+
height?: number;
|
|
947
|
+
fullPage?: boolean;
|
|
948
|
+
format?: 'png' | 'jpeg';
|
|
949
|
+
save?: boolean;
|
|
950
|
+
path?: string;
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
export async function screenshot(sessionId: string, tabId?: string, opts?: ScreenshotOptions): Promise<NiResponse> {
|
|
954
|
+
const params = new URLSearchParams();
|
|
955
|
+
if (tabId) params.set('tabId', tabId);
|
|
956
|
+
if (opts?.maxWidth !== undefined) params.set('maxWidth', String(opts.maxWidth));
|
|
957
|
+
if (opts?.quality !== undefined) params.set('quality', String(opts.quality));
|
|
958
|
+
if (opts?.width !== undefined) params.set('width', String(opts.width));
|
|
959
|
+
if (opts?.height !== undefined) params.set('height', String(opts.height));
|
|
960
|
+
if (opts?.fullPage) params.set('fullPage', '1');
|
|
961
|
+
if (opts?.format) params.set('format', opts.format);
|
|
962
|
+
if (opts?.save) params.set('save', '1');
|
|
963
|
+
if (opts?.path) params.set('path', opts.path);
|
|
964
|
+
const qs = params.size ? `?${params}` : '';
|
|
965
|
+
// A resized or full-page capture (and a saved file) takes longer than a plain one.
|
|
966
|
+
return request('GET', `/api/browser/sessions/${sessionId}/screenshot-base64${qs}`, undefined, LONG_TIMEOUT);
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
/** The tab's buffered console messages and page errors (browser_console). */
|
|
970
|
+
export async function consoleMessages(
|
|
971
|
+
sessionId: string,
|
|
972
|
+
tabId?: string,
|
|
973
|
+
opts?: { level?: string; since?: string; limit?: number; clear?: boolean },
|
|
974
|
+
): Promise<NiResponse> {
|
|
975
|
+
const params = new URLSearchParams();
|
|
976
|
+
if (tabId) params.set('tabId', tabId);
|
|
977
|
+
if (opts?.level) params.set('level', opts.level);
|
|
978
|
+
if (opts?.since) params.set('since', opts.since);
|
|
979
|
+
if (opts?.limit !== undefined) params.set('limit', String(opts.limit));
|
|
980
|
+
if (opts?.clear) params.set('clear', '1');
|
|
981
|
+
const qs = params.size ? `?${params}` : '';
|
|
982
|
+
return request('GET', `/api/browser/sessions/${sessionId}/console${qs}`);
|
|
217
983
|
}
|
|
218
984
|
|
|
219
985
|
// ── Advanced ──
|
|
220
986
|
|
|
221
|
-
export async function evaluate(sessionId: string, script: string): Promise<NiResponse> {
|
|
222
|
-
return request('POST', `/api/browser/sessions/${sessionId}/evaluate`, { script }, LONG_TIMEOUT);
|
|
987
|
+
export async function evaluate(sessionId: string, script: string, tabId?: string): Promise<NiResponse> {
|
|
988
|
+
return request('POST', `/api/browser/sessions/${sessionId}/evaluate`, { script, ...(tabId && { tabId }) }, LONG_TIMEOUT);
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
export interface BrowserExtractOptions {
|
|
992
|
+
scrolls?: number;
|
|
993
|
+
minItems?: number;
|
|
994
|
+
maxItems?: number;
|
|
995
|
+
dedupeKeys: string[];
|
|
996
|
+
scrollTarget?: string;
|
|
997
|
+
scrollDistance?: number;
|
|
998
|
+
scrollDirection?: 1 | -1;
|
|
999
|
+
settleMs?: number;
|
|
1000
|
+
scrollIfEmpty?: boolean;
|
|
1001
|
+
fields?: string[];
|
|
1002
|
+
maxChars?: number;
|
|
1003
|
+
timeoutMs?: number;
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
export async function extract(sessionId: string, script: string, tabId: string | undefined, opts: BrowserExtractOptions): Promise<NiResponse> {
|
|
1007
|
+
return request('POST', `/api/browser/sessions/${sessionId}/extract`, {
|
|
1008
|
+
script, ...opts, ...(tabId && { tabId }),
|
|
1009
|
+
}, Math.min(30_000, opts.timeoutMs || 15_000) + 2_000);
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
// Read-only structured state of the X/Twitter composer (quote card, submit button, modal,
|
|
1013
|
+
// stale draft). The detection script lives server-side so the loop publish gate shares it.
|
|
1014
|
+
export async function xComposeState(sessionId: string, tabId?: string): Promise<NiResponse> {
|
|
1015
|
+
return request('POST', `/api/browser/sessions/${sessionId}/x-compose-state`, { ...(tabId && { tabId }) }, LONG_TIMEOUT);
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
// ── Browser assistance (read-only context; the judgments run in this process, never in the Neural Interface) ──
|
|
1019
|
+
|
|
1020
|
+
/** Bounded, value-free description of the current page. Read-only: safe to call after any outcome. */
|
|
1021
|
+
export async function semanticContext(
|
|
1022
|
+
sessionId: string,
|
|
1023
|
+
tabId?: string,
|
|
1024
|
+
opts?: { purpose?: 'page-state' | 'empty-extractor' | 'social' | 'batch'; scope?: string; social?: boolean },
|
|
1025
|
+
): Promise<NiResponse> {
|
|
1026
|
+
return request('POST', `/api/browser/sessions/${sessionId}/semantic-context`, {
|
|
1027
|
+
...(opts?.purpose && { purpose: opts.purpose }),
|
|
1028
|
+
...(opts?.scope && { scope: opts.scope }),
|
|
1029
|
+
...(opts?.social && { social: true }),
|
|
1030
|
+
...(tabId && { tabId }),
|
|
1031
|
+
}, 6000);
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
/**
|
|
1035
|
+
* The one auto-heal click. It names a candidate inside a context the server
|
|
1036
|
+
* minted after a click it confirmed never started; the selector and the
|
|
1037
|
+
* fingerprint stay on the server. Deliberately `requestOnce`: route recovery
|
|
1038
|
+
* could re-issue this on another tab, and a heal is never sent twice.
|
|
1039
|
+
*/
|
|
1040
|
+
export async function clickAutoHeal(
|
|
1041
|
+
sessionId: string,
|
|
1042
|
+
tabId: string | undefined,
|
|
1043
|
+
pick: { contextId: string; candidateId: string },
|
|
1044
|
+
snapshot?: 'diff' | 'full' | 'none',
|
|
1045
|
+
): Promise<NiResponse> {
|
|
1046
|
+
return requestOnce('POST', `/api/browser/sessions/${sessionId}/click`, {
|
|
1047
|
+
autoHeal: { contextId: pick.contextId, candidateId: pick.candidateId },
|
|
1048
|
+
...(isBrowserCompactMode() && { compact: true }),
|
|
1049
|
+
...(snapshot && { snapshot }),
|
|
1050
|
+
...(isBrowserV2Enabled() && { snapshotMaxChars: 6000 }),
|
|
1051
|
+
...(tabId && { tabId }),
|
|
1052
|
+
}, 15_000);
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
// Upload a local image file to BlueSky as a blob, using the page's own session
|
|
1056
|
+
// token. The Neural Interface reads the file from disk (the MCP page context
|
|
1057
|
+
// can't), pulls accessJwt/pdsUrl from the bsky.app tab, and POSTs the bytes to
|
|
1058
|
+
// com.atproto.repo.uploadBlob. Returns { ok, blob } (the AT Protocol blob ref).
|
|
1059
|
+
export async function uploadBlueskyBlob(sessionId: string, filePath: string, tabId?: string): Promise<NiResponse> {
|
|
1060
|
+
return request('POST', `/api/browser/sessions/${sessionId}/bluesky/upload-blob`, { filePath, ...(tabId && { tabId }) }, LONG_TIMEOUT);
|
|
223
1061
|
}
|
|
224
1062
|
|
|
225
1063
|
export async function waitFor(
|
|
226
1064
|
sessionId: string,
|
|
227
|
-
opts: { selector?: string; state?: string; loadState?: string; timeout?: number }
|
|
1065
|
+
opts: { selector?: string; state?: string; loadState?: string; timeout?: number },
|
|
1066
|
+
tabId?: string
|
|
228
1067
|
): Promise<NiResponse> {
|
|
229
|
-
return request('POST', `/api/browser/sessions/${sessionId}/wait`, opts, LONG_TIMEOUT);
|
|
1068
|
+
return request('POST', `/api/browser/sessions/${sessionId}/wait`, { ...opts, ...(isBrowserCompactMode() && { compact: true }), ...(tabId && { tabId }) }, LONG_TIMEOUT);
|
|
230
1069
|
}
|
|
231
1070
|
|
|
232
1071
|
// ── Whiteboard ──
|
|
233
1072
|
|
|
234
|
-
|
|
235
|
-
|
|
1073
|
+
/** Read the board. `images: false` asks the server to replace image dataUrls
|
|
1074
|
+
* with their byte size (the tools never need the base64 payload). */
|
|
1075
|
+
export async function getWhiteboard(opts: { images?: boolean } = {}): Promise<NiResponse> {
|
|
1076
|
+
return request('GET', opts.images === false ? '/api/whiteboard?images=0' : '/api/whiteboard');
|
|
236
1077
|
}
|
|
237
1078
|
|
|
238
1079
|
export async function addWhiteboardElements(
|
|
@@ -243,6 +1084,14 @@ export async function addWhiteboardElements(
|
|
|
243
1084
|
return request('POST', '/api/whiteboard/elements', { elements, coordMode, layout } as Record<string, unknown>);
|
|
244
1085
|
}
|
|
245
1086
|
|
|
1087
|
+
/** Atomic update/remove ops (one save, one broadcast, per-op results). */
|
|
1088
|
+
export async function batchWhiteboardOps(
|
|
1089
|
+
ops: Record<string, unknown>[],
|
|
1090
|
+
coordMode?: string
|
|
1091
|
+
): Promise<NiResponse> {
|
|
1092
|
+
return request('POST', '/api/whiteboard/elements/batch', { ops, coordMode } as Record<string, unknown>);
|
|
1093
|
+
}
|
|
1094
|
+
|
|
246
1095
|
export async function updateWhiteboardElement(
|
|
247
1096
|
id: string,
|
|
248
1097
|
updates: Record<string, unknown>,
|
|
@@ -259,8 +1108,9 @@ export async function clearWhiteboard(): Promise<NiResponse> {
|
|
|
259
1108
|
return request('POST', '/api/whiteboard/clear');
|
|
260
1109
|
}
|
|
261
1110
|
|
|
262
|
-
export async function whiteboardScreenshot(): Promise<NiResponse> {
|
|
263
|
-
|
|
1111
|
+
export async function whiteboardScreenshot(opts: { crop?: string } = {}): Promise<NiResponse> {
|
|
1112
|
+
const query = opts.crop === 'usable' ? '?crop=usable' : '';
|
|
1113
|
+
return request('GET', `/api/whiteboard/screenshot${query}`, undefined, 15_000);
|
|
264
1114
|
}
|
|
265
1115
|
|
|
266
1116
|
// ── Cards (Memory Card MCP integration) ──
|
|
@@ -333,6 +1183,60 @@ export async function gitBranches(path: string): Promise<NiResponse> {
|
|
|
333
1183
|
return request('GET', `/api/terminal/branches?path=${encodeURIComponent(path)}`);
|
|
334
1184
|
}
|
|
335
1185
|
|
|
1186
|
+
// ── Style Guide ──
|
|
1187
|
+
|
|
1188
|
+
// `projectPath` is any path inside a registered project; the server resolves it to the project root.
|
|
1189
|
+
function styleGuideQuery(params: Record<string, string | undefined | null>): string {
|
|
1190
|
+
const query = new URLSearchParams();
|
|
1191
|
+
for (const [key, value] of Object.entries(params)) if (value !== undefined && value !== null && value !== '') query.set(key, value);
|
|
1192
|
+
return query.toString();
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1195
|
+
export async function getStyleGuide(projectPath: string): Promise<NiResponse> {
|
|
1196
|
+
return request('GET', `/api/style-guide?${styleGuideQuery({ projectPath })}`);
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1199
|
+
/** The compact text agents get: { summary, tokensEstimate, saved, revision, projectPath }. */
|
|
1200
|
+
export async function getStyleGuideSummary(projectPath: string, taskClass?: string): Promise<NiResponse> {
|
|
1201
|
+
return request('GET', `/api/style-guide/summary?${styleGuideQuery({ projectPath, taskClass })}`);
|
|
1202
|
+
}
|
|
1203
|
+
|
|
1204
|
+
/** One export format as text: { format, contentType, filename, text, revision }. */
|
|
1205
|
+
export async function getStyleGuideExport(projectPath: string, format: string, theme?: string): Promise<NiResponse> {
|
|
1206
|
+
return request('GET', `/api/style-guide/export?${styleGuideQuery({ projectPath, format, theme, as: 'json' })}`);
|
|
1207
|
+
}
|
|
1208
|
+
|
|
1209
|
+
/** Write the project's artifacts now: { written: [{ format, path, changed }] }. */
|
|
1210
|
+
export async function writeStyleGuideExports(projectPath: string, formats?: string[]): Promise<NiResponse> {
|
|
1211
|
+
return request('POST', '/api/style-guide/export', { projectPath, ...(formats?.length ? { formats } : {}) });
|
|
1212
|
+
}
|
|
1213
|
+
|
|
1214
|
+
/** WCAG ratio + APCA for two colors (or aliases, with a project): { ratio, aa, aaa, aaLarge, apca, fg, bg }. */
|
|
1215
|
+
export async function styleGuideContrast(body: { fg: string; bg: string; size?: string; projectPath?: string; theme?: string }): Promise<NiResponse> {
|
|
1216
|
+
return request('POST', '/api/style-guide/contrast', body);
|
|
1217
|
+
}
|
|
1218
|
+
|
|
1219
|
+
/** An agent's only write to a guide: a merge patch the user accepts or rejects. { id, pending, ignored, diff } */
|
|
1220
|
+
export async function proposeStyleGuideChange(body: { projectPath: string; changes: Record<string, unknown>; reason: string; runId?: string; provider?: string; model?: string }): Promise<NiResponse> {
|
|
1221
|
+
const identity = getIdentity();
|
|
1222
|
+
const runId = effectivePins(identity).terminalSessionId || identity.state.ancestorPinnedTerminal;
|
|
1223
|
+
return request('POST', '/api/style-guide/proposals', { ...(!body.runId && runId ? { runId } : {}), ...body });
|
|
1224
|
+
}
|
|
1225
|
+
|
|
1226
|
+
/** The project's proposals (a bare array on success). */
|
|
1227
|
+
export async function listStyleGuideProposals(projectPath: string, status?: string): Promise<NiResponse> {
|
|
1228
|
+
return request('GET', `/api/style-guide/proposals?${styleGuideQuery({ projectPath, status })}`);
|
|
1229
|
+
}
|
|
1230
|
+
|
|
1231
|
+
/** Registered projects with their guide's status (a bare array on success). */
|
|
1232
|
+
export async function listStyleGuideProjects(): Promise<NiResponse> {
|
|
1233
|
+
return request('GET', '/api/style-guide/projects');
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1236
|
+
export async function listProjects(): Promise<NiResponse> {
|
|
1237
|
+
return request('GET', '/api/projects');
|
|
1238
|
+
}
|
|
1239
|
+
|
|
336
1240
|
// ── Image store ──
|
|
337
1241
|
|
|
338
1242
|
export async function listImages(): Promise<NiResponse> {
|
|
@@ -342,3 +1246,243 @@ export async function listImages(): Promise<NiResponse> {
|
|
|
342
1246
|
export async function deleteImage(filename: string): Promise<NiResponse> {
|
|
343
1247
|
return request('DELETE', `/api/images/${encodeURIComponent(filename)}`);
|
|
344
1248
|
}
|
|
1249
|
+
|
|
1250
|
+
// ── YouTube trailer pipeline (sourcing + download + API) ──
|
|
1251
|
+
// These delegate to the Neural Interface server, which holds the IGDB/Twitch
|
|
1252
|
+
// token, the Steam proxy, the yt-dlp binary, and the YouTube OAuth credentials.
|
|
1253
|
+
|
|
1254
|
+
const DOWNLOAD_TIMEOUT = 600_000; // trailer downloads can be large/slow
|
|
1255
|
+
|
|
1256
|
+
/**
|
|
1257
|
+
* Discover candidate trailers. `source` selects the discovery backend:
|
|
1258
|
+
* 'igdb' — query IGDB for games + Steam appid + YouTube trailer ids
|
|
1259
|
+
* 'steam' — resolve Steam appdetails movies[] for explicit appids/query
|
|
1260
|
+
* 'youtube' — search YouTube directly for recently published trailer videos
|
|
1261
|
+
* 'auto' — IGDB discovery enriched with Steam mp4 URLs (default)
|
|
1262
|
+
*/
|
|
1263
|
+
export async function youtubeDiscover(body: {
|
|
1264
|
+
source?: 'igdb' | 'steam' | 'youtube' | 'auto';
|
|
1265
|
+
query?: string;
|
|
1266
|
+
appids?: number[];
|
|
1267
|
+
limit?: number;
|
|
1268
|
+
filters?: Record<string, unknown>;
|
|
1269
|
+
}): Promise<NiResponse> {
|
|
1270
|
+
return request('POST', '/api/sources/discover', body as Record<string, unknown>, LONG_TIMEOUT);
|
|
1271
|
+
}
|
|
1272
|
+
|
|
1273
|
+
/**
|
|
1274
|
+
* Download a trailer to disk. Prefers a direct Steam mp4 URL; falls back to
|
|
1275
|
+
* yt-dlp on a YouTube id/url. Returns `{ filePath, bytes, source }`.
|
|
1276
|
+
*/
|
|
1277
|
+
export async function youtubeDownload(body: {
|
|
1278
|
+
steamMp4Url?: string;
|
|
1279
|
+
ytId?: string;
|
|
1280
|
+
url?: string;
|
|
1281
|
+
appid?: number;
|
|
1282
|
+
outputDir?: string;
|
|
1283
|
+
filename?: string;
|
|
1284
|
+
quality?: string;
|
|
1285
|
+
useCookies?: boolean;
|
|
1286
|
+
}): Promise<NiResponse> {
|
|
1287
|
+
return request('POST', '/api/youtube/download', body as Record<string, unknown>, DOWNLOAD_TIMEOUT);
|
|
1288
|
+
}
|
|
1289
|
+
|
|
1290
|
+
export async function youtubeGetConfig(): Promise<NiResponse> {
|
|
1291
|
+
return request('GET', '/api/youtube/config');
|
|
1292
|
+
}
|
|
1293
|
+
|
|
1294
|
+
export async function youtubeSetConfig(config: Record<string, unknown>): Promise<NiResponse> {
|
|
1295
|
+
return request('PUT', '/api/youtube/config', config);
|
|
1296
|
+
}
|
|
1297
|
+
|
|
1298
|
+
/** Test configured credentials. `target`: 'youtube' | 'igdb' | 'steam' | 'all'. */
|
|
1299
|
+
export async function youtubeTest(target?: string): Promise<NiResponse> {
|
|
1300
|
+
return request('POST', '/api/youtube/test', target ? { target } : {}, LONG_TIMEOUT);
|
|
1301
|
+
}
|
|
1302
|
+
|
|
1303
|
+
/** Read-only analytics via the YouTube Data/Analytics API (OAuth). */
|
|
1304
|
+
export async function youtubeAnalytics(body: {
|
|
1305
|
+
videoId?: string;
|
|
1306
|
+
channelId?: string;
|
|
1307
|
+
metrics?: string[];
|
|
1308
|
+
startDate?: string;
|
|
1309
|
+
endDate?: string;
|
|
1310
|
+
}): Promise<NiResponse> {
|
|
1311
|
+
return request('POST', '/api/youtube/analytics', body as Record<string, unknown>, LONG_TIMEOUT);
|
|
1312
|
+
}
|
|
1313
|
+
|
|
1314
|
+
// ── MoreLogin (anti-detect browser) — proxied to the Neural Interface ──
|
|
1315
|
+
|
|
1316
|
+
export async function moreloginStatus(): Promise<NiResponse> {
|
|
1317
|
+
return request('GET', '/api/morelogin/status', undefined, LONG_TIMEOUT);
|
|
1318
|
+
}
|
|
1319
|
+
|
|
1320
|
+
export async function moreloginProfiles(): Promise<NiResponse> {
|
|
1321
|
+
return request('GET', '/api/morelogin/profiles', undefined, LONG_TIMEOUT);
|
|
1322
|
+
}
|
|
1323
|
+
|
|
1324
|
+
export async function moreloginCreate(name?: string): Promise<NiResponse> {
|
|
1325
|
+
return request('POST', '/api/morelogin/profiles', name ? { name } : {}, LONG_TIMEOUT);
|
|
1326
|
+
}
|
|
1327
|
+
|
|
1328
|
+
export async function moreloginStart(envId: string): Promise<NiResponse> {
|
|
1329
|
+
return request('POST', '/api/morelogin/start', { envId }, SESSION_CREATE_TIMEOUT);
|
|
1330
|
+
}
|
|
1331
|
+
|
|
1332
|
+
export async function moreloginStop(envId: string): Promise<NiResponse> {
|
|
1333
|
+
return request('POST', '/api/morelogin/stop', { envId }, LONG_TIMEOUT);
|
|
1334
|
+
}
|
|
1335
|
+
|
|
1336
|
+
export async function moreloginUseDefault(envId: string | null): Promise<NiResponse> {
|
|
1337
|
+
return request('POST', '/api/morelogin/use-default', envId ? { envId } : { clear: true });
|
|
1338
|
+
}
|
|
1339
|
+
|
|
1340
|
+
// ── SynaBun assistant orchestration (role-gated `agents` tool group) ──
|
|
1341
|
+
// Thin proxies over /api/assistant/* (neural-interface/lib/assistant-api.js),
|
|
1342
|
+
// which owns dispatch state, rails and authorization. requestOnce already
|
|
1343
|
+
// sends X-Synabun-Terminal (the assistant pin) and X-Synabun-Role.
|
|
1344
|
+
|
|
1345
|
+
export type AssistantProvider = 'claude-code' | 'codex' | 'opencode';
|
|
1346
|
+
|
|
1347
|
+
export type AssistantDispatchBody = {
|
|
1348
|
+
/** Optional when routeId names an approved route (the server applies it). */
|
|
1349
|
+
provider?: AssistantProvider;
|
|
1350
|
+
task: string;
|
|
1351
|
+
cwd: string;
|
|
1352
|
+
assistantSessionId: string;
|
|
1353
|
+
model?: string;
|
|
1354
|
+
effort?: string;
|
|
1355
|
+
mcpProfile?: string;
|
|
1356
|
+
routeId?: string;
|
|
1357
|
+
taskClass?: string;
|
|
1358
|
+
confidence?: number;
|
|
1359
|
+
usesComputer?: boolean;
|
|
1360
|
+
agent?: string;
|
|
1361
|
+
accountId?: string;
|
|
1362
|
+
codexAccountId?: string;
|
|
1363
|
+
claudeAccountId?: string;
|
|
1364
|
+
permissionPolicy?: 'auto' | 'ask' | 'restricted';
|
|
1365
|
+
capability?: 'read-only' | 'workspace' | 'full';
|
|
1366
|
+
maxMinutes?: number;
|
|
1367
|
+
budgetUsd?: number;
|
|
1368
|
+
usesBrowser?: boolean;
|
|
1369
|
+
focus?: boolean;
|
|
1370
|
+
title?: string;
|
|
1371
|
+
context?: string;
|
|
1372
|
+
tags?: string[];
|
|
1373
|
+
workflowId?: string;
|
|
1374
|
+
parentRunId?: string;
|
|
1375
|
+
outputSchema?: Record<string, unknown>;
|
|
1376
|
+
idempotencyKey?: string;
|
|
1377
|
+
briefId?: string;
|
|
1378
|
+
independent?: boolean;
|
|
1379
|
+
};
|
|
1380
|
+
|
|
1381
|
+
// A dispatch may acquire a browser tab before the run is accepted.
|
|
1382
|
+
const ASSISTANT_DISPATCH_TIMEOUT = 90_000;
|
|
1383
|
+
// Long-poll waits block server-side for up to timeoutMs; the HTTP deadline
|
|
1384
|
+
// must always outlive them so a timed-out wait is reported by the server.
|
|
1385
|
+
const ASSISTANT_WAIT_MARGIN_MS = 15_000;
|
|
1386
|
+
|
|
1387
|
+
function assistantRunPath(runId: string, suffix = ''): string {
|
|
1388
|
+
return `/api/assistant/runs/${encodeURIComponent(runId)}${suffix}`;
|
|
1389
|
+
}
|
|
1390
|
+
|
|
1391
|
+
function queryString(params: Record<string, string | number | boolean | undefined | null>): string {
|
|
1392
|
+
const qs = new URLSearchParams();
|
|
1393
|
+
for (const [key, value] of Object.entries(params)) {
|
|
1394
|
+
if (value === undefined || value === null || value === '') continue;
|
|
1395
|
+
qs.set(key, String(value));
|
|
1396
|
+
}
|
|
1397
|
+
const rendered = qs.toString();
|
|
1398
|
+
return rendered ? `?${rendered}` : '';
|
|
1399
|
+
}
|
|
1400
|
+
|
|
1401
|
+
export async function assistantCatalog(opts: { provider?: string; search?: string } = {}): Promise<NiResponse> {
|
|
1402
|
+
return request('GET', `/api/assistant/catalog${queryString({ view: 'brain', provider: opts.provider, q: opts.search })}`, undefined, LONG_TIMEOUT);
|
|
1403
|
+
}
|
|
1404
|
+
|
|
1405
|
+
// agent_route may show the user a route card and wait for the answer; the
|
|
1406
|
+
// server caps its own wait below this deadline (X-Synabun-Deadline).
|
|
1407
|
+
const ASSISTANT_ROUTE_TIMEOUT = 115_000;
|
|
1408
|
+
|
|
1409
|
+
export async function assistantRoute(body: {
|
|
1410
|
+
assistantSessionId: string;
|
|
1411
|
+
task_class: string;
|
|
1412
|
+
summary: string;
|
|
1413
|
+
confidence: number;
|
|
1414
|
+
needs_vision?: boolean;
|
|
1415
|
+
proposals: Array<{ kind: 'direct' | 'dispatch'; provider?: string; model?: string; effort?: string; reason?: string }>;
|
|
1416
|
+
independent?: boolean;
|
|
1417
|
+
}): Promise<NiResponse> {
|
|
1418
|
+
return request('POST', '/api/assistant/route', body as unknown as Record<string, unknown>, ASSISTANT_ROUTE_TIMEOUT);
|
|
1419
|
+
}
|
|
1420
|
+
|
|
1421
|
+
// agent_clarify shows the user a question card and waits briefly for the
|
|
1422
|
+
// answers; like agent_route, the server caps its wait below this deadline.
|
|
1423
|
+
export async function assistantClarify(body: {
|
|
1424
|
+
assistantSessionId: string;
|
|
1425
|
+
summary: string;
|
|
1426
|
+
questions: Array<{ id?: string; header?: string; question: string; options: Array<{ label: string; description?: string }>; multi_select?: boolean }>;
|
|
1427
|
+
constraints?: string[];
|
|
1428
|
+
assumptions?: string[];
|
|
1429
|
+
}): Promise<NiResponse> {
|
|
1430
|
+
return request('POST', '/api/assistant/clarify', body as unknown as Record<string, unknown>, ASSISTANT_ROUTE_TIMEOUT);
|
|
1431
|
+
}
|
|
1432
|
+
|
|
1433
|
+
export async function assistantListRuns(opts: { activeOnly?: boolean; assistantSessionId?: string; workflowId?: string } = {}): Promise<NiResponse> {
|
|
1434
|
+
return request('GET', `/api/assistant/runs${queryString({
|
|
1435
|
+
active: opts.activeOnly ? 1 : undefined,
|
|
1436
|
+
assistantSessionId: opts.assistantSessionId,
|
|
1437
|
+
workflowId: opts.workflowId,
|
|
1438
|
+
})}`);
|
|
1439
|
+
}
|
|
1440
|
+
|
|
1441
|
+
/** Usage of one task ("current", an id) or the session ("all"); `runId` with "all" adds that run's totals over its tasks. */
|
|
1442
|
+
export async function assistantUsage(assistantSessionId: string, task = 'current', runId?: string): Promise<NiResponse> {
|
|
1443
|
+
return request('GET', `/api/assistant/sessions/${encodeURIComponent(assistantSessionId)}/usage${queryString({ task, run: runId })}`);
|
|
1444
|
+
}
|
|
1445
|
+
|
|
1446
|
+
export async function assistantDispatch(body: AssistantDispatchBody): Promise<NiResponse> {
|
|
1447
|
+
return request('POST', '/api/assistant/dispatch', body, ASSISTANT_DISPATCH_TIMEOUT);
|
|
1448
|
+
}
|
|
1449
|
+
|
|
1450
|
+
export async function assistantRun(runId: string): Promise<NiResponse> {
|
|
1451
|
+
return request('GET', assistantRunPath(runId));
|
|
1452
|
+
}
|
|
1453
|
+
|
|
1454
|
+
export async function assistantResult(runId: string): Promise<NiResponse> {
|
|
1455
|
+
return request('GET', assistantRunPath(runId, '/result'));
|
|
1456
|
+
}
|
|
1457
|
+
|
|
1458
|
+
export async function assistantTranscript(runId: string, opts: { format?: string; tail?: number; maxChars?: number } = {}): Promise<NiResponse> {
|
|
1459
|
+
return request('GET', assistantRunPath(runId, `/transcript${queryString({ format: opts.format, tail: opts.tail, maxChars: opts.maxChars })}`), undefined, LONG_TIMEOUT);
|
|
1460
|
+
}
|
|
1461
|
+
|
|
1462
|
+
export async function assistantSend(runId: string, body: { text: string; queue?: boolean }): Promise<NiResponse> {
|
|
1463
|
+
return request('POST', assistantRunPath(runId, '/send'), body, LONG_TIMEOUT);
|
|
1464
|
+
}
|
|
1465
|
+
|
|
1466
|
+
export async function assistantPermission(runId: string, body: { requestId: string; behavior: 'allow' | 'deny'; answers?: Record<string, unknown>; message?: string }): Promise<NiResponse> {
|
|
1467
|
+
return request('POST', assistantRunPath(runId, '/permission'), body, LONG_TIMEOUT);
|
|
1468
|
+
}
|
|
1469
|
+
|
|
1470
|
+
export async function assistantWaitRun(runId: string, opts: { until?: string; timeoutMs: number }): Promise<NiResponse> {
|
|
1471
|
+
return request('GET', assistantRunPath(runId, `/wait${queryString({ until: opts.until, timeout: opts.timeoutMs })}`), undefined, opts.timeoutMs + ASSISTANT_WAIT_MARGIN_MS);
|
|
1472
|
+
}
|
|
1473
|
+
|
|
1474
|
+
export async function assistantWaitMany(body: { runIds?: string[]; workflowId?: string; mode?: string; until?: string; timeoutMs: number }): Promise<NiResponse> {
|
|
1475
|
+
return request('POST', '/api/assistant/wait', body, body.timeoutMs + ASSISTANT_WAIT_MARGIN_MS);
|
|
1476
|
+
}
|
|
1477
|
+
|
|
1478
|
+
export async function assistantStop(runId: string, reason?: string): Promise<NiResponse> {
|
|
1479
|
+
return request('POST', assistantRunPath(runId, '/stop'), reason ? { reason } : {}, LONG_TIMEOUT);
|
|
1480
|
+
}
|
|
1481
|
+
|
|
1482
|
+
export async function assistantKillAll(body: { assistantSessionId?: string; workflowId?: string; reason?: string } = {}): Promise<NiResponse> {
|
|
1483
|
+
return request('POST', '/api/assistant/kill-all', body, LONG_TIMEOUT);
|
|
1484
|
+
}
|
|
1485
|
+
|
|
1486
|
+
export async function assistantFocus(runId: string, focus: boolean): Promise<NiResponse> {
|
|
1487
|
+
return request('POST', assistantRunPath(runId, '/focus'), { focus });
|
|
1488
|
+
}
|