synabun 2.0.10 → 2.1.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 +86 -0
- package/README.md +25 -2
- package/THIRD-PARTY-LICENSES.md +22 -0
- package/bin/synabun.js +71 -24
- package/docs/whatsapp.md +2 -2
- 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 +17 -8
- package/lib/desktop-app.js +7 -1
- package/lib/external-tools.js +1 -1
- 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 +228 -0
- package/lib/virustotal.mjs +192 -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/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/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/neural-interface.d.ts +16 -10
- 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 +20 -62
- 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/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 +10 -10
- package/mcp-server/dist/tools/agents.d.ts.map +1 -1
- package/mcp-server/dist/tools/agents.js +22 -13
- 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/image-tools.d.ts +1 -1
- package/mcp-server/dist/tools/image-tools.js +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 +639 -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/codex-config-heal.ts +80 -29
- package/mcp-server/src/services/memory-judge-backfill.ts +7 -1
- package/mcp-server/src/services/neural-interface.ts +79 -20
- package/mcp-server/src/services/server-instructions.ts +27 -63
- 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/whiteboard-geometry.ts +94 -9
- package/mcp-server/src/tools/agents.ts +22 -14
- package/mcp-server/src/tools/image-tools.ts +1 -1
- package/mcp-server/src/tools/skill-tools.ts +589 -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 +3463 -200
- package/neural-interface/i18n/pt-BR.json +3411 -151
- package/neural-interface/lib/assistant-api.js +127 -28
- 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-catalog.js +6 -7
- package/neural-interface/lib/assistant-dispatch.js +871 -156
- package/neural-interface/lib/assistant-envelope.js +3 -1
- package/neural-interface/lib/assistant-persona.js +80 -11
- package/neural-interface/lib/assistant-plan-permissions.js +10 -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 +13 -8
- package/neural-interface/lib/assistant-runtime.js +56 -18
- package/neural-interface/lib/assistant-task-prompt.js +78 -14
- package/neural-interface/lib/assistant-tools.js +51 -0
- package/neural-interface/lib/backup-service.js +620 -3
- 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 +83 -0
- package/neural-interface/lib/browser-network-guard.js +284 -0
- package/neural-interface/lib/browser-policy-roots.js +64 -0
- package/neural-interface/lib/browser-tool-policy.js +186 -31
- package/neural-interface/lib/claude-agent-bridge.js +4 -2
- package/neural-interface/lib/claude-hooks-status.js +103 -0
- package/neural-interface/lib/claude-temporary.js +5 -11
- package/neural-interface/lib/cli-install.js +18 -138
- package/neural-interface/lib/cli-resolver.js +4 -1
- package/neural-interface/lib/cli-update-planner.js +32 -31
- package/neural-interface/lib/cloudflared/tunnel.js +42 -2
- package/neural-interface/lib/codex-mcp-approvals.js +11 -0
- package/neural-interface/lib/codex-worker-app-server.js +172 -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/exec-loop-command.js +4 -8
- 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 +0 -29
- package/neural-interface/lib/mcp-external-servers.js +323 -0
- package/neural-interface/lib/{mcp-profile-refresh-coordinator.js → mcp-tools-refresh-coordinator.js} +4 -4
- package/neural-interface/lib/morelogin.js +30 -0
- package/neural-interface/lib/native-loop-providers.js +547 -47
- package/neural-interface/lib/native-loop-runtime.js +268 -41
- 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 +44 -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/peer-identity.js +763 -0
- package/neural-interface/lib/request-gate.js +17 -2
- package/neural-interface/lib/rulesets/api.js +1 -1
- package/neural-interface/lib/rulesets/fs-safe.js +1 -1
- package/neural-interface/lib/rulesets/installer.js +92 -27
- package/neural-interface/lib/rulesets/json-edit.js +1 -1
- package/neural-interface/lib/session-cache-builder.js +17 -30
- 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 +294 -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 +267 -0
- package/neural-interface/lib/skills/creation.js +843 -0
- package/neural-interface/lib/skills/deploy.js +564 -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 +214 -0
- package/neural-interface/lib/skills/eval-confinement.js +397 -0
- package/neural-interface/lib/skills/eval-sandbox.js +280 -0
- package/neural-interface/lib/skills/eval-trace.js +119 -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 +200 -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 +387 -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 +262 -0
- package/neural-interface/lib/skills/runtime-checks.js +355 -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 +522 -0
- package/neural-interface/lib/skills/telemetry.js +113 -0
- package/neural-interface/lib/sqlite-integrity-worker.js +22 -0
- package/neural-interface/lib/tool-lists.js +124 -0
- package/neural-interface/lib/whatsapp/bridge.js +6 -3
- package/neural-interface/lib/worker-confinement.js +1192 -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-relay-ports.js +227 -0
- package/neural-interface/lib/worker-resume.js +229 -0
- package/neural-interface/lib/worker-sandbox.js +299 -0
- package/neural-interface/package-lock.json +18 -12
- package/neural-interface/package.json +2 -2
- package/neural-interface/public/index.html +3 -1
- package/neural-interface/public/index2d.html +19 -11
- package/neural-interface/public/onboarding.html +2 -2
- package/neural-interface/public/shared/account-menu.js +8 -5
- package/neural-interface/public/shared/agent-runtime-options.js +35 -19
- 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 +33 -2
- 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 +49 -35
- package/neural-interface/public/shared/assistant/asst-control.js +157 -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-limit-dock.js +40 -0
- package/neural-interface/public/shared/assistant/asst-limit-wait.js +294 -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 +106 -11
- package/neural-interface/public/shared/assistant/asst-rack-styles.js +66 -49
- package/neural-interface/public/shared/assistant/asst-render.js +401 -77
- package/neural-interface/public/shared/assistant/asst-route.js +83 -12
- package/neural-interface/public/shared/assistant/asst-scenes.js +2 -0
- package/neural-interface/public/shared/assistant/asst-sidepanel.js +67 -4
- package/neural-interface/public/shared/assistant/asst-slash.js +9 -7
- package/neural-interface/public/shared/assistant/asst-state.js +11 -15
- package/neural-interface/public/shared/assistant/asst-stop.js +127 -0
- package/neural-interface/public/shared/assistant/asst-styles.js +59 -21
- package/neural-interface/public/shared/assistant/asst-tool-kinds.js +156 -16
- 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 +8 -7
- package/neural-interface/public/shared/cdx/cdx-panel.js +45 -149
- package/neural-interface/public/shared/cdx/cdx-protocol.js +28 -1
- package/neural-interface/public/shared/cdx/cdx-render.js +47 -29
- package/neural-interface/public/shared/cdx/cdx-requests.js +3 -3
- package/neural-interface/public/shared/cdx/cdx-skill-hints.js +54 -0
- package/neural-interface/public/shared/cdx/cdx-styles.js +11 -3
- package/neural-interface/public/shared/cdx/cdx-tabs.js +52 -39
- package/neural-interface/public/shared/cdx/cdx-ws.js +0 -1
- package/neural-interface/public/shared/cli-install-view.js +4 -8
- package/neural-interface/public/shared/cli-status.js +2 -2
- package/neural-interface/public/shared/constants.js +2 -2
- 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 +366 -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/crash-notice-view.js +168 -0
- package/neural-interface/public/shared/desktop-update-view.js +20 -0
- package/neural-interface/public/shared/editor/editor-panel-logic.js +2 -2
- package/neural-interface/public/shared/html-shell.js +9 -11
- 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 +47 -252
- 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-render.js +6 -21
- 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 +0 -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 +14 -47
- package/neural-interface/public/shared/page-session.js +96 -0
- 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-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/skills/ss-args.js +96 -0
- package/neural-interface/public/shared/skills/ss-creation.js +219 -0
- package/neural-interface/public/shared/skills/ss-dialog.js +130 -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 +141 -0
- package/neural-interface/public/shared/skills/ss-presets.js +117 -0
- package/neural-interface/public/shared/skills/ss-profiles.js +475 -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 +236 -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 +229 -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-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 +279 -0
- package/neural-interface/public/shared/skills/studio/sx-install.js +296 -0
- package/neural-interface/public/shared/skills/studio/sx-library-view.js +639 -0
- package/neural-interface/public/shared/skills/studio/sx-library.js +475 -0
- package/neural-interface/public/shared/skills/studio/sx-main.js +681 -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 +248 -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 +425 -0
- package/neural-interface/public/shared/styleguide/sg-panel.js +4 -2
- package/neural-interface/public/shared/styles.css +1525 -1779
- package/neural-interface/public/shared/synabun-mascot.js +1115 -9
- 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/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-automation-studio.js +91 -128
- package/neural-interface/public/shared/ui-claude-panel.js +77 -5
- 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-image-gallery.js +50 -47
- package/neural-interface/public/shared/ui-keybinds.js +26 -1
- package/neural-interface/public/shared/ui-menubar.js +8 -18
- package/neural-interface/public/shared/ui-native-loop-router-state.js +5 -0
- package/neural-interface/public/shared/ui-native-loop-router.js +7 -1
- package/neural-interface/public/shared/ui-navbar.js +4 -24
- package/neural-interface/public/shared/ui-panels.js +96 -65
- package/neural-interface/public/shared/ui-schedules-studio.js +507 -423
- package/neural-interface/public/shared/ui-sessions.js +5 -3
- package/neural-interface/public/shared/ui-settings.js +594 -462
- package/neural-interface/public/shared/ui-sidepanel-sessions.js +1 -1
- package/neural-interface/public/shared/ui-sidepanel-state.js +23 -12
- package/neural-interface/public/shared/ui-sidepanel-windows.js +16 -11
- 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 +124 -180
- package/neural-interface/public/shared/ui-tool-updates.js +3 -1
- package/neural-interface/public/shared/ui-tooltip.js +10 -5
- 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 +311 -58
- package/neural-interface/public/shared/ui-worker-end.js +4 -0
- 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 +1 -1
- 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-restart.js +12 -0
- package/neural-interface/public/sidepanel-session.html +1 -1
- 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 +3934 -2454
- package/neural-interface/templates/rulesets/core.md +1 -1
- package/neural-interface/templates/rulesets/legacy-hashes.json +18 -0
- package/neural-interface/templates/rulesets/manifest.json +8 -8
- package/npm-shrinkwrap.json +18 -12
- package/package.json +16 -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 +4 -4
- 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
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
// ═══════════════════════════════════════════
|
|
2
|
+
// SynaBun — The page secret: what tells the owner's own page from a local process
|
|
3
|
+
// ═══════════════════════════════════════════
|
|
4
|
+
//
|
|
5
|
+
// The owner's writes to Skills Studio (a skill creation, an install, a review decision) used to be told apart from
|
|
6
|
+
// an agent's by headers alone: an agent sends X-Synabun-Terminal / -Role, the page sends X-SynaBun-UI. Both are
|
|
7
|
+
// plain headers any local process can send or leave out, so a shell-capable worker could omit the agent headers
|
|
8
|
+
// and start a creation "as the owner" (the P3 review, ea44bd5f).
|
|
9
|
+
//
|
|
10
|
+
// Now the server mints one random secret per boot and hands it to the page as an HttpOnly, SameSite=Strict cookie
|
|
11
|
+
// on the app's own pages (and on the Studio's first read, so a page the service worker served still gets it). The
|
|
12
|
+
// browser sends it back by itself with every same-origin request; the page's code never sees it (HttpOnly) and
|
|
13
|
+
// never has to send it. An owner write without it is refused (403 PAGE_SECRET_REQUIRED / UI_ONLY). A worker never
|
|
14
|
+
// gets it: nothing SynaBun starts is given the cookie, it is in no environment, no file and no API answer a worker
|
|
15
|
+
// reads.
|
|
16
|
+
//
|
|
17
|
+
// Per boot, not per install: the secret lives in this process only (no file in the data home, so nothing a worker
|
|
18
|
+
// can read outside the server hands it out), and a restart makes a new one. The owner's open tab keeps the old
|
|
19
|
+
// cookie, so its first write after a restart is refused; the page recovers by itself (public/shared/page-session.js
|
|
20
|
+
// wraps the page's fetch: a 403 UI_ONLY / PAGE_SECRET_REQUIRED on a same-origin write asks GET /api/page-session,
|
|
21
|
+
// which sets this boot's cookie, and sends the write once more; no reload, no toast, nothing lost).
|
|
22
|
+
//
|
|
23
|
+
// Per port: the browser's cookie jar ignores ports, so every server on localhost sees every localhost cookie. The
|
|
24
|
+
// cookie's name carries the port (synabun_page_<port>): two SynaBun servers side by side (the app and a test
|
|
25
|
+
// instance, or a second checkout) each read their own and neither overwrites the other's. Other servers on
|
|
26
|
+
// localhost still receive it with every request a page of theirs makes, as they receive any localhost cookie: a
|
|
27
|
+
// local process that fetches one of the pages itself reads the Set-Cookie header the same way the browser does.
|
|
28
|
+
// Both are the same class of limit, stated plainly: the secret raises the bar from "leave the headers out" to
|
|
29
|
+
// "know this and fetch a page first"; the worker confinement (lib/worker-confinement.js) is what keeps a
|
|
30
|
+
// prompt-injected worker from doing that with its shell (a guarded run's shell may not call SynaBun's own port),
|
|
31
|
+
// and the two are meant to be used together. A browser worker that opens SynaBun's pages in the automation browser
|
|
32
|
+
// is told apart by the marker cookie (WORKER_BROWSER_COOKIE, set on that browser's context by server.js): its
|
|
33
|
+
// owner writes are refused. The marker's name carries no port on purpose: it only ever refuses, so a marker from
|
|
34
|
+
// one SynaBun instance refusing an owner write at another is the safe direction, and each automation browser is a
|
|
35
|
+
// Playwright context of its own, so no instance's marker is overwritten by another's.
|
|
36
|
+
|
|
37
|
+
//
|
|
38
|
+
// Owner authority by peer identity (lib/peer-identity.js): markers are told by the browser, the TCP table cannot be
|
|
39
|
+
// talked into anything. When the server wires a peer lookup in (`peer`), every way the secret is handed out or
|
|
40
|
+
// used asks it too: a request from SynaBun's automation browser, a browser started for automation, an agent's
|
|
41
|
+
// process tree or a relay is never handed the secret (the pages, GET /api/page-session, a Studio read's attach) and
|
|
42
|
+
// never counts as the owner (verify), whatever host, port, cookie or marker it carries, and a service worker there
|
|
43
|
+
// gets a worker that takes itself away (serviceWorker). A lookup that could not run leaves the rules above.
|
|
44
|
+
|
|
45
|
+
import { randomBytes, timingSafeEqual } from 'node:crypto';
|
|
46
|
+
import { isIP } from 'node:net';
|
|
47
|
+
import { parseCookies } from './http-guards.js';
|
|
48
|
+
import { ipv6Groups, mappedIPv4 } from './peer-identity.js';
|
|
49
|
+
import { setBrowserNetworkRule, localMarkerPatterns } from './browser-network-guard.js';
|
|
50
|
+
|
|
51
|
+
/** The cookie's name without a port (tests, hosts that pass none); with one it is pageSecretCookieName(port). */
|
|
52
|
+
export const PAGE_SECRET_COOKIE = 'synabun_page';
|
|
53
|
+
/** The page secret cookie's name for a server at `port`: synabun_page_<port>, or synabun_page without a port. */
|
|
54
|
+
export function pageSecretCookieName(port) {
|
|
55
|
+
const n = Number(port);
|
|
56
|
+
return Number.isInteger(n) && n > 0 ? `${PAGE_SECRET_COOKIE}_${n}` : PAGE_SECRET_COOKIE;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* The marker SynaBun's automation browser carries for SynaBun's own origin: a worker that opens SynaBun's pages in
|
|
60
|
+
* that browser (visual QA of the Studio) gets the page secret cookie like any page, so its writes would pass; this
|
|
61
|
+
* cookie, set on the browser context itself (HttpOnly, by SynaBun, never by a page), tells those tabs apart and an
|
|
62
|
+
* owner write that carries it is refused. Reads, screenshots and clicks still work there.
|
|
63
|
+
*/
|
|
64
|
+
export const WORKER_BROWSER_COOKIE = 'synabun_worker';
|
|
65
|
+
/**
|
|
66
|
+
* The host-proof twin of the marker cookie: a request HEADER SynaBun's browser layer adds to every request its
|
|
67
|
+
* automation browser makes to any local destination (markWorkerBrowserContext, via CDP request interception). The
|
|
68
|
+
* cookie jar is per host, so a worker that drives the automation browser to the LAN IP, the hostname or [::1]
|
|
69
|
+
* instead of localhost gets a fresh page-secret cookie for that host and no marker cookie — it would pass as the
|
|
70
|
+
* owner. The header travels with EVERY request whatever the host or port, and page JS cannot see or remove a
|
|
71
|
+
* header the browser adds at the network layer (and item 1 keeps raw CDP away from a guarded worker, so it cannot
|
|
72
|
+
* strip it there either). The server refuses the page secret and owner authority to any request carrying it.
|
|
73
|
+
*/
|
|
74
|
+
export const WORKER_BROWSER_HEADER = 'x-synabun-worker';
|
|
75
|
+
/** Does a request carry the automation-browser marker (cookie or the host-proof header)? */
|
|
76
|
+
function hasWorkerMarker(req) {
|
|
77
|
+
if (req?.headers?.[WORKER_BROWSER_HEADER] !== undefined) return true;
|
|
78
|
+
const jar = parseCookies(req?.headers?.cookie);
|
|
79
|
+
return !!jar && jar[WORKER_BROWSER_COOKIE] !== undefined;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* A host as one spelling: lowercase, no brackets, no trailing dot ("localhost.", "Mac."), an IPv4 address in any of
|
|
83
|
+
* the forms the URL parser takes (127.1, 2130706433, 0x7f.1) as its dotted quad, an IPv4-mapped IPv6 literal
|
|
84
|
+
* ([::ffff:127.0.0.1], [::ffff:7f00:1]) as the IPv4 address it stands for, any other IPv6 literal as its eight groups.
|
|
85
|
+
*/
|
|
86
|
+
export function canonicalMarkerHost(hostname) {
|
|
87
|
+
let h = String(hostname ?? '').trim().toLowerCase().replace(/^\[|\]$/g, '');
|
|
88
|
+
while (h.endsWith('.')) h = h.slice(0, -1);
|
|
89
|
+
if (!h) return '';
|
|
90
|
+
if (h.includes(':')) {
|
|
91
|
+
const v4 = mappedIPv4(h);
|
|
92
|
+
if (v4) return v4;
|
|
93
|
+
const groups = ipv6Groups(h);
|
|
94
|
+
return groups ? groups.map((g) => g.toString(16)).join(':') : h;
|
|
95
|
+
}
|
|
96
|
+
if (/^[0-9a-fx.]+$/.test(h)) {
|
|
97
|
+
// A name made of digits, dots and hex: what the browser would connect to (WHATWG IPv4 parsing), if it is an address.
|
|
98
|
+
try { const parsed = new URL(`http://${h}/`).hostname; if (isIP(parsed) === 4) return parsed; } catch { /* not an address */ }
|
|
99
|
+
}
|
|
100
|
+
return h;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function isLocalIPv4(dotted) {
|
|
104
|
+
const [a, b] = dotted.split('.').map(Number);
|
|
105
|
+
return a === 127 || a === 10 || a === 0 // loopback, private, "this network"
|
|
106
|
+
|| (a === 172 && b >= 16 && b <= 31) || (a === 192 && b === 168) // private
|
|
107
|
+
|| (a === 169 && b === 254) // link-local
|
|
108
|
+
|| (a === 100 && b >= 64 && b <= 127); // shared address space (CGNAT, a tailnet's addresses)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/** Loopback / private-network / link-local host — a local destination the marker header is safe to add to (never a
|
|
112
|
+
* public site, so the automation browser's fingerprint on real sites is unchanged). Address ranges are matched on
|
|
113
|
+
* address literals only (127.example.com is a name, and a public one); names match "localhost", *.localhost and this
|
|
114
|
+
* computer's own names (also as <name>.local), whatever their spelling. */
|
|
115
|
+
export function isLocalMarkerHost(hostname, extraNames = []) {
|
|
116
|
+
const h = canonicalMarkerHost(hostname);
|
|
117
|
+
if (!h) return false;
|
|
118
|
+
if (h === 'localhost' || h.endsWith('.localhost')) return true;
|
|
119
|
+
if (isIP(h) === 4) return isLocalIPv4(h);
|
|
120
|
+
const groups = h.includes(':') ? ipv6Groups(h) : null;
|
|
121
|
+
if (groups) {
|
|
122
|
+
if (groups.slice(0, 7).every((g) => g === 0) && groups[7] <= 1) return true; // :: and ::1
|
|
123
|
+
if ((groups[0] & 0xffc0) === 0xfe80 || (groups[0] & 0xfe00) === 0xfc00) return true; // link-local, unique-local
|
|
124
|
+
if (groups.slice(0, 6).every((g) => g === 0)) return isLocalIPv4(`${groups[6] >> 8}.${groups[6] & 255}.${groups[7] >> 8}.${groups[7] & 255}`); // ::a.b.c.d
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
return (Array.isArray(extraNames) ? extraNames : []).some((name) => {
|
|
128
|
+
const n = canonicalMarkerHost(name);
|
|
129
|
+
if (!n) return false;
|
|
130
|
+
const bare = n.endsWith('.local') ? n.slice(0, -'.local'.length) : n;
|
|
131
|
+
return h === n || h === bare || h === `${bare}.local`;
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* The pages the cookie is set on: the app's shells and the detached side panel's window, each the first page a
|
|
136
|
+
* browser window loads. The Studio's library read sets it too (server.js), as does GET /api/page-session.
|
|
137
|
+
*/
|
|
138
|
+
export const PAGE_SECRET_PATHS = Object.freeze(['/', '/index.html', '/index2d.html', '/onboarding.html', '/sidepanel-session.html']);
|
|
139
|
+
/** The route an open tab asks for this boot's cookie after a restart (public/shared/page-session.js). */
|
|
140
|
+
export const PAGE_SECRET_REFRESH_PATH = '/api/page-session';
|
|
141
|
+
/** The app's service worker (public/sw.js): a browser that may not hold the secret gets SERVICE_WORKER_NOOP instead. */
|
|
142
|
+
export const SERVICE_WORKER_PATH = '/sw.js';
|
|
143
|
+
/**
|
|
144
|
+
* The service worker SynaBun's automation browser (and anything else refused the page secret) is given in place of
|
|
145
|
+
* public/sw.js: no fetch handler, so none of that browser's requests is answered by a worker, and it unregisters
|
|
146
|
+
* itself once active (an older worker it replaces goes with it).
|
|
147
|
+
*/
|
|
148
|
+
export const SERVICE_WORKER_NOOP = `// SynaBun: this browser gets no service worker (it is not the owner's own browser), so every request it makes
|
|
149
|
+
// reaches the server as itself. This worker takes itself away.
|
|
150
|
+
self.addEventListener('install', () => self.skipWaiting());
|
|
151
|
+
self.addEventListener('activate', (event) => { event.waitUntil(self.registration.unregister().catch(() => {})); });
|
|
152
|
+
`;
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* @param {object} [o]
|
|
156
|
+
* @param {{ refusal(req): string|null }} [o.peer] lib/peer-identity.js: why a request's peer process may not hold or
|
|
157
|
+
* use the secret (null when it may, or when it could not be told)
|
|
158
|
+
*/
|
|
159
|
+
export function createPageSession({ secret = null, cookieName = null, port = null, secure = false, isGuest = null, peer = null, networkRule = setBrowserNetworkRule } = {}) {
|
|
160
|
+
const value = typeof secret === 'string' && secret.length >= 32 ? secret : randomBytes(32).toString('hex');
|
|
161
|
+
const expected = Buffer.from(value);
|
|
162
|
+
const name = typeof cookieName === 'string' && cookieName ? cookieName : pageSecretCookieName(port);
|
|
163
|
+
const guest = (req) => { try { return typeof isGuest === 'function' && isGuest(req) === true; } catch { return true; } };
|
|
164
|
+
/** Why the peer lookup refuses this request the secret, or null (never asked, could not tell, or allowed). */
|
|
165
|
+
const peerRefusal = (req) => { try { return typeof peer?.refusal === 'function' ? (peer.refusal(req) || null) : null; } catch { return null; } };
|
|
166
|
+
/** A request that may neither be handed the secret nor use it: a marker of the automation browser, or its peer. */
|
|
167
|
+
const heldBack = (req) => hasWorkerMarker(req) || !!peerRefusal(req);
|
|
168
|
+
|
|
169
|
+
/** The Set-Cookie header value (HttpOnly, SameSite=Strict, the whole site). */
|
|
170
|
+
function cookie() {
|
|
171
|
+
return `${name}=${value}; Path=/; HttpOnly; SameSite=Strict${secure ? '; Secure' : ''}`;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Add the cookie to a response (once; a header already there is kept and this one appended). Never to a guest, a
|
|
175
|
+
* request with the automation browser's marker or one whose peer is refused: `req` is the response's own request
|
|
176
|
+
* (Express's res.req) unless given, so every caller that hands the page the secret asks the same questions.
|
|
177
|
+
*/
|
|
178
|
+
function attach(res, req = res?.req) {
|
|
179
|
+
if (!res || typeof res.getHeader !== 'function' || typeof res.setHeader !== 'function') return;
|
|
180
|
+
if (req && (heldBack(req) || guest(req))) return;
|
|
181
|
+
const current = res.getHeader('Set-Cookie');
|
|
182
|
+
const list = current === undefined ? [] : Array.isArray(current) ? [...current] : [String(current)];
|
|
183
|
+
if (list.some((line) => String(line).startsWith(`${name}=`))) return;
|
|
184
|
+
list.push(cookie());
|
|
185
|
+
res.setHeader('Set-Cookie', list);
|
|
186
|
+
}
|
|
187
|
+
/** Whether a request carries this boot's secret cookie (nothing else asked: the cheap test for "look the peer up"). */
|
|
188
|
+
function carriesSecret(req) {
|
|
189
|
+
const jar = parseCookies(req?.headers?.cookie);
|
|
190
|
+
const got = jar && typeof jar[name] === 'string' ? Buffer.from(jar[name]) : null;
|
|
191
|
+
return !!got && got.length === expected.length && timingSafeEqual(got, expected);
|
|
192
|
+
}
|
|
193
|
+
/** Whether a request carries this boot's secret, and neither the automation browser's marker (cookie or header)
|
|
194
|
+
* nor a peer the lookup refuses. */
|
|
195
|
+
function verify(req) {
|
|
196
|
+
if (heldBack(req)) return false;
|
|
197
|
+
return carriesSecret(req);
|
|
198
|
+
}
|
|
199
|
+
/** Whether a request comes from a tab of SynaBun's automation browser (the marker cookie or the host-proof header). */
|
|
200
|
+
function fromWorkerBrowser(req) {
|
|
201
|
+
return hasWorkerMarker(req);
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Mark a Playwright browser context as SynaBun's automation browser. Two markers, both HttpOnly / network-level so
|
|
205
|
+
* no page script reads or drops them, and never throws:
|
|
206
|
+
* • a cookie for localhost and 127.0.0.1 at the server's port (kept for compatibility and defence in depth);
|
|
207
|
+
* • a host-proof request header (WORKER_BROWSER_HEADER) added to every request the context makes to a LOCAL
|
|
208
|
+
* destination, whatever the host or port (so the LAN IP / hostname / [::1] forms are covered, which the
|
|
209
|
+
* per-host cookie is not). Public sites are left untouched, so the browser's fingerprint there is unchanged.
|
|
210
|
+
* @param {string[]} [hostNames] this machine's own names (os.hostname / scutil), for the header's local-host test.
|
|
211
|
+
*/
|
|
212
|
+
async function markWorkerBrowserContext(context, { port: atPort, hostNames = [] } = {}) {
|
|
213
|
+
if (!context || !(Number(atPort) > 0)) return false;
|
|
214
|
+
if (typeof context.addCookies === 'function') {
|
|
215
|
+
const cookies = ['localhost', '127.0.0.1'].map((host) => ({ name: WORKER_BROWSER_COOKIE, value: '1', url: `http://${host}:${Number(atPort)}/`, httpOnly: true, sameSite: 'Lax' }));
|
|
216
|
+
try { await context.addCookies(cookies); } catch { /* a CDP-attached context may refuse; the header still marks it */ }
|
|
217
|
+
}
|
|
218
|
+
try {
|
|
219
|
+
await networkRule(context, 'worker-marker', {
|
|
220
|
+
patterns: localMarkerPatterns(hostNames),
|
|
221
|
+
decide(request) {
|
|
222
|
+
return isLocalMarkerHost(new URL(request.url).hostname, hostNames) ? { headers: { [WORKER_BROWSER_HEADER]: '1' } } : null;
|
|
223
|
+
},
|
|
224
|
+
});
|
|
225
|
+
return true;
|
|
226
|
+
} catch (error) {
|
|
227
|
+
// Cookies alone miss LAN IPs/hostnames. The caller must not silently
|
|
228
|
+
// navigate an unmarked browser when the host-proof header failed.
|
|
229
|
+
console.warn('[worker-browser] network marker unavailable:', error.message);
|
|
230
|
+
return false;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
/** Express middleware for an owner write: 403 PAGE_SECRET_REQUIRED without the secret. */
|
|
234
|
+
function require(req, res, next) {
|
|
235
|
+
if (verify(req)) return next();
|
|
236
|
+
res.status(403).json({ ok: false, code: 'PAGE_SECRET_REQUIRED', error: 'This change is made from SynaBun\'s own page. Reload the page and try again.' });
|
|
237
|
+
}
|
|
238
|
+
/** Express middleware that sets the cookie on the pages it belongs to (GET only, the app's shells; never a guest's
|
|
239
|
+
* and never a request that carries the automation-browser marker or whose peer is refused — a marked tab, an
|
|
240
|
+
* automation browser, an agent or a relay must never be handed the secret). */
|
|
241
|
+
function pages(req, res, next) {
|
|
242
|
+
if ((req.method === 'GET' || req.method === 'HEAD') && PAGE_SECRET_PATHS.includes(req.path) && !guest(req) && !heldBack(req)) attach(res, req);
|
|
243
|
+
next();
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* GET /api/page-session: this boot's cookie for a page that is already open (its cookie is an earlier boot's
|
|
247
|
+
* after a restart). Answers { ok: true } with the cookie; a guest gets 403 and no cookie. A tab of SynaBun's
|
|
248
|
+
* automation browser (the marker cookie or the host-proof header) is refused the secret too (403 WORKER_BROWSER),
|
|
249
|
+
* as is a request whose peer process the lookup refuses (403 PEER_REFUSED: an automation browser, an agent's
|
|
250
|
+
* process tree, a relay). Never cached.
|
|
251
|
+
*/
|
|
252
|
+
function refresh(req, res) {
|
|
253
|
+
res.setHeader('Cache-Control', 'no-store');
|
|
254
|
+
if (guest(req)) return res.status(403).json({ ok: false, code: 'GUEST_FORBIDDEN', error: 'Available to the owner only.' });
|
|
255
|
+
if (hasWorkerMarker(req)) return res.status(403).json({ ok: false, code: 'WORKER_BROWSER', error: 'SynaBun\'s automation browser does not hold the owner\'s page secret.' });
|
|
256
|
+
const why = peerRefusal(req);
|
|
257
|
+
if (why) return res.status(403).json({ ok: false, code: 'PEER_REFUSED', error: `SynaBun hands its page secret to the owner's own browser only; this request comes from ${why}.` });
|
|
258
|
+
attach(res, req);
|
|
259
|
+
res.json({ ok: true });
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Express middleware for GET /sw.js: a browser that may not hold the secret (the automation browser's marker, or a
|
|
263
|
+
* refused peer) gets SERVICE_WORKER_NOOP, so no service worker answers its requests out of the server's sight;
|
|
264
|
+
* everyone else falls through to the real public/sw.js.
|
|
265
|
+
*/
|
|
266
|
+
function serviceWorker(req, res, next) {
|
|
267
|
+
if ((req.method === 'GET' || req.method === 'HEAD') && req.path === SERVICE_WORKER_PATH && heldBack(req)) {
|
|
268
|
+
res.setHeader('Cache-Control', 'no-store');
|
|
269
|
+
res.setHeader('Content-Type', 'text/javascript; charset=utf-8');
|
|
270
|
+
return res.end(req.method === 'HEAD' ? undefined : SERVICE_WORKER_NOOP);
|
|
271
|
+
}
|
|
272
|
+
next();
|
|
273
|
+
}
|
|
274
|
+
return { cookieName: name, cookie, attach, carriesSecret, verify, require, pages, refresh, serviceWorker, fromWorkerBrowser, peerRefusal, markWorkerBrowserContext };
|
|
275
|
+
}
|