synabun 2.0.10 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +207 -0
- package/README.md +25 -2
- package/THIRD-PARTY-LICENSES.md +22 -0
- package/bin/synabun.js +71 -24
- package/docs/whatsapp.md +13 -13
- package/hooks/claude-code/pre-websearch.mjs +12 -1
- package/hooks/claude-code/shared.mjs +5 -0
- package/hooks/claude-code/stop.mjs +1 -1
- package/lib/claude-hooks.js +172 -18
- package/lib/client-config-repair.js +30 -17
- package/lib/desktop-app.js +7 -1
- package/lib/external-tools.js +7 -6
- package/lib/first-launch-protection.js +57 -12
- package/lib/mcp-dist.js +176 -0
- package/lib/release-npm-ci.mjs +138 -0
- package/lib/release-publish.mjs +91 -0
- package/lib/release-scan.mjs +50 -0
- package/lib/server-crash-record.js +123 -0
- package/lib/server-exit.js +318 -0
- package/lib/server-supervisor.js +508 -0
- package/lib/start-launcher.js +37 -4
- package/lib/tools-cli.js +45 -0
- package/lib/update-snapshot.js +302 -0
- package/lib/virustotal.mjs +203 -0
- package/lib/windows-crash-event.js +269 -0
- package/mcp-server/dist/http.d.ts +20 -1
- package/mcp-server/dist/http.d.ts.map +1 -1
- package/mcp-server/dist/http.js +59 -12
- package/mcp-server/dist/http.js.map +1 -1
- package/mcp-server/dist/index.d.ts +33 -27
- package/mcp-server/dist/index.d.ts.map +1 -1
- package/mcp-server/dist/index.js +128 -143
- package/mcp-server/dist/index.js.map +1 -1
- package/mcp-server/dist/preload.js +1 -1
- package/mcp-server/dist/preload.js.map +1 -1
- package/mcp-server/dist/services/budget-judgments.d.ts +1 -1
- package/mcp-server/dist/services/budget-judgments.d.ts.map +1 -1
- package/mcp-server/dist/services/budget-judgments.js +5 -3
- package/mcp-server/dist/services/budget-judgments.js.map +1 -1
- package/mcp-server/dist/services/codex-config-heal.d.ts +6 -2
- package/mcp-server/dist/services/codex-config-heal.d.ts.map +1 -1
- package/mcp-server/dist/services/codex-config-heal.js +81 -28
- package/mcp-server/dist/services/codex-config-heal.js.map +1 -1
- package/mcp-server/dist/services/identity.d.ts +2 -2
- package/mcp-server/dist/services/identity.js +2 -2
- package/mcp-server/dist/services/memory-judge-backfill.d.ts +6 -0
- package/mcp-server/dist/services/memory-judge-backfill.d.ts.map +1 -1
- package/mcp-server/dist/services/memory-judge-backfill.js +7 -1
- package/mcp-server/dist/services/memory-judge-backfill.js.map +1 -1
- package/mcp-server/dist/services/memory-sessions.d.ts +1 -1
- package/mcp-server/dist/services/memory-sessions.d.ts.map +1 -1
- package/mcp-server/dist/services/memory-sessions.js +28 -2
- package/mcp-server/dist/services/memory-sessions.js.map +1 -1
- package/mcp-server/dist/services/neural-interface.d.ts +18 -11
- package/mcp-server/dist/services/neural-interface.d.ts.map +1 -1
- package/mcp-server/dist/services/neural-interface.js +67 -11
- package/mcp-server/dist/services/neural-interface.js.map +1 -1
- package/mcp-server/dist/services/server-instructions.d.ts +7 -2
- package/mcp-server/dist/services/server-instructions.d.ts.map +1 -1
- package/mcp-server/dist/services/server-instructions.js +22 -63
- package/mcp-server/dist/services/server-instructions.js.map +1 -1
- package/mcp-server/dist/services/tool-catalog.d.ts +120 -0
- package/mcp-server/dist/services/tool-catalog.d.ts.map +1 -0
- package/mcp-server/dist/services/tool-catalog.js +339 -0
- package/mcp-server/dist/services/tool-catalog.js.map +1 -0
- package/mcp-server/dist/services/tool-list-refresh-barrier.d.ts +12 -0
- package/mcp-server/dist/services/tool-list-refresh-barrier.d.ts.map +1 -0
- package/mcp-server/dist/services/tool-list-refresh-barrier.js +40 -0
- package/mcp-server/dist/services/tool-list-refresh-barrier.js.map +1 -0
- package/mcp-server/dist/services/tool-list.d.ts +108 -0
- package/mcp-server/dist/services/tool-list.d.ts.map +1 -0
- package/mcp-server/dist/services/tool-list.js +334 -0
- package/mcp-server/dist/services/tool-list.js.map +1 -0
- package/mcp-server/dist/services/tool-runtime.d.ts +161 -0
- package/mcp-server/dist/services/tool-runtime.d.ts.map +1 -0
- package/mcp-server/dist/services/tool-runtime.js +400 -0
- package/mcp-server/dist/services/tool-runtime.js.map +1 -0
- package/mcp-server/dist/services/typesafe-config.js +1 -1
- package/mcp-server/dist/services/typesafe-config.js.map +1 -1
- package/mcp-server/dist/services/whiteboard-geometry.d.ts +26 -2
- package/mcp-server/dist/services/whiteboard-geometry.d.ts.map +1 -1
- package/mcp-server/dist/services/whiteboard-geometry.js +91 -8
- package/mcp-server/dist/services/whiteboard-geometry.js.map +1 -1
- package/mcp-server/dist/tools/agents.d.ts +14 -14
- package/mcp-server/dist/tools/agents.d.ts.map +1 -1
- package/mcp-server/dist/tools/agents.js +29 -19
- package/mcp-server/dist/tools/agents.js.map +1 -1
- package/mcp-server/dist/tools/browser-batch.d.ts +3 -3
- package/mcp-server/dist/tools/choice.d.ts +6 -0
- package/mcp-server/dist/tools/choice.d.ts.map +1 -1
- package/mcp-server/dist/tools/choice.js +18 -13
- package/mcp-server/dist/tools/choice.js.map +1 -1
- package/mcp-server/dist/tools/git-tools.js +2 -2
- package/mcp-server/dist/tools/git-tools.js.map +1 -1
- package/mcp-server/dist/tools/image-tools.d.ts +1 -1
- package/mcp-server/dist/tools/image-tools.js +1 -1
- package/mcp-server/dist/tools/morelogin.d.ts.map +1 -1
- package/mcp-server/dist/tools/morelogin.js +9 -6
- package/mcp-server/dist/tools/morelogin.js.map +1 -1
- package/mcp-server/dist/tools/skill-tools.d.ts +505 -0
- package/mcp-server/dist/tools/skill-tools.d.ts.map +1 -0
- package/mcp-server/dist/tools/skill-tools.js +642 -0
- package/mcp-server/dist/tools/skill-tools.js.map +1 -0
- package/mcp-server/dist/tools/skill.d.ts +7 -0
- package/mcp-server/dist/tools/skill.d.ts.map +1 -0
- package/mcp-server/dist/tools/skill.js +11 -0
- package/mcp-server/dist/tools/skill.js.map +1 -0
- package/mcp-server/dist/tools/tool-groups.d.ts +68 -0
- package/mcp-server/dist/tools/tool-groups.d.ts.map +1 -0
- package/mcp-server/dist/tools/tool-groups.js +147 -0
- package/mcp-server/dist/tools/tool-groups.js.map +1 -0
- package/mcp-server/dist/tools/whiteboard-format.d.ts.map +1 -1
- package/mcp-server/dist/tools/whiteboard-format.js +7 -4
- package/mcp-server/dist/tools/whiteboard-format.js.map +1 -1
- package/mcp-server/dist/tools/whiteboard-tools.d.ts +64 -13
- package/mcp-server/dist/tools/whiteboard-tools.d.ts.map +1 -1
- package/mcp-server/dist/tools/whiteboard-tools.js +30 -5
- package/mcp-server/dist/tools/whiteboard-tools.js.map +1 -1
- package/mcp-server/package-lock.json +2 -2
- package/mcp-server/package.json +1 -1
- package/mcp-server/src/http.ts +75 -12
- package/mcp-server/src/index.ts +147 -154
- package/mcp-server/src/preload.ts +12 -12
- package/mcp-server/src/services/budget-judgments.ts +5 -3
- package/mcp-server/src/services/codex-config-heal.ts +80 -29
- package/mcp-server/src/services/identity.ts +2 -2
- package/mcp-server/src/services/memory-judge-backfill.ts +7 -1
- package/mcp-server/src/services/memory-sessions.ts +24 -3
- package/mcp-server/src/services/neural-interface.ts +81 -21
- package/mcp-server/src/services/server-instructions.ts +29 -64
- package/mcp-server/src/services/tool-catalog.ts +403 -0
- package/mcp-server/src/services/tool-list-refresh-barrier.ts +33 -0
- package/mcp-server/src/services/tool-list.ts +410 -0
- package/mcp-server/src/services/tool-runtime.ts +457 -0
- package/mcp-server/src/services/typesafe-config.ts +1 -1
- package/mcp-server/src/services/whiteboard-geometry.ts +94 -9
- package/mcp-server/src/tools/agents.ts +29 -20
- package/mcp-server/src/tools/choice.ts +17 -12
- package/mcp-server/src/tools/git-tools.ts +2 -2
- package/mcp-server/src/tools/image-tools.ts +1 -1
- package/mcp-server/src/tools/morelogin.ts +6 -4
- package/mcp-server/src/tools/skill-tools.ts +592 -0
- package/mcp-server/src/tools/skill.ts +13 -0
- package/mcp-server/src/tools/tool-groups.ts +164 -0
- package/mcp-server/src/tools/whiteboard-format.ts +9 -3
- package/mcp-server/src/tools/whiteboard-tools.ts +39 -5
- package/neural-interface/i18n/en.json +3953 -228
- package/neural-interface/i18n/pt-BR.json +3901 -179
- package/neural-interface/lib/agent-sandbox-elevation.js +6 -0
- package/neural-interface/lib/antigravity/acp-client-host.js +554 -0
- package/neural-interface/lib/antigravity/acp-connection.js +299 -0
- package/neural-interface/lib/antigravity/bypass.js +100 -0
- package/neural-interface/lib/antigravity/catalog.js +273 -0
- package/neural-interface/lib/antigravity/home.js +260 -0
- package/neural-interface/lib/antigravity/migrate-gemini.js +139 -0
- package/neural-interface/lib/antigravity/panel-bridge.js +1058 -0
- package/neural-interface/lib/antigravity/policy-hook.mjs +78 -0
- package/neural-interface/lib/antigravity/policy.js +74 -0
- package/neural-interface/lib/antigravity/tool-call.js +178 -0
- package/neural-interface/lib/antigravity/transcripts.js +252 -0
- package/neural-interface/lib/antigravity/usage.js +43 -0
- package/neural-interface/lib/assistant-api.js +128 -28
- package/neural-interface/lib/assistant-brains/antigravity.js +423 -0
- package/neural-interface/lib/assistant-brains/claude.js +4 -3
- package/neural-interface/lib/assistant-brains/codex-browser-policy-hook.mjs +12 -2
- package/neural-interface/lib/assistant-brains/codex-route-gate-hook.mjs +32 -9
- package/neural-interface/lib/assistant-brains/codex.js +9 -5
- package/neural-interface/lib/assistant-brains/opencode.js +120 -54
- package/neural-interface/lib/assistant-brains/opencode2-browser-policy/index.js +28 -13
- package/neural-interface/lib/assistant-brains/opencode2-route-gate/index.js +59 -19
- package/neural-interface/lib/assistant-budget-planner.js +7 -3
- package/neural-interface/lib/assistant-budget-split.js +42 -15
- package/neural-interface/lib/assistant-catalog.js +81 -15
- package/neural-interface/lib/assistant-config.js +6 -3
- package/neural-interface/lib/assistant-dispatch.js +1073 -200
- package/neural-interface/lib/assistant-envelope.js +156 -2
- package/neural-interface/lib/assistant-evidence.js +80 -0
- package/neural-interface/lib/assistant-hidden-models.js +7 -5
- package/neural-interface/lib/assistant-persona.js +93 -19
- package/neural-interface/lib/assistant-plan-permissions.js +25 -9
- package/neural-interface/lib/assistant-route-gate-codex.js +3 -0
- package/neural-interface/lib/assistant-route-gate.js +6 -4
- package/neural-interface/lib/assistant-router.js +245 -38
- package/neural-interface/lib/assistant-runtime.js +214 -30
- package/neural-interface/lib/assistant-task-prompt.js +87 -21
- package/neural-interface/lib/assistant-tools.js +51 -0
- package/neural-interface/lib/assistant-usage.js +29 -0
- package/neural-interface/lib/backup-service.js +626 -4
- package/neural-interface/lib/backup-zip-reader.js +10 -5
- package/neural-interface/lib/backup-zip-writer.js +257 -0
- package/neural-interface/lib/browser-execution.js +10 -2
- package/neural-interface/lib/browser-guard-cdp.js +84 -0
- package/neural-interface/lib/browser-network-guard.js +476 -0
- package/neural-interface/lib/browser-policy-roots.js +64 -0
- package/neural-interface/lib/browser-tool-policy.js +198 -38
- package/neural-interface/lib/claude-agent-bridge.js +11 -2
- package/neural-interface/lib/claude-history-cache.js +210 -0
- package/neural-interface/lib/claude-hooks-status.js +103 -0
- package/neural-interface/lib/claude-model-catalog.js +5 -1
- package/neural-interface/lib/claude-temporary.js +5 -11
- package/neural-interface/lib/cli-install-api.js +1 -1
- package/neural-interface/lib/cli-install.js +163 -154
- package/neural-interface/lib/cli-resolver.js +13 -3
- package/neural-interface/lib/cli-update-planner.js +52 -41
- package/neural-interface/lib/cloudflared/tunnel.js +42 -2
- package/neural-interface/lib/codex-mcp-approvals.js +11 -0
- package/neural-interface/lib/codex-rollout-reader.js +52 -0
- package/neural-interface/lib/codex-worker-app-server.js +191 -0
- package/neural-interface/lib/confined-fs.js +30 -3
- package/neural-interface/lib/crash-notice-api.js +98 -0
- package/neural-interface/lib/editor-completion-opencode.js +68 -68
- package/neural-interface/lib/editor-git-api.js +3 -20
- package/neural-interface/lib/exec-loop-command.js +13 -10
- package/neural-interface/lib/file-explorer-api.js +74 -40
- package/neural-interface/lib/file-explorer-watch.js +9 -3
- package/neural-interface/lib/git-bash/install.js +52 -6
- package/neural-interface/lib/git-bash/manager.js +59 -17
- package/neural-interface/lib/git-bash/pins.js +12 -0
- package/neural-interface/lib/git-read.js +2 -2
- package/neural-interface/lib/git-status-runner.js +390 -0
- package/neural-interface/lib/git-status-watchdog.js +40 -0
- package/neural-interface/lib/greeting/budgets.js +1 -0
- package/neural-interface/lib/greeting/engine.js +2 -2
- package/neural-interface/lib/greeting/sources.js +10 -12
- package/neural-interface/lib/greeting/writer.js +1 -1
- package/neural-interface/lib/http-guards.js +8 -2
- package/neural-interface/lib/install-details.js +4 -1
- package/neural-interface/lib/mcp-agent-servers.js +67 -0
- package/neural-interface/lib/mcp-client-config.js +35 -33
- package/neural-interface/lib/mcp-external-servers.js +332 -0
- package/neural-interface/lib/mcp-installer.js +2 -1
- package/neural-interface/lib/{mcp-profile-refresh-coordinator.js → mcp-tools-refresh-coordinator.js} +4 -4
- package/neural-interface/lib/memory-session-capture.js +17 -3
- package/neural-interface/lib/morelogin.js +177 -25
- package/neural-interface/lib/native-loop-providers.js +965 -66
- package/neural-interface/lib/native-loop-runtime.js +290 -42
- package/neural-interface/lib/opencode-config.js +557 -0
- package/neural-interface/lib/opencode-db-schema.js +17 -34
- package/neural-interface/lib/opencode-history.js +48 -218
- package/neural-interface/lib/opencode-mcp-ready.js +108 -0
- package/neural-interface/lib/opencode-native-boundary.js +53 -0
- package/neural-interface/lib/opencode-protocol.js +249 -112
- package/neural-interface/lib/opencode-runtime-config.js +32 -22
- package/neural-interface/lib/opencode-serve-records.js +39 -21
- package/neural-interface/lib/opencode-v2-client.js +48 -153
- package/neural-interface/lib/opencode-v2-ws-requests.js +36 -210
- package/neural-interface/lib/opencode-worker-data.js +27 -0
- package/neural-interface/lib/opencode2-client.js +73 -37
- package/neural-interface/lib/opencode2-proxy.js +23 -63
- package/neural-interface/lib/opencode2-translate.js +51 -2
- package/neural-interface/lib/owner-authority.js +249 -0
- package/neural-interface/lib/page-session.js +275 -0
- package/neural-interface/lib/path-confine.js +12 -9
- package/neural-interface/lib/peer-identity.js +793 -0
- package/neural-interface/lib/pty-host/core.js +28 -1
- package/neural-interface/lib/pty-host/lifetime.js +12 -0
- package/neural-interface/lib/pty-host/manager.js +12 -1
- package/neural-interface/lib/remote-policy.js +1 -1
- package/neural-interface/lib/request-gate.js +20 -2
- package/neural-interface/lib/rulesets/api.js +7 -6
- package/neural-interface/lib/rulesets/fs-safe.js +1 -1
- package/neural-interface/lib/rulesets/installer.js +180 -36
- package/neural-interface/lib/rulesets/json-edit.js +1 -1
- package/neural-interface/lib/rulesets/render.js +1 -1
- package/neural-interface/lib/session-cache-builder.js +81 -31
- package/neural-interface/lib/session-title-generator.js +58 -36
- package/neural-interface/lib/skills/api-v2.js +495 -0
- package/neural-interface/lib/skills/bundle.js +418 -0
- package/neural-interface/lib/skills/catalog.js +298 -0
- package/neural-interface/lib/skills/creation-api.js +191 -0
- package/neural-interface/lib/skills/creation-brief.js +247 -0
- package/neural-interface/lib/skills/creation-sources.js +285 -0
- package/neural-interface/lib/skills/creation.js +843 -0
- package/neural-interface/lib/skills/deploy.js +569 -0
- package/neural-interface/lib/skills/digest.js +119 -0
- package/neural-interface/lib/skills/discover.js +111 -0
- package/neural-interface/lib/skills/draft-confinement.js +216 -0
- package/neural-interface/lib/skills/eval-confinement.js +399 -0
- package/neural-interface/lib/skills/eval-sandbox.js +280 -0
- package/neural-interface/lib/skills/eval-trace.js +135 -0
- package/neural-interface/lib/skills/evals-api.js +212 -0
- package/neural-interface/lib/skills/evals.js +1573 -0
- package/neural-interface/lib/skills/export.js +203 -0
- package/neural-interface/lib/skills/frontmatter.js +64 -0
- package/neural-interface/lib/skills/health.js +75 -0
- package/neural-interface/lib/skills/json-edit.js +165 -0
- package/neural-interface/lib/skills/known-bridge-digests.json +441 -0
- package/neural-interface/lib/skills/known-bridges.js +96 -0
- package/neural-interface/lib/skills/library.js +823 -0
- package/neural-interface/lib/skills/local-store.js +21 -0
- package/neural-interface/lib/skills/migration.js +433 -0
- package/neural-interface/lib/skills/operations.js +45 -0
- package/neural-interface/lib/skills/ownership.js +427 -0
- package/neural-interface/lib/skills/packages.js +88 -0
- package/neural-interface/lib/skills/reviews.js +212 -0
- package/neural-interface/lib/skills/revision.js +80 -0
- package/neural-interface/lib/skills/roots.js +269 -0
- package/neural-interface/lib/skills/runtime-checks.js +358 -0
- package/neural-interface/lib/skills/scan-assets.js +252 -0
- package/neural-interface/lib/skills/scan-context.js +26 -0
- package/neural-interface/lib/skills/scan-shell.js +324 -0
- package/neural-interface/lib/skills/scan.js +364 -0
- package/neural-interface/lib/skills/scanners.js +54 -0
- package/neural-interface/lib/skills/service.js +530 -0
- package/neural-interface/lib/skills/telemetry.js +119 -0
- package/neural-interface/lib/sqlite-integrity-worker.js +22 -0
- package/neural-interface/lib/synabun-version.js +1 -1
- package/neural-interface/lib/system-activity.js +1 -1
- package/neural-interface/lib/tool-lists.js +124 -0
- package/neural-interface/lib/whatsapp/brain.js +7 -3
- package/neural-interface/lib/whatsapp/bridge.js +6 -3
- package/neural-interface/lib/whatsapp/cards.js +22 -9
- package/neural-interface/lib/whatsapp/config.js +1 -1
- package/neural-interface/lib/worker-confinement.js +1268 -0
- package/neural-interface/lib/worker-guard-setting.js +56 -0
- package/neural-interface/lib/worker-mcp-channel.js +175 -0
- package/neural-interface/lib/worker-question.js +74 -0
- package/neural-interface/lib/worker-relay-ports.js +227 -0
- package/neural-interface/lib/worker-resume.js +238 -0
- package/neural-interface/lib/worker-sandbox.js +329 -0
- package/neural-interface/package-lock.json +34 -12
- package/neural-interface/package.json +3 -2
- package/neural-interface/public/index.html +3 -1
- package/neural-interface/public/index2d.html +19 -11
- package/neural-interface/public/onboarding.html +3 -3
- package/neural-interface/public/shared/account-menu.js +8 -5
- package/neural-interface/public/shared/agent-runtime-options.js +125 -31
- package/neural-interface/public/shared/agy/agy-bypass.js +47 -0
- package/neural-interface/public/shared/agy/agy-client.js +266 -0
- package/neural-interface/public/shared/agy/agy-commands.js +120 -0
- package/neural-interface/public/shared/agy/agy-copy.js +326 -0
- package/neural-interface/public/shared/agy/agy-diff.js +161 -0
- package/neural-interface/public/shared/agy/agy-events.js +469 -0
- package/neural-interface/public/shared/agy/agy-greeting.js +26 -0
- package/neural-interface/public/shared/agy/agy-options.js +232 -0
- package/neural-interface/public/shared/agy/agy-panel.js +2543 -0
- package/neural-interface/public/shared/agy/agy-render.js +392 -0
- package/neural-interface/public/shared/agy/agy-setup.js +149 -0
- package/neural-interface/public/shared/agy/agy-styles.js +604 -0
- package/neural-interface/public/shared/agy/agy-tabs-logic.js +181 -0
- package/neural-interface/public/shared/api.js +1527 -1336
- package/neural-interface/public/shared/app-frame.js +192 -0
- package/neural-interface/public/shared/assistant/asst-agents-dock.js +36 -6
- package/neural-interface/public/shared/assistant/asst-api.js +1 -1
- package/neural-interface/public/shared/assistant/asst-ask-styles.js +270 -0
- package/neural-interface/public/shared/assistant/asst-ask-tail.js +118 -0
- package/neural-interface/public/shared/assistant/asst-ask.js +397 -0
- package/neural-interface/public/shared/assistant/asst-brain-picker.js +105 -44
- package/neural-interface/public/shared/assistant/asst-budget.js +5 -4
- package/neural-interface/public/shared/assistant/asst-control.js +205 -26
- package/neural-interface/public/shared/assistant/asst-followups-card.js +383 -0
- package/neural-interface/public/shared/assistant/asst-followups.js +417 -0
- package/neural-interface/public/shared/assistant/asst-hosts.js +16 -7
- package/neural-interface/public/shared/assistant/asst-limit-dock.js +45 -0
- package/neural-interface/public/shared/assistant/asst-limit-wait.js +327 -0
- package/neural-interface/public/shared/assistant/asst-limit.js +168 -0
- package/neural-interface/public/shared/assistant/asst-mascot.js +49 -12
- package/neural-interface/public/shared/assistant/asst-menu.js +7 -6
- package/neural-interface/public/shared/assistant/asst-panel.js +151 -19
- package/neural-interface/public/shared/assistant/asst-rack-styles.js +66 -49
- package/neural-interface/public/shared/assistant/asst-render.js +445 -82
- package/neural-interface/public/shared/assistant/asst-route.js +304 -53
- package/neural-interface/public/shared/assistant/asst-routes-editor.js +9 -8
- package/neural-interface/public/shared/assistant/asst-scenes.js +56 -1
- package/neural-interface/public/shared/assistant/asst-sidepanel.js +117 -10
- package/neural-interface/public/shared/assistant/asst-slash.js +17 -9
- package/neural-interface/public/shared/assistant/asst-state.js +87 -24
- package/neural-interface/public/shared/assistant/asst-stop.js +127 -0
- package/neural-interface/public/shared/assistant/asst-styles.js +93 -21
- package/neural-interface/public/shared/assistant/asst-tool-kinds.js +190 -23
- package/neural-interface/public/shared/assistant/asst-usage.js +2 -1
- package/neural-interface/public/shared/automation-context.js +5 -2
- package/neural-interface/public/shared/cc-dropdown.js +89 -19
- package/neural-interface/public/shared/cdx/cdx-context-menu.js +10 -9
- package/neural-interface/public/shared/cdx/cdx-copy.js +16 -0
- package/neural-interface/public/shared/cdx/cdx-output-model.js +22 -1
- package/neural-interface/public/shared/cdx/cdx-output.js +34 -10
- package/neural-interface/public/shared/cdx/cdx-panel.js +59 -151
- package/neural-interface/public/shared/cdx/cdx-preview.js +12 -0
- package/neural-interface/public/shared/cdx/cdx-protocol.js +39 -11
- package/neural-interface/public/shared/cdx/cdx-render.js +57 -38
- package/neural-interface/public/shared/cdx/cdx-requests.js +14 -4
- package/neural-interface/public/shared/cdx/cdx-skill-hints.js +54 -0
- package/neural-interface/public/shared/cdx/cdx-styles.js +15 -3
- package/neural-interface/public/shared/cdx/cdx-tabs.js +127 -44
- package/neural-interface/public/shared/cdx/cdx-ws.js +0 -1
- package/neural-interface/public/shared/cli-install-controller.js +218 -0
- package/neural-interface/public/shared/cli-install-view.js +11 -12
- package/neural-interface/public/shared/cli-status.js +11 -10
- package/neural-interface/public/shared/constants.js +5 -4
- package/neural-interface/public/shared/context-menu-areas.js +34 -0
- package/neural-interface/public/shared/context-menu-logic.js +243 -0
- package/neural-interface/public/shared/context-menu-model.js +367 -0
- package/neural-interface/public/shared/context-menu.js +372 -0
- package/neural-interface/public/shared/cp/cp-context-menu.js +10 -9
- package/neural-interface/public/shared/cp/cp-restore.js +162 -0
- package/neural-interface/public/shared/cp/cp-tool-cards.js +10 -3
- package/neural-interface/public/shared/crash-notice-view.js +168 -0
- package/neural-interface/public/shared/desktop-bridge.js +17 -0
- package/neural-interface/public/shared/desktop-titlebar-view.js +12 -0
- package/neural-interface/public/shared/desktop-titlebar.js +13 -4
- package/neural-interface/public/shared/desktop-update-view.js +21 -0
- package/neural-interface/public/shared/editor/editor-panel-logic.js +2 -2
- package/neural-interface/public/shared/explorer/fx-api.js +4 -4
- package/neural-interface/public/shared/explorer/fx-links.js +3 -3
- package/neural-interface/public/shared/explorer/fx-logic.js +1 -1
- package/neural-interface/public/shared/explorer/fx-main.js +48 -16
- package/neural-interface/public/shared/explorer/fx-tree.js +1 -0
- package/neural-interface/public/shared/greeting/greeting-card.js +2 -2
- package/neural-interface/public/shared/greeting/greeting-view.js +1 -0
- package/neural-interface/public/shared/html-shell.js +30 -15
- package/neural-interface/public/shared/i18n.js +2 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-approvals.js +7 -7
- package/neural-interface/public/shared/ocp-v2/ocp-v2-binding.js +4 -4
- package/neural-interface/public/shared/ocp-v2/ocp-v2-changes-logic.js +3 -101
- package/neural-interface/public/shared/ocp-v2/ocp-v2-childpanel.js +2 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-compact-button.js +1 -3
- package/neural-interface/public/shared/ocp-v2/ocp-v2-composer-logic.js +2 -6
- package/neural-interface/public/shared/ocp-v2/ocp-v2-context-menu.js +11 -11
- package/neural-interface/public/shared/ocp-v2/ocp-v2-context-model.js +0 -3
- package/neural-interface/public/shared/ocp-v2/ocp-v2-events.js +8 -4
- package/neural-interface/public/shared/ocp-v2/ocp-v2-manager.js +7 -7
- package/neural-interface/public/shared/ocp-v2/ocp-v2-outcome-notifications.js +16 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-panel.js +74 -259
- package/neural-interface/public/shared/ocp-v2/ocp-v2-plan.js +1 -2
- package/neural-interface/public/shared/ocp-v2/ocp-v2-projectbar.js +95 -202
- package/neural-interface/public/shared/ocp-v2/ocp-v2-rehydrate.js +13 -4
- package/neural-interface/public/shared/ocp-v2/ocp-v2-render.js +13 -22
- package/neural-interface/public/shared/ocp-v2/ocp-v2-send.js +4 -4
- package/neural-interface/public/shared/ocp-v2/ocp-v2-session-actions.js +8 -61
- package/neural-interface/public/shared/ocp-v2/ocp-v2-sessions-logic.js +2 -91
- package/neural-interface/public/shared/ocp-v2/ocp-v2-slash-hints.js +16 -15
- package/neural-interface/public/shared/ocp-v2/ocp-v2-state.js +8 -21
- package/neural-interface/public/shared/ocp-v2/ocp-v2-status-logic.js +1 -99
- package/neural-interface/public/shared/ocp-v2/ocp-v2-status.js +5 -35
- package/neural-interface/public/shared/ocp-v2/ocp-v2-styles.js +17 -21
- package/neural-interface/public/shared/ocp-v2/{ocp-v2-profile-inheritance.js → ocp-v2-tools-inheritance.js} +16 -16
- package/neural-interface/public/shared/ocp-v2/ocp-v2-ws.js +60 -50
- package/neural-interface/public/shared/page-session.js +96 -0
- package/neural-interface/public/shared/provider-icons.js +4 -2
- package/neural-interface/public/shared/registry.js +5 -3
- package/neural-interface/public/shared/retired-2d.js +3 -0
- package/neural-interface/public/shared/schedules-view.js +195 -61
- package/neural-interface/public/shared/settings/settings-claude-hooks.js +135 -0
- package/neural-interface/public/shared/settings/settings-data.js +3 -1
- package/neural-interface/public/shared/settings/settings-ia.js +6 -6
- package/neural-interface/public/shared/settings/settings-opencode.js +89 -0
- package/neural-interface/public/shared/settings/settings-rules.js +2 -2
- package/neural-interface/public/shared/settings/settings-skill-folders-pane.js +265 -0
- package/neural-interface/public/shared/settings/settings-skill-folders.js +130 -0
- package/neural-interface/public/shared/settings/settings-worker-guard.js +72 -0
- package/neural-interface/public/shared/showcase-privacy.js +6 -1
- package/neural-interface/public/shared/sidepanel-session-status.js +3 -3
- package/neural-interface/public/shared/skills/ss-args.js +96 -0
- package/neural-interface/public/shared/skills/ss-creation.js +222 -0
- package/neural-interface/public/shared/skills/ss-dialog.js +133 -0
- package/neural-interface/public/shared/skills/ss-doc.js +173 -0
- package/neural-interface/public/shared/skills/ss-eval-adapters.js +269 -0
- package/neural-interface/public/shared/skills/ss-eval-grade.js +359 -0
- package/neural-interface/public/shared/skills/ss-eval-optimise.js +153 -0
- package/neural-interface/public/shared/skills/ss-eval-plan.js +315 -0
- package/neural-interface/public/shared/skills/ss-evals.js +417 -0
- package/neural-interface/public/shared/skills/ss-form.js +159 -0
- package/neural-interface/public/shared/skills/ss-frontmatter.js +376 -0
- package/neural-interface/public/shared/skills/ss-ids.js +32 -0
- package/neural-interface/public/shared/skills/ss-lint.js +149 -0
- package/neural-interface/public/shared/skills/ss-presets.js +117 -0
- package/neural-interface/public/shared/skills/ss-profiles.js +513 -0
- package/neural-interface/public/shared/skills/ss-resources.js +165 -0
- package/neural-interface/public/shared/skills/ss-review-view.js +190 -0
- package/neural-interface/public/shared/skills/ss-tabs.js +79 -0
- package/neural-interface/public/shared/skills/ss-unicode.js +135 -0
- package/neural-interface/public/shared/skills/studio/sx-actions.js +222 -0
- package/neural-interface/public/shared/skills/studio/sx-cm.js +101 -0
- package/neural-interface/public/shared/skills/studio/sx-create-ai-view.js +749 -0
- package/neural-interface/public/shared/skills/studio/sx-create-ai.js +237 -0
- package/neural-interface/public/shared/skills/studio/sx-create-view.js +254 -0
- package/neural-interface/public/shared/skills/studio/sx-create.js +126 -0
- package/neural-interface/public/shared/skills/studio/sx-diff-view.js +43 -0
- package/neural-interface/public/shared/skills/studio/sx-diff.js +133 -0
- package/neural-interface/public/shared/skills/studio/sx-docs.js +480 -0
- package/neural-interface/public/shared/skills/studio/sx-dom.js +230 -0
- package/neural-interface/public/shared/skills/studio/sx-edit-view.js +848 -0
- package/neural-interface/public/shared/skills/studio/sx-editor-model.js +193 -0
- package/neural-interface/public/shared/skills/studio/sx-errors.js +22 -0
- package/neural-interface/public/shared/skills/studio/sx-fixes-view.js +359 -0
- package/neural-interface/public/shared/skills/studio/sx-fixes.js +327 -0
- package/neural-interface/public/shared/skills/studio/sx-geometry.js +82 -0
- package/neural-interface/public/shared/skills/studio/sx-import.js +262 -0
- package/neural-interface/public/shared/skills/studio/sx-inspector.js +308 -0
- package/neural-interface/public/shared/skills/studio/sx-install-flow.js +282 -0
- package/neural-interface/public/shared/skills/studio/sx-install.js +313 -0
- package/neural-interface/public/shared/skills/studio/sx-library-view.js +748 -0
- package/neural-interface/public/shared/skills/studio/sx-library.js +479 -0
- package/neural-interface/public/shared/skills/studio/sx-main.js +690 -0
- package/neural-interface/public/shared/skills/studio/sx-operations-view.js +98 -0
- package/neural-interface/public/shared/skills/studio/sx-operations.js +11 -0
- package/neural-interface/public/shared/skills/studio/sx-plan.js +158 -0
- package/neural-interface/public/shared/skills/studio/sx-publish-view.js +621 -0
- package/neural-interface/public/shared/skills/studio/sx-review-view.js +369 -0
- package/neural-interface/public/shared/skills/studio/sx-review.js +148 -0
- package/neural-interface/public/shared/skills/studio/sx-scan.js +35 -0
- package/neural-interface/public/shared/skills/studio/sx-snippets.js +96 -0
- package/neural-interface/public/shared/skills/studio/sx-subject.js +249 -0
- package/neural-interface/public/shared/skills/studio/sx-test-view.js +994 -0
- package/neural-interface/public/shared/skills/studio/sx-test.js +328 -0
- package/neural-interface/public/shared/skills/studio/sx-versions-view.js +241 -0
- package/neural-interface/public/shared/skills/studio/sx-workspace-view.js +426 -0
- package/neural-interface/public/shared/state.js +1 -1
- package/neural-interface/public/shared/streaming-markdown.js +58 -0
- package/neural-interface/public/shared/styleguide/sg-panel.js +4 -2
- package/neural-interface/public/shared/styles.css +1822 -1756
- package/neural-interface/public/shared/synabun-mascot.js +1115 -9
- package/neural-interface/public/shared/text-cache.js +29 -0
- package/neural-interface/public/shared/tool-list-picker.js +55 -0
- package/neural-interface/public/shared/tool-list-storage.js +24 -0
- package/neural-interface/public/shared/tool-list-view.js +112 -0
- package/neural-interface/public/shared/topright-overflow-logic.js +54 -0
- package/neural-interface/public/shared/tour/tour-actor.js +268 -0
- package/neural-interface/public/shared/tour/tour-beats.js +336 -0
- package/neural-interface/public/shared/tour/tour-engine.js +884 -0
- package/neural-interface/public/shared/tour/tour-ink.js +390 -0
- package/neural-interface/public/shared/tour/tour-stage.js +440 -0
- package/neural-interface/public/shared/tour/tour-state.js +40 -0
- package/neural-interface/public/shared/tour/tour-tips.js +99 -0
- package/neural-interface/public/shared/tour/tour.css +144 -0
- package/neural-interface/public/shared/ui-antigravity-panel.js +19 -0
- package/neural-interface/public/shared/ui-assistant.js +2 -0
- package/neural-interface/public/shared/ui-automation-studio.js +111 -140
- package/neural-interface/public/shared/ui-claude-panel.js +376 -82
- package/neural-interface/public/shared/ui-cli-banner.js +23 -167
- package/neural-interface/public/shared/ui-command-runner.js +6 -3
- package/neural-interface/public/shared/ui-context-menu.js +295 -0
- package/neural-interface/public/shared/ui-cost-widget.js +57 -59
- package/neural-interface/public/shared/ui-crash-notice.js +187 -0
- package/neural-interface/public/shared/ui-detail.js +15 -3
- package/neural-interface/public/shared/ui-file-explorer.js +48 -6
- package/neural-interface/public/shared/ui-file-links.js +2 -2
- package/neural-interface/public/shared/ui-games.js +2 -2
- package/neural-interface/public/shared/ui-image-gallery.js +50 -47
- package/neural-interface/public/shared/ui-judgments.js +1 -1
- package/neural-interface/public/shared/ui-keybinds.js +33 -2
- package/neural-interface/public/shared/ui-link.js +3 -3
- package/neural-interface/public/shared/ui-menubar.js +10 -20
- package/neural-interface/public/shared/ui-native-loop-router-state.js +5 -0
- package/neural-interface/public/shared/ui-native-loop-router.js +11 -1
- package/neural-interface/public/shared/ui-navbar.js +49 -24
- package/neural-interface/public/shared/ui-notifications.js +1 -0
- package/neural-interface/public/shared/ui-panels.js +96 -65
- package/neural-interface/public/shared/ui-resume.js +9 -7
- package/neural-interface/public/shared/ui-schedules-studio.js +546 -431
- package/neural-interface/public/shared/ui-scroll-follow.js +16 -5
- package/neural-interface/public/shared/ui-sessions.js +27 -15
- package/neural-interface/public/shared/ui-settings.js +683 -526
- package/neural-interface/public/shared/ui-sidepanel-session-entry.js +9 -2
- package/neural-interface/public/shared/ui-sidepanel-sessions.js +4 -4
- package/neural-interface/public/shared/ui-sidepanel-state.js +23 -12
- package/neural-interface/public/shared/ui-sidepanel-tray.js +48 -7
- package/neural-interface/public/shared/ui-sidepanel-windows.js +18 -13
- package/neural-interface/public/shared/ui-skills.js +33 -2830
- package/neural-interface/public/shared/ui-styleguide.js +5 -2
- package/neural-interface/public/shared/ui-sync.js +15 -5
- package/neural-interface/public/shared/ui-terminal.js +270 -190
- package/neural-interface/public/shared/ui-tool-updates.js +6 -4
- package/neural-interface/public/shared/ui-tooltip.js +81 -51
- package/neural-interface/public/shared/ui-topright-overflow.js +233 -0
- package/neural-interface/public/shared/ui-trash.js +6 -4
- package/neural-interface/public/shared/ui-tutorial-layout.js +3 -117
- package/neural-interface/public/shared/ui-tutorial-preview.js +103 -0
- package/neural-interface/public/shared/ui-tutorial-steps.js +3 -65
- package/neural-interface/public/shared/ui-tutorial.css +47 -100
- package/neural-interface/public/shared/ui-tutorial.js +285 -509
- package/neural-interface/public/shared/ui-update.js +38 -2
- package/neural-interface/public/shared/ui-whiteboard.js +312 -59
- package/neural-interface/public/shared/ui-worker-end.js +5 -1
- package/neural-interface/public/shared/ui-workspaces.js +3 -2
- package/neural-interface/public/shared/view-variant.js +66 -0
- package/neural-interface/public/shared/whatsapp/wa-view.js +3 -3
- package/neural-interface/public/shared/whiteboard-list.js +172 -0
- package/neural-interface/public/shared/worker-end.js +10 -3
- package/neural-interface/public/shared/worker-questions.js +34 -0
- package/neural-interface/public/shared/worker-restart.js +12 -0
- package/neural-interface/public/sidepanel-session.html +2 -2
- package/neural-interface/public/variant/2d/background.js +2 -1
- package/neural-interface/public/variant/2d/context-menu.js +8 -2
- package/neural-interface/public/variant/2d/graph.js +42 -20
- package/neural-interface/public/variant/2d/hulls.js +14 -9
- package/neural-interface/public/variant/2d/lasso.js +11 -7
- package/neural-interface/public/variant/2d/main.js +32 -1
- package/neural-interface/public/variant/2d/minimap.js +11 -13
- package/neural-interface/public/variant/3d/main.js +69 -6
- package/neural-interface/public/variant/3d/map-controls.js +24 -9
- package/neural-interface/public/vendor/caveat/OFL.txt +93 -0
- package/neural-interface/public/vendor/caveat/caveat-latin-400-normal.woff2 +0 -0
- package/neural-interface/public/vendor/caveat/caveat-latin-700-normal.woff2 +0 -0
- package/neural-interface/public/vendor/caveat/caveat.css +17 -0
- package/neural-interface/public/vendor/caveat/manifest.json +12 -0
- package/neural-interface/public/vendor/yaml/LICENSE +13 -0
- package/neural-interface/public/vendor/yaml/manifest.json +4 -0
- package/neural-interface/public/vendor/yaml/yaml-2.9.1.min.js +137 -0
- package/neural-interface/scripts/build-vendor.mjs +32 -0
- package/neural-interface/server.js +4553 -2855
- package/neural-interface/templates/rulesets/README.md +1 -1
- package/neural-interface/templates/rulesets/core.md +1 -1
- package/neural-interface/templates/rulesets/legacy-hashes.json +23 -5
- package/neural-interface/templates/rulesets/manifest.json +8 -8
- package/npm-shrinkwrap.json +34 -12
- package/package.json +17 -3
- package/postinstall.js +9 -4
- package/preuninstall.js +1 -1
- package/setup.js +97 -322
- package/skills/skill-forge/SKILL.md +177 -0
- package/skills/skill-forge/evals/evals.json +54 -0
- package/skills/skill-forge/references/package.md +105 -0
- package/skills/skill-forge/references/review-and-recovery.md +63 -0
- package/skills/skill-forge/references/runtime-profiles.md +20 -0
- package/skills/skill-forge/references/sources-and-capabilities.md +51 -0
- package/skills/synabun/SKILL.md +10 -7
- package/skills/synabun/modules/audit.md +1 -5
- package/skills/synabun/modules/changelog.md +1 -5
- package/skills/synabun/modules/idea.md +1 -1
- package/skills/synabun/modules/memorize.md +6 -9
- package/skills/synabun/modules/schedule.md +6 -6
- package/mcp-server/dist/services/profiles.d.ts +0 -120
- package/mcp-server/dist/services/profiles.d.ts.map +0 -1
- package/mcp-server/dist/services/profiles.js +0 -387
- package/mcp-server/dist/services/profiles.js.map +0 -1
- package/mcp-server/dist/tools/leonardo-browser-tools.d.ts +0 -97
- package/mcp-server/dist/tools/leonardo-browser-tools.d.ts.map +0 -1
- package/mcp-server/dist/tools/leonardo-browser-tools.js +0 -228
- package/mcp-server/dist/tools/leonardo-browser-tools.js.map +0 -1
- package/mcp-server/dist/tools/leonardo.d.ts +0 -13
- package/mcp-server/dist/tools/leonardo.d.ts.map +0 -1
- package/mcp-server/dist/tools/leonardo.js +0 -21
- package/mcp-server/dist/tools/leonardo.js.map +0 -1
- package/mcp-server/dist/tools/profile.d.ts +0 -17
- package/mcp-server/dist/tools/profile.d.ts.map +0 -1
- package/mcp-server/dist/tools/profile.js +0 -114
- package/mcp-server/dist/tools/profile.js.map +0 -1
- package/mcp-server/src/services/profiles.ts +0 -428
- package/mcp-server/src/tools/leonardo-browser-tools.ts +0 -291
- package/mcp-server/src/tools/leonardo.ts +0 -30
- package/mcp-server/src/tools/profile.ts +0 -122
- package/neural-interface/lib/assistant-brains/opencode-browser-policy.js +0 -47
- package/neural-interface/lib/assistant-brains/opencode-route-gate.js +0 -62
- package/neural-interface/lib/mcp-profile-servers.js +0 -120
- package/neural-interface/public/shared/ui-tutorial-draw.js +0 -311
- package/skills/leonardo/SKILL.md +0 -168
- package/skills/leonardo/icon.svg +0 -1
- package/skills/leonardo/modules/browser-guide.md +0 -378
- package/skills/leonardo/modules/image-prompter.md +0 -283
- package/skills/leonardo/modules/model-advisor.md +0 -100
- package/skills/leonardo/modules/prompt-library.md +0 -110
- package/skills/leonardo/modules/style-guide.md +0 -186
- package/skills/leonardo/modules/video-prompter.md +0 -317
- /package/neural-interface/templates/rulesets/{gemini.md → antigravity.md} +0 -0
|
@@ -0,0 +1,476 @@
|
|
|
1
|
+
// Playwright context.route(), even with a narrow matcher, enables Fetch("*")
|
|
2
|
+
// AND disables HTTP cache on every target. Keep our safety rules on a separate
|
|
3
|
+
// CDP client with native, selective Fetch patterns. Never change cache, Runtime,
|
|
4
|
+
// identity, emulation, or page scripts here. Unmatched requests stay in Chromium.
|
|
5
|
+
//
|
|
6
|
+
// Auto-attach pauses new pages, OOPIFs and workers so
|
|
7
|
+
// their FIRST request is guarded too. Closing this client releases its sessions;
|
|
8
|
+
// it never closes a user's target or browser.
|
|
9
|
+
//
|
|
10
|
+
// Faults are per target first. A target is protected once its Fetch rules are in
|
|
11
|
+
// place; releasing it (Runtime.runIfWaitingForDebugger) is not part of that, and its
|
|
12
|
+
// reply comes from the target itself once it actually runs: Chromium holds a new
|
|
13
|
+
// service worker until EVERY auto-attached CDP client has released it, and does not
|
|
14
|
+
// answer a stopped worker's Runtime commands until it runs again. A slow or silent
|
|
15
|
+
// reply is therefore never a fault. A paused service/shared worker whose rules cannot
|
|
16
|
+
// be installed stays paused and is retried; pages, frames, dedicated workers and
|
|
17
|
+
// targets already running still fail closed for the whole context, and a faulted
|
|
18
|
+
// context re-arms with a fresh attachment (recoverBrowserNetworkGuard).
|
|
19
|
+
import { connectGuardCdp } from './browser-guard-cdp.js';
|
|
20
|
+
const guards = new WeakMap();
|
|
21
|
+
const endpoints = new WeakMap();
|
|
22
|
+
const legacyRules = new WeakMap();
|
|
23
|
+
const FILTER = ['page', 'iframe', 'worker', 'shared_worker', 'service_worker'].map(type => ({ type }));
|
|
24
|
+
const AUTO = { autoAttach: true, waitForDebuggerOnStart: true, flatten: true, filter: FILTER };
|
|
25
|
+
const gone = error => /closed|detached|No session|No target|Target.*not found|Session with given id not found/i.test(error?.message || '');
|
|
26
|
+
const expiredRequest = error => /^Fetch\.(?:continueRequest|failRequest)$/.test(error?.method || '')
|
|
27
|
+
&& /Invalid InterceptionId|Invalid interception id/i.test(error.message);
|
|
28
|
+
// Workers whose own requests only their own Fetch rules intercept. Dedicated workers
|
|
29
|
+
// are intercepted by their owning page or frame instead.
|
|
30
|
+
const OWN_FETCH_WORKERS = new Set(['service_worker', 'shared_worker']);
|
|
31
|
+
const TIMING = {
|
|
32
|
+
quarantineRetryMs: [1000, 5000, 15000, 60000], // the last delay repeats while the worker exists
|
|
33
|
+
rearmBackoffMs: [2000, 5000, 15000, 30000, 60000], // after a failed re-arm; the last repeats
|
|
34
|
+
recoverTimeoutMs: 10000, // the longest a caller waits for one re-arm
|
|
35
|
+
};
|
|
36
|
+
export const NETWORK_GUARD_FAULT_EVENT = 'synabun-network-guard-fault';
|
|
37
|
+
export const NETWORK_GUARD_RECOVERED_EVENT = 'synabun-network-guard-recovered';
|
|
38
|
+
|
|
39
|
+
/** Register only externally owned Chromium contexts with an existing endpoint. */
|
|
40
|
+
export function registerBrowserNetworkEndpoint(context, endpoint, { connect = connectGuardCdp, timing } = {}) {
|
|
41
|
+
endpoints.set(context, { endpoint, connect, timing: { ...TIMING, ...timing } });
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function usesNativeBrowserNetworkGuard(context) { return endpoints.has(context); }
|
|
45
|
+
|
|
46
|
+
/** One flattened CDP connection and every session it holds. Re-arming replaces it whole. */
|
|
47
|
+
class GuardLink {
|
|
48
|
+
constructor(guard) {
|
|
49
|
+
this.guard = guard;
|
|
50
|
+
this.children = new Map();
|
|
51
|
+
this.installing = new Set();
|
|
52
|
+
this.timers = new Set();
|
|
53
|
+
this.fault = null;
|
|
54
|
+
this.closed = false;
|
|
55
|
+
}
|
|
56
|
+
/** A fault of this link. It is the context's fault only while this link is the current one. */
|
|
57
|
+
failed(error) {
|
|
58
|
+
if (this.closed) return;
|
|
59
|
+
this.fault ||= error;
|
|
60
|
+
if (this.guard.link === this) this.guard.fault = error;
|
|
61
|
+
}
|
|
62
|
+
later(delay, work) {
|
|
63
|
+
if (this.closed) return;
|
|
64
|
+
const timer = setTimeout(() => { this.timers.delete(timer); if (!this.closed) work(); }, delay);
|
|
65
|
+
timer.unref?.();
|
|
66
|
+
this.timers.add(timer);
|
|
67
|
+
}
|
|
68
|
+
async open() {
|
|
69
|
+
const { endpoint, connect } = endpoints.get(this.guard.context);
|
|
70
|
+
this.connecting = connect(endpoint);
|
|
71
|
+
this.root = await this.connecting;
|
|
72
|
+
if (this.closed) { await this.root.detach(); throw new Error('Network guard disposed during setup'); }
|
|
73
|
+
this.root.on('event', event => this.dispatch(event.sessionId ? this.children.get(event.sessionId) : this.root, event.method, event.params));
|
|
74
|
+
this.root.on('close', () => {
|
|
75
|
+
if (this.closed) return;
|
|
76
|
+
this.failed(new Error('Network guard CDP disconnected; reconnect the browser session'));
|
|
77
|
+
// Cancel pending automation and refuse subsequent actions until a fresh
|
|
78
|
+
// protected attachment exists. Never reinstate context.route on MoreLogin:
|
|
79
|
+
// it would mutate unrelated native traffic and cache even during teardown.
|
|
80
|
+
console.error('[browser-network-guard] CDP disconnected; browser automation refused until the guard re-arms');
|
|
81
|
+
});
|
|
82
|
+
// A page-target attachment can arrive after a popup's initial navigation
|
|
83
|
+
// has started (another CDP client may resume it). The browser Fetch domain
|
|
84
|
+
// closes that gap for selective Document requests only. Attribute each to
|
|
85
|
+
// this profile before deciding; never apply rules to a foreign context.
|
|
86
|
+
await this.configure(this.root);
|
|
87
|
+
await this.root.send('Target.setAutoAttach', AUTO);
|
|
88
|
+
while (this.installing.size) await Promise.all([...this.installing]);
|
|
89
|
+
if (this.fault) throw this.fault;
|
|
90
|
+
}
|
|
91
|
+
async configure(child) {
|
|
92
|
+
// Dedicated workers have no Fetch domain in Chromium. Their requests are
|
|
93
|
+
// intercepted by the owning page/frame (also for nested workers), as in
|
|
94
|
+
// Playwright's CRNetworkManager workerFrame path. Never resume a worker
|
|
95
|
+
// until that parent's current selective guard is installed.
|
|
96
|
+
if (child.target?.type === 'worker') {
|
|
97
|
+
if (!child.parent?.guarded || child.parent.quarantined || !child.parent.configuration) {
|
|
98
|
+
throw new Error(`Network guard worker ${child.target.targetId} has no protected network parent`);
|
|
99
|
+
}
|
|
100
|
+
await child.parent.configuration;
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
const patterns = this.guard.patterns().map(pattern => child === this.root ? { ...pattern, resourceType: 'Document' } : pattern);
|
|
104
|
+
await child.send(patterns.length ? 'Fetch.enable' : 'Fetch.disable', patterns.length ? { patterns } : {});
|
|
105
|
+
}
|
|
106
|
+
/** Rules in place for the target and for what it starts next. */
|
|
107
|
+
async protect(child) {
|
|
108
|
+
await (child.configuration = this.configure(child));
|
|
109
|
+
if (this.closed) return;
|
|
110
|
+
await child.send('Target.setAutoAttach', AUTO);
|
|
111
|
+
child.protected = true;
|
|
112
|
+
}
|
|
113
|
+
/** Release a target this client holds paused. Never awaited and never a fault: the
|
|
114
|
+
* reply comes from the target once it actually runs, which another CDP client of the
|
|
115
|
+
* profile, or a stopped service worker, can delay indefinitely. The target's rules are
|
|
116
|
+
* already in place, so its requests are guarded whenever it runs. */
|
|
117
|
+
resume(child) {
|
|
118
|
+
child.send('Runtime.runIfWaitingForDebugger').catch(error => {
|
|
119
|
+
if (this.closed || gone(error)) return;
|
|
120
|
+
console.warn(`[browser-network-guard] ${error.message}; the target keeps its rules and runs when Chromium releases it`);
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
/** Whether a failed command's target is gone, which is no fault. A reply can be lost
|
|
124
|
+
* while its target is destroyed, so a timeout asks the browser before deciding. */
|
|
125
|
+
async vanished(child, error) {
|
|
126
|
+
if (this.closed || gone(error) || this.children.get(child.id) !== child) return true;
|
|
127
|
+
try {
|
|
128
|
+
const { targetInfo } = await this.root.send('Target.getTargetInfo', { targetId: child.target.targetId });
|
|
129
|
+
return !targetInfo;
|
|
130
|
+
} catch (probe) {
|
|
131
|
+
return /No target with given id/i.test(probe.protocolMessage || probe.message);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
/** A paused service/shared worker whose rules could not be installed. Nothing else
|
|
135
|
+
* intercepts its requests, so it must not run unprotected: keep holding it paused
|
|
136
|
+
* (no other target is affected), retry, and release it once its rules are in place. */
|
|
137
|
+
quarantine(child, error, attempt = 0) {
|
|
138
|
+
child.quarantined = error;
|
|
139
|
+
const delays = this.guard.timing.quarantineRetryMs;
|
|
140
|
+
const delay = delays[Math.min(attempt, delays.length - 1)];
|
|
141
|
+
if (!attempt) console.error(`[browser-network-guard] ${error.message}; this worker stays paused, retrying its protection`);
|
|
142
|
+
this.later(delay, async () => {
|
|
143
|
+
if (this.children.get(child.id) !== child) return;
|
|
144
|
+
try {
|
|
145
|
+
await this.protect(child);
|
|
146
|
+
} catch (retryError) {
|
|
147
|
+
if (await this.vanished(child, retryError)) return;
|
|
148
|
+
this.quarantine(child, retryError, attempt + 1);
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
if (this.closed) return;
|
|
152
|
+
child.quarantined = null;
|
|
153
|
+
console.warn(`[browser-network-guard] worker ${child.target.targetId} protected after ${attempt + 1} retr${attempt ? 'ies' : 'y'}; releasing it`);
|
|
154
|
+
this.resume(child);
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
async ownsDocument(frameId) {
|
|
158
|
+
try {
|
|
159
|
+
const { targetInfo } = await this.root.send('Target.getTargetInfo', { targetId: frameId });
|
|
160
|
+
return targetInfo.browserContextId === this.guard.contextId;
|
|
161
|
+
} catch (error) {
|
|
162
|
+
// Same-process subframes have frame IDs, but no separate Target. Find
|
|
163
|
+
// their owning protected page; unrelated incognito frames stay native.
|
|
164
|
+
if (!/No target with given id found/i.test(error.message)) throw error;
|
|
165
|
+
const contains = tree => tree.frame.id === frameId || tree.childFrames?.some(contains);
|
|
166
|
+
let uncertain = false;
|
|
167
|
+
for (const child of this.children.values()) {
|
|
168
|
+
if (!child.guarded || !['page', 'iframe'].includes(child.target.type)) continue;
|
|
169
|
+
try {
|
|
170
|
+
if (contains((await child.send('Page.getFrameTree')).frameTree)) return true;
|
|
171
|
+
} catch (treeError) { if (!gone(treeError)) uncertain = true; }
|
|
172
|
+
}
|
|
173
|
+
// A protected page that cannot list its frames may hold this one. Decide it as
|
|
174
|
+
// the profile's (the stricter answer) instead of faulting every tab.
|
|
175
|
+
return uncertain;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
dispatch(parent, method, event) {
|
|
179
|
+
if (this.closed) return;
|
|
180
|
+
if (method === 'Target.attachedToTarget') {
|
|
181
|
+
const child = {
|
|
182
|
+
id: event.sessionId, parent, target: event.targetInfo,
|
|
183
|
+
send: async (method, params) => {
|
|
184
|
+
try { return await this.root.send(method, params, event.sessionId); }
|
|
185
|
+
catch (error) {
|
|
186
|
+
Object.assign(error, { method, targetType: child.target.type, targetId: child.target.targetId,
|
|
187
|
+
parentTargetType: parent?.target?.type, parentTargetId: parent?.target?.targetId });
|
|
188
|
+
error.message = `${method} [target=${child.target.type}:${child.target.targetId}, session=${child.id}, parent=${parent?.target?.type || 'browser'}:${parent?.target?.targetId || 'root'}]: ${error.protocolMessage || error.message}`;
|
|
189
|
+
throw error;
|
|
190
|
+
}
|
|
191
|
+
},
|
|
192
|
+
close: () => this.root.rejectSession(event.sessionId),
|
|
193
|
+
};
|
|
194
|
+
this.children.set(event.sessionId, child);
|
|
195
|
+
const installing = this.attach(child, event).catch(error => {
|
|
196
|
+
if (!gone(error)) {
|
|
197
|
+
this.failed(error);
|
|
198
|
+
// Do not resume an unguarded new target. Existing user tabs are never
|
|
199
|
+
// closed. Tool operations fail until the guard re-arms.
|
|
200
|
+
console.error('[browser-network-guard] target protection failed:', error.message);
|
|
201
|
+
}
|
|
202
|
+
}).finally(() => this.installing.delete(installing));
|
|
203
|
+
this.installing.add(installing);
|
|
204
|
+
} else if (method === 'Target.detachedFromTarget') {
|
|
205
|
+
this.children.get(event.sessionId)?.close();
|
|
206
|
+
this.children.delete(event.sessionId);
|
|
207
|
+
} else if (method === 'Fetch.requestPaused') {
|
|
208
|
+
if (!parent) return; // event queued before this target's detach arrived
|
|
209
|
+
void this.request(parent, event).catch(error => {
|
|
210
|
+
if (!gone(error)) { this.failed(error); console.error('[browser-network-guard] request refused after guard failure:', error.message); }
|
|
211
|
+
});
|
|
212
|
+
} else if (method === 'Inspector.targetReloadedAfterCrash') {
|
|
213
|
+
// A stopped service worker that runs again keeps this session and its rules.
|
|
214
|
+
// Release it as Playwright does, so this client never holds it.
|
|
215
|
+
if (parent?.protected && !parent.quarantined) this.resume(parent);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
async attach(child, event) {
|
|
219
|
+
if (this.closed) return;
|
|
220
|
+
const waiting = !!event.waitingForDebugger;
|
|
221
|
+
const inherited = !event.targetInfo.browserContextId && child.parent?.guarded;
|
|
222
|
+
if (event.targetInfo.browserContextId !== this.guard.contextId && !inherited) {
|
|
223
|
+
// A browser-level CDP connection also sees other incognito contexts. Our
|
|
224
|
+
// session there intercepts nothing: releasing it is never this profile's fault.
|
|
225
|
+
if (waiting) this.resume(child);
|
|
226
|
+
await child.parent.send('Target.detachFromTarget', { sessionId: child.id }).catch(error => {
|
|
227
|
+
if (!gone(error)) console.warn('[browser-network-guard] could not release a foreign target:', error.message);
|
|
228
|
+
});
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
child.guarded = true;
|
|
232
|
+
try {
|
|
233
|
+
await this.protect(child);
|
|
234
|
+
} catch (error) {
|
|
235
|
+
if (await this.vanished(child, error)) return;
|
|
236
|
+
if (waiting && OWN_FETCH_WORKERS.has(child.target.type)) { this.quarantine(child, error); return; }
|
|
237
|
+
// Pages, frames, dedicated workers and anything already running fail closed.
|
|
238
|
+
throw error;
|
|
239
|
+
}
|
|
240
|
+
if (this.closed) return;
|
|
241
|
+
// Only a target that waits for us is released; a running or stopped one is not.
|
|
242
|
+
if (waiting) this.resume(child);
|
|
243
|
+
}
|
|
244
|
+
async request(child, event) {
|
|
245
|
+
const { requestId, request } = event;
|
|
246
|
+
try {
|
|
247
|
+
const fault = this.fault || this.guard.fault;
|
|
248
|
+
if (fault) throw fault;
|
|
249
|
+
if (child === this.root && !await this.ownsDocument(event.frameId)) {
|
|
250
|
+
await child.send('Fetch.continueRequest', { requestId });
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
let headers;
|
|
254
|
+
for (const rule of this.guard.rules.values()) {
|
|
255
|
+
const decision = rule.decide(request);
|
|
256
|
+
if (decision?.abort) {
|
|
257
|
+
await child.send('Fetch.failRequest', { requestId, errorReason: 'BlockedByClient' });
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
if (decision?.headers) headers = { ...headers, ...decision.headers };
|
|
261
|
+
}
|
|
262
|
+
const params = { requestId };
|
|
263
|
+
if (headers) {
|
|
264
|
+
const replacements = new Set(Object.keys(headers).map(name => name.toLowerCase()));
|
|
265
|
+
params.headers = Object.entries(request.headers).filter(([name]) => !replacements.has(name.toLowerCase()))
|
|
266
|
+
.concat(Object.entries(headers)).map(([name, value]) => ({ name, value: String(value) }));
|
|
267
|
+
}
|
|
268
|
+
await child.send('Fetch.continueRequest', params);
|
|
269
|
+
} catch (error) {
|
|
270
|
+
// A navigation/closed tab can retire the request before continue/fail is
|
|
271
|
+
// processed. These protocol replies do not invalidate other targets.
|
|
272
|
+
if (gone(error) || expiredRequest(error)) return;
|
|
273
|
+
// Never continue without a required financial/local marker decision.
|
|
274
|
+
await child.send('Fetch.failRequest', { requestId, errorReason: 'BlockedByClient' }).catch(() => {});
|
|
275
|
+
throw error;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
/** Current rules onto every protected target of this link. */
|
|
279
|
+
async reconfigure() {
|
|
280
|
+
await this.configure(this.root);
|
|
281
|
+
// A quarantined worker takes the current rules on its next retry.
|
|
282
|
+
await Promise.all([...this.children.values()].filter(child => child.guarded && !child.quarantined).map(async child => {
|
|
283
|
+
try { await (child.configuration = this.configure(child)); }
|
|
284
|
+
catch (error) { if (!await this.vanished(child, error)) throw error; }
|
|
285
|
+
}));
|
|
286
|
+
}
|
|
287
|
+
close() {
|
|
288
|
+
if (this.closing) return this.closing;
|
|
289
|
+
this.closed = true;
|
|
290
|
+
for (const timer of this.timers) clearTimeout(timer);
|
|
291
|
+
this.timers.clear();
|
|
292
|
+
// Detaching our browser CDP session also detaches its child sessions and
|
|
293
|
+
// releases paused targets. No Target.closeTarget or Browser.close.
|
|
294
|
+
this.closing = (async () => {
|
|
295
|
+
// Closing may race a handshake. Await and detach that late connection
|
|
296
|
+
// as well; returning early would briefly leave a new client attached.
|
|
297
|
+
if (!this.root && this.connecting) this.root = await this.connecting.catch(() => null);
|
|
298
|
+
await this.root?.detach().catch(() => {});
|
|
299
|
+
for (const child of this.children.values()) child.close();
|
|
300
|
+
this.children.clear();
|
|
301
|
+
})();
|
|
302
|
+
return this.closing;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
class ContextGuard {
|
|
307
|
+
get fault() { return this._fault; }
|
|
308
|
+
set fault(error) {
|
|
309
|
+
if (this.disposed) return;
|
|
310
|
+
this._fault = error;
|
|
311
|
+
if (error) {
|
|
312
|
+
this.context.__browserNetworkGuardError = error.message;
|
|
313
|
+
this.context.emit?.(NETWORK_GUARD_FAULT_EVENT, error.message);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
constructor(context) {
|
|
317
|
+
this.context = context;
|
|
318
|
+
this.timing = endpoints.get(context)?.timing || TIMING;
|
|
319
|
+
this.rules = new Map();
|
|
320
|
+
this.fault = null;
|
|
321
|
+
this.queue = Promise.resolve();
|
|
322
|
+
this.rearmFailures = 0;
|
|
323
|
+
this.rearmAt = 0;
|
|
324
|
+
}
|
|
325
|
+
patterns() {
|
|
326
|
+
return [...new Set([...this.rules.values()].flatMap(rule => rule.patterns))].map(urlPattern => ({ urlPattern, requestStage: 'Request' }));
|
|
327
|
+
}
|
|
328
|
+
async start() {
|
|
329
|
+
this.onContextClose = () => { void this.dispose(); };
|
|
330
|
+
this.onBrowserDisconnect = () => { void this.dispose(); };
|
|
331
|
+
this.context.once('close', this.onContextClose);
|
|
332
|
+
this.context.browser().once('disconnected', this.onBrowserDisconnect);
|
|
333
|
+
const page = this.context.pages().find(page => !page.isClosed());
|
|
334
|
+
if (!page) throw new Error('Network guard requires the attachment tab');
|
|
335
|
+
const probe = await this.context.newCDPSession(page);
|
|
336
|
+
try { this.contextId = (await probe.send('Target.getTargetInfo')).targetInfo.browserContextId; }
|
|
337
|
+
finally { await probe.detach(); }
|
|
338
|
+
if (this.disposed) throw new Error('Network guard disposed during setup');
|
|
339
|
+
this.link = new GuardLink(this);
|
|
340
|
+
await this.link.open();
|
|
341
|
+
}
|
|
342
|
+
async update(key, rule) {
|
|
343
|
+
if (this.disposed) throw new Error('Network guard disposed');
|
|
344
|
+
if (this.fault) throw this.fault;
|
|
345
|
+
if (rule) this.rules.set(key, rule); else this.rules.delete(key);
|
|
346
|
+
if (!this.ready) this.ready = this.start().catch(async error => { await this.dispose(); throw error; });
|
|
347
|
+
await this.ready;
|
|
348
|
+
await this.link.reconfigure();
|
|
349
|
+
}
|
|
350
|
+
/** Re-arm a faulted guard; resolves true once the context is protected again. One
|
|
351
|
+
* attempt at a time, in order with rule updates, and none during the backoff that
|
|
352
|
+
* follows a failed one. */
|
|
353
|
+
rearm() {
|
|
354
|
+
if (this.disposed || !this.link) return Promise.resolve(false);
|
|
355
|
+
if (!this.fault) return Promise.resolve(true);
|
|
356
|
+
if (this.rearming) return this.rearming;
|
|
357
|
+
if (Date.now() < this.rearmAt) return Promise.resolve(false);
|
|
358
|
+
const attempt = this.queue.then(() => this.replaceLink());
|
|
359
|
+
this.queue = attempt.catch(() => {});
|
|
360
|
+
this.rearming = attempt.catch(() => false).finally(() => { this.rearming = null; });
|
|
361
|
+
return this.rearming;
|
|
362
|
+
}
|
|
363
|
+
async replaceLink() {
|
|
364
|
+
if (this.disposed) return false;
|
|
365
|
+
if (!this.fault) return true;
|
|
366
|
+
// The faulted link stays attached (failing its own paused requests closed) until
|
|
367
|
+
// the fresh one has every current target protected, so no target is ever left
|
|
368
|
+
// without an attachment holding its rules.
|
|
369
|
+
const fresh = this.pendingLink = new GuardLink(this);
|
|
370
|
+
try {
|
|
371
|
+
await fresh.open();
|
|
372
|
+
} catch (error) {
|
|
373
|
+
await fresh.close();
|
|
374
|
+
const delays = this.timing.rearmBackoffMs;
|
|
375
|
+
this.rearmAt = Date.now() + delays[Math.min(this.rearmFailures++, delays.length - 1)];
|
|
376
|
+
console.error('[browser-network-guard] re-arm failed; actions stay refused:', error.message);
|
|
377
|
+
return false;
|
|
378
|
+
} finally { this.pendingLink = null; }
|
|
379
|
+
if (this.disposed) { await fresh.close(); return false; }
|
|
380
|
+
const old = this.link;
|
|
381
|
+
this.link = fresh;
|
|
382
|
+
this.rearmFailures = 0;
|
|
383
|
+
this.rearmAt = 0;
|
|
384
|
+
this._fault = null;
|
|
385
|
+
delete this.context.__browserNetworkGuardError;
|
|
386
|
+
this.context.emit?.(NETWORK_GUARD_RECOVERED_EVENT);
|
|
387
|
+
console.warn('[browser-network-guard] re-armed with a fresh protected attachment');
|
|
388
|
+
await old.close();
|
|
389
|
+
return true;
|
|
390
|
+
}
|
|
391
|
+
dispose() {
|
|
392
|
+
if (this.disposal) return this.disposal;
|
|
393
|
+
this.disposed = true;
|
|
394
|
+
if (this.onContextClose) this.context.removeListener('close', this.onContextClose);
|
|
395
|
+
if (this.onBrowserDisconnect) this.context.browser().removeListener('disconnected', this.onBrowserDisconnect);
|
|
396
|
+
this.disposal = (async () => {
|
|
397
|
+
await Promise.all([this.link?.close(), this.pendingLink?.close()]);
|
|
398
|
+
if (guards.get(this.context) === this) guards.delete(this.context);
|
|
399
|
+
})();
|
|
400
|
+
return this.disposal;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
/** Re-arm a faulted native guard: a fresh protected attachment replaces the broken one,
|
|
405
|
+
* so the context needs no server restart. Resolves true when the context is protected
|
|
406
|
+
* (again), false while its actions stay refused. Never rejects. */
|
|
407
|
+
export async function recoverBrowserNetworkGuard(context, { timeoutMs } = {}) {
|
|
408
|
+
const guard = guards.get(context);
|
|
409
|
+
if (!guard) return !context?.__browserNetworkGuardError;
|
|
410
|
+
let timer;
|
|
411
|
+
try {
|
|
412
|
+
return await Promise.race([
|
|
413
|
+
guard.rearm(),
|
|
414
|
+
new Promise(resolve => { timer = setTimeout(() => resolve(false), timeoutMs ?? guard.timing.recoverTimeoutMs); timer.unref?.(); }),
|
|
415
|
+
]);
|
|
416
|
+
} catch { return false; }
|
|
417
|
+
finally { clearTimeout(timer); }
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
/** Explicitly release only this context's safety transport, including failed setup. */
|
|
421
|
+
export async function disposeBrowserNetworkGuard(context) {
|
|
422
|
+
await guards.get(context)?.dispose();
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
/** Add/remove a named rule. Decisions compose: an abort always wins over headers. */
|
|
426
|
+
export function setBrowserNetworkRule(context, key, rule) {
|
|
427
|
+
if (!context) return Promise.reject(new Error('Network guard needs a browser context'));
|
|
428
|
+
if (rule && (!rule.patterns?.length || rule.patterns.some(pattern => pattern === '*' || pattern === '*://*/*'))) {
|
|
429
|
+
return Promise.reject(new Error('Network guard requires selective URL patterns'));
|
|
430
|
+
}
|
|
431
|
+
// Managed browsers retain their established Playwright guards. MoreLogin is
|
|
432
|
+
// registered at attachment and MUST use the native transport; a failure there
|
|
433
|
+
// rejects setup rather than silently falling back to wildcard interception.
|
|
434
|
+
if (!endpoints.has(context)) return setManagedBrowserRule(context, key, rule);
|
|
435
|
+
let guard = guards.get(context);
|
|
436
|
+
if (!guard) { guard = new ContextGuard(context); guards.set(context, guard); }
|
|
437
|
+
const updated = guard.queue.then(() => guard.update(key, rule));
|
|
438
|
+
guard.queue = updated.catch(error => { guard.fault = error; });
|
|
439
|
+
return updated;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
async function setManagedBrowserRule(context, key, rule) {
|
|
443
|
+
let entries = legacyRules.get(context);
|
|
444
|
+
if (!entries) { entries = new Map(); legacyRules.set(context, entries); }
|
|
445
|
+
const old = entries.get(key);
|
|
446
|
+
if (old) { await context.unroute(old); entries.delete(key); }
|
|
447
|
+
if (!rule) return;
|
|
448
|
+
const matches = url => !!rule.decide({ url: url.href });
|
|
449
|
+
await context.route(matches, async route => {
|
|
450
|
+
const decision = rule.decide({ url: route.request().url() });
|
|
451
|
+
if (decision?.abort) return route.abort('blockedbyclient');
|
|
452
|
+
if (decision?.headers) return route.fallback({ headers: { ...await route.request().allHeaders(), ...decision.headers } });
|
|
453
|
+
return route.fallback();
|
|
454
|
+
});
|
|
455
|
+
entries.set(key, matches);
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
// A serve may start at any time. Inspect explicit ports only, then decide using
|
|
459
|
+
// the CURRENT live-port set. Default-port public HTTPS never enters Fetch.
|
|
460
|
+
export const SERVE_PORT_PATTERNS = ['*://*:*/*'];
|
|
461
|
+
// Include authority spellings (trailing dot / explicit port) the exact existing
|
|
462
|
+
// regex already matches. The decide predicate still determines every abort.
|
|
463
|
+
export const MONEY_PATTERNS = ['*://*.facebook.com*/*', '*://facebook.com*/*'];
|
|
464
|
+
|
|
465
|
+
/** Native URL patterns covering isLocalMarkerHost, with the exact check in decide. */
|
|
466
|
+
export function localMarkerPatterns(hostNames = []) {
|
|
467
|
+
const hosts = ['localhost*', '*.localhost*', '127.*', '10.*', '0.*', '192.168.*', '169.254.*', '[*]'];
|
|
468
|
+
for (let n = 16; n <= 31; n++) hosts.push(`172.${n}.*`);
|
|
469
|
+
for (let n = 64; n <= 127; n++) hosts.push(`100.${n}.*`);
|
|
470
|
+
for (const raw of hostNames) {
|
|
471
|
+
const name = String(raw).toLowerCase().replace(/\.+$/, '').replace(/\.local$/, '');
|
|
472
|
+
// DNS names only; never turn an untrusted machine name into a wildcard.
|
|
473
|
+
if (/^[a-z0-9_-]+(?:\.[a-z0-9_-]+)*$/.test(name)) hosts.push(`${name}*`, `${name}.local*`);
|
|
474
|
+
}
|
|
475
|
+
return [...new Set(hosts)].flatMap(host => [`*://${host}/*`, `*://${host}:*/*`]);
|
|
476
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// ═══════════════════════════════════════════
|
|
2
|
+
// SynaBun — Browser policy: the projects where automated tests may run
|
|
3
|
+
// ═══════════════════════════════════════════
|
|
4
|
+
//
|
|
5
|
+
// The browser policy (lib/browser-tool-policy.js) lets a test runner (npm
|
|
6
|
+
// test, node --test, vitest, jest, npx playwright test) run browser tests from
|
|
7
|
+
// inside the session's own project, and from inside the `roots` its caller
|
|
8
|
+
// passes: the registered SynaBun projects (DATA_HOME/data/claude-code-projects.json,
|
|
9
|
+
// the "Registered projects" of the Assistant's routing sheet) that are code
|
|
10
|
+
// projects. A registered project is a code project when its folder
|
|
11
|
+
// - is an absolute path,
|
|
12
|
+
// - holds `.git` (a git work tree's root; a worktree's or a submodule's `.git`
|
|
13
|
+
// file counts), `package.json`, `deno.json` or `deno.jsonc` at its top,
|
|
14
|
+
// - is not the home folder or a folder above it, and
|
|
15
|
+
// - is not the Downloads folder or anything inside it (downloaded files are
|
|
16
|
+
// untrusted, whatever they hold).
|
|
17
|
+
// Read where a run starts (server.js for workers, assistant-runtime.js for the
|
|
18
|
+
// brain); the policy module itself reads nothing and gets the list.
|
|
19
|
+
|
|
20
|
+
import { statSync } from 'node:fs';
|
|
21
|
+
import { homedir } from 'node:os';
|
|
22
|
+
import { isAbsolute, relative, resolve } from 'node:path';
|
|
23
|
+
|
|
24
|
+
/** What at a folder's top makes it a code project. */
|
|
25
|
+
export const CODE_PROJECT_MARKERS = Object.freeze(['.git', 'package.json', 'deno.json', 'deno.jsonc']);
|
|
26
|
+
|
|
27
|
+
// macOS and Windows name a folder in any letter case: the exclusions compare that way.
|
|
28
|
+
const caseless = (path) => (process.platform === 'darwin' || process.platform === 'win32' ? path.toLowerCase() : path);
|
|
29
|
+
function inside(child, parent) {
|
|
30
|
+
const rel = relative(caseless(resolve(parent)), caseless(resolve(child)));
|
|
31
|
+
return rel === '' || (!rel.startsWith('..') && !isAbsolute(rel));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** Why `path` is not a code project the browser policy lets tests run in, else null. `stat`: tests. */
|
|
35
|
+
export function codeProjectRefusal(path, { home = homedir(), stat = statSync } = {}) {
|
|
36
|
+
const text = typeof path === 'string' ? path.trim() : '';
|
|
37
|
+
if (!text || !isAbsolute(text)) return 'not an absolute path';
|
|
38
|
+
const root = resolve(text);
|
|
39
|
+
if (inside(home, root)) return 'the home folder or a folder above it';
|
|
40
|
+
if (inside(root, resolve(home, 'Downloads'))) return 'the Downloads folder (downloaded files)';
|
|
41
|
+
const marked = CODE_PROJECT_MARKERS.some((name) => {
|
|
42
|
+
try {
|
|
43
|
+
const entry = stat(resolve(root, name));
|
|
44
|
+
return name === '.git' ? entry.isDirectory() || entry.isFile() : entry.isFile();
|
|
45
|
+
} catch { return false; }
|
|
46
|
+
});
|
|
47
|
+
return marked ? null : 'no .git, package.json, deno.json or deno.jsonc at its top';
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* The registered projects (claude-code-projects.json rows `{ path }` or plain
|
|
52
|
+
* paths) that are code projects, resolved, each once: the browser policy's
|
|
53
|
+
* `roots`.
|
|
54
|
+
*/
|
|
55
|
+
export function browserPolicyRoots(projects, options = {}) {
|
|
56
|
+
const out = [];
|
|
57
|
+
for (const row of Array.isArray(projects) ? projects : []) {
|
|
58
|
+
const path = typeof row === 'string' ? row : row?.path;
|
|
59
|
+
if (typeof path !== 'string' || codeProjectRefusal(path, options) !== null) continue;
|
|
60
|
+
const root = resolve(path.trim());
|
|
61
|
+
if (!out.includes(root)) out.push(root);
|
|
62
|
+
}
|
|
63
|
+
return out;
|
|
64
|
+
}
|