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
|
@@ -1,37 +1,34 @@
|
|
|
1
1
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
2
|
-
//
|
|
2
|
+
// The raw requests SynaBun makes to a serve, answered through OpenCode 2's API.
|
|
3
3
|
//
|
|
4
|
-
// Besides the
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
// gets a clear 501 instead of a web page.
|
|
4
|
+
// Besides the client's methods, server.js and the panel's request module call
|
|
5
|
+
// a serve by path (`ocpProxy(method, path, body)`): the provider and agent
|
|
6
|
+
// lists, a session's deletion, the pending questions and a question's answer,
|
|
7
|
+
// the MCP resources, and OpenCode 2's own /api/* routes. Those paths are the
|
|
8
|
+
// ones SynaBun has always named (OpenCode 1's); every one of them would land
|
|
9
|
+
// on OpenCode 2's web app (an HTML page, status 200), so each is answered here
|
|
10
|
+
// through the OpenCode 2 client (lib/opencode2-client.js), in the shapes
|
|
11
|
+
// SynaBun reads, as `{ status, data }`. A path under /api/ goes through with
|
|
12
|
+
// the serve's password. Anything else gets a clear 501 instead of a web page.
|
|
14
13
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
15
14
|
|
|
16
15
|
const json = (status, data) => ({ status, data });
|
|
17
16
|
|
|
18
17
|
function asProxyResult(result, okStatus = 200) {
|
|
19
|
-
if (!result) return json(500, { error: 'OpenCode
|
|
18
|
+
if (!result) return json(500, { error: 'OpenCode gave no answer' });
|
|
20
19
|
if (result.error) {
|
|
21
20
|
const status = Number(result.response?.status) || 500;
|
|
22
21
|
const error = result.error;
|
|
23
|
-
const message = typeof error === 'string' ? error : (error?.message || error?.data?.message || 'OpenCode
|
|
22
|
+
const message = typeof error === 'string' ? error : (error?.message || error?.data?.message || 'OpenCode request failed');
|
|
24
23
|
return json(status >= 400 ? status : 500, { error: message, ...(error && typeof error === 'object' ? { name: error._tag || error.name || undefined } : {}) });
|
|
25
24
|
}
|
|
26
25
|
return json(okStatus, result.data === undefined ? true : result.data);
|
|
27
26
|
}
|
|
28
27
|
|
|
29
|
-
const notOnV2 = (what) => json(501, { error: `${what} is not available on OpenCode 2 from SynaBun yet. Use the OpenCode 2 app or CLI for it.` });
|
|
30
|
-
|
|
31
28
|
/**
|
|
32
|
-
* Answer one raw
|
|
33
|
-
*
|
|
34
|
-
*
|
|
29
|
+
* Answer one raw request on a serve. `client` is an OpenCode 2 client
|
|
30
|
+
* (createOpencode2Client), `rawFetch(path, init)` sends a request under /api/
|
|
31
|
+
* with the serve's password (the pass-through).
|
|
35
32
|
*/
|
|
36
33
|
export async function opencode2Proxy(client, method, path, body = null, { rawFetch = null } = {}) {
|
|
37
34
|
const url = new URL(path, 'http://opencode.invalid');
|
|
@@ -45,37 +42,17 @@ export async function opencode2Proxy(client, method, path, body = null, { rawFet
|
|
|
45
42
|
return rawFetch(`${route}${url.search}`, { method: verb, body });
|
|
46
43
|
}
|
|
47
44
|
|
|
48
|
-
// ──
|
|
49
|
-
if (route === '/global/health' && verb === 'GET') return asProxyResult(await client.global.health());
|
|
50
|
-
// OpenCode 2 has no "dispose": its instances end with the process, which
|
|
51
|
-
// SynaBun stops right after asking.
|
|
52
|
-
if (route === '/global/dispose' && verb === 'POST') return json(200, true);
|
|
53
|
-
|
|
54
|
-
// ── Providers, agents, config ──
|
|
45
|
+
// ── Providers, agents ──
|
|
55
46
|
if (route === '/provider' && verb === 'GET') return asProxyResult(await client.provider.list({ directory }));
|
|
56
|
-
if (route === '/provider/auth' && verb === 'GET') return json(200, {});
|
|
57
|
-
if (segments[0] === 'provider' && segments[2] === 'oauth') return notOnV2('Signing in to a provider');
|
|
58
|
-
if (segments[0] === 'auth' && segments.length === 2) return notOnV2('Saving provider credentials');
|
|
59
47
|
if (route === '/config/providers' && verb === 'GET') return asProxyResult(await client.config.providers({ directory }));
|
|
60
|
-
if (route === '/config' && verb === 'GET') return asProxyResult(await client.config.get({ directory }));
|
|
61
|
-
if (route === '/config' && verb === 'PATCH') return notOnV2('Changing the running OpenCode config');
|
|
62
48
|
if (route === '/agent' && verb === 'GET') return asProxyResult(await client.app.agents({ directory }));
|
|
63
|
-
if (route === '/command' && verb === 'GET') return asProxyResult(await client.command.list({ directory }));
|
|
64
|
-
if (route === '/experimental/tool/ids' && verb === 'GET') return json(200, []);
|
|
65
49
|
|
|
66
|
-
// ── MCP ──
|
|
67
|
-
if (route === '/mcp' && verb === 'GET') return asProxyResult(await client.mcp.status({ directory }));
|
|
68
|
-
if (route === '/mcp' && verb === 'POST') return asProxyResult(await client.mcp.add({ name: body?.name, config: body?.config, directory }));
|
|
69
|
-
if (segments[0] === 'mcp' && segments.length === 3 && verb === 'POST') {
|
|
70
|
-
if (segments[2] === 'connect') return asProxyResult(await client.mcp.connect({ name: segments[1], directory }));
|
|
71
|
-
if (segments[2] === 'disconnect') return asProxyResult(await client.mcp.disconnect({ name: segments[1], directory }));
|
|
72
|
-
}
|
|
73
|
-
if (segments[0] === 'mcp' && segments[2] === 'auth') return notOnV2('Signing in to an MCP server');
|
|
50
|
+
// ── MCP resources ──
|
|
74
51
|
if (route === '/experimental/resource' && verb === 'GET' && typeof rawFetch === 'function') {
|
|
75
52
|
const located = directory ? `?location%5Bdirectory%5D=${encodeURIComponent(directory)}` : '';
|
|
76
53
|
const listed = await rawFetch(`/api/mcp/resource${located}`, { method: 'GET' });
|
|
77
54
|
if (listed.status !== 200) return listed;
|
|
78
|
-
//
|
|
55
|
+
// { "<server>:<uri>": { name, uri, client, … } }
|
|
79
56
|
const out = {};
|
|
80
57
|
for (const resource of Array.isArray(listed.data?.data?.resources) ? listed.data.data.resources : []) {
|
|
81
58
|
if (!resource?.uri) continue;
|
|
@@ -86,31 +63,14 @@ export async function opencode2Proxy(client, method, path, body = null, { rawFet
|
|
|
86
63
|
|
|
87
64
|
// ── Questions ──
|
|
88
65
|
if (route === '/question' && verb === 'GET') return asProxyResult(await client.question.list({ directory }));
|
|
89
|
-
if (segments[0] === 'question' && segments.length === 3 && verb === 'POST') {
|
|
90
|
-
|
|
91
|
-
if (segments[2] === 'reject') return asProxyResult(await client.question.reject({ requestID: segments[1], directory }));
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// ── Permissions ──
|
|
95
|
-
if (route === '/permission' && verb === 'GET') return asProxyResult(await client.permission.list({ directory }));
|
|
96
|
-
if (segments[0] === 'permission' && segments.length === 3 && segments[2] === 'reply' && verb === 'POST') {
|
|
97
|
-
return asProxyResult(await client.permission.reply({ requestID: segments[1], reply: body?.reply, message: body?.message, directory }));
|
|
66
|
+
if (segments[0] === 'question' && segments.length === 3 && segments[2] === 'reply' && verb === 'POST') {
|
|
67
|
+
return asProxyResult(await client.question.reply({ requestID: segments[1], answers: body?.answers, directory }));
|
|
98
68
|
}
|
|
99
69
|
|
|
100
70
|
// ── Sessions ──
|
|
101
|
-
if (
|
|
102
|
-
|
|
103
|
-
const sessionID = segments[1];
|
|
104
|
-
if (verb === 'GET') return asProxyResult(await client.session.get({ sessionID }));
|
|
105
|
-
if (verb === 'DELETE') return asProxyResult(await client.session.delete({ sessionID }));
|
|
106
|
-
if (verb === 'PATCH') return asProxyResult(await client.session.update({ sessionID, ...(body || {}) }));
|
|
107
|
-
}
|
|
108
|
-
if (segments[0] === 'session' && segments.length === 3 && verb === 'POST' && segments[2] === 'abort') {
|
|
109
|
-
return asProxyResult(await client.session.abort({ sessionID: segments[1] }));
|
|
110
|
-
}
|
|
111
|
-
if (segments[0] === 'session' && segments.length === 3 && verb === 'GET' && segments[2] === 'message') {
|
|
112
|
-
return asProxyResult(await client.session.messages({ sessionID: segments[1], directory }));
|
|
71
|
+
if (segments[0] === 'session' && segments.length === 2 && verb === 'DELETE') {
|
|
72
|
+
return asProxyResult(await client.session.delete({ sessionID: segments[1] }));
|
|
113
73
|
}
|
|
114
74
|
|
|
115
|
-
return json(501, { error: `SynaBun does not translate ${verb} ${route} for OpenCode
|
|
75
|
+
return json(501, { error: `SynaBun does not translate ${verb} ${route} for OpenCode.` });
|
|
116
76
|
}
|
|
@@ -84,9 +84,58 @@ export function rulesToV1(rules) {
|
|
|
84
84
|
.map((rule) => ({ permission: v1ToolName(rule.action), pattern: str(rule.resource || '*'), action: str(rule.effect) }));
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
+
/** The variables an OpenCode 2 integration reads a provider's key from (its `env` methods). */
|
|
88
|
+
export function integrationEnvNames(integration) {
|
|
89
|
+
const names = [];
|
|
90
|
+
for (const method of Array.isArray(integration?.methods) ? integration.methods : []) {
|
|
91
|
+
if (method?.type !== 'env' || !Array.isArray(method.names)) continue;
|
|
92
|
+
for (const name of method.names) if (typeof name === 'string' && name && !names.includes(name)) names.push(name);
|
|
93
|
+
}
|
|
94
|
+
return names;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* How each provider is connected, from OpenCode 2's integrations, in OpenCode 1's shape:
|
|
99
|
+
* `{ [id]: [{ type: 'api', label? } | { type: 'oauth', label, id }] }` — a key method is `api`, a sign-in method
|
|
100
|
+
* `oauth` (its `id` is the method SynaBun starts). Methods that take a form of their own (an AWS profile, a
|
|
101
|
+
* Google Cloud project) or run a command are left out; so is an integration with no method left.
|
|
102
|
+
*/
|
|
103
|
+
export function integrationsToAuthMethods(integrations) {
|
|
104
|
+
const out = {};
|
|
105
|
+
for (const integration of Array.isArray(integrations) ? integrations : []) {
|
|
106
|
+
const id = str(integration?.id);
|
|
107
|
+
if (!id) continue;
|
|
108
|
+
const methods = [];
|
|
109
|
+
for (const method of Array.isArray(integration.methods) ? integration.methods : []) {
|
|
110
|
+
if (method?.type === 'key' && !(Array.isArray(method.form) && method.form.length)) methods.push({ type: 'api', ...(method.label ? { label: str(method.label) } : {}) });
|
|
111
|
+
else if (method?.type === 'oauth' && method.id && !(Array.isArray(method.form) && method.form.some((field) => field?.required && !field.hidden && field.default === undefined))) {
|
|
112
|
+
methods.push({ type: 'oauth', label: str(method.label || 'Sign in'), id: str(method.id) });
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
if (methods.length) out[id] = methods;
|
|
116
|
+
}
|
|
117
|
+
return out;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/** The integrations with a credential of their own stored (an `env` connection is the user's environment, not one). */
|
|
121
|
+
export function integrationsWithCredentials(integrations) {
|
|
122
|
+
return (Array.isArray(integrations) ? integrations : [])
|
|
123
|
+
.filter((integration) => integration?.id && (Array.isArray(integration.connections) ? integration.connections : []).some((connection) => connection?.type === 'credential' && connection.id))
|
|
124
|
+
.map((integration) => str(integration.id));
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/** The credential ids an integration stored. */
|
|
128
|
+
export function integrationCredentialIds(integration) {
|
|
129
|
+
return (Array.isArray(integration?.connections) ? integration.connections : [])
|
|
130
|
+
.filter((connection) => connection?.type === 'credential' && connection.id)
|
|
131
|
+
.map((connection) => str(connection.id));
|
|
132
|
+
}
|
|
133
|
+
|
|
87
134
|
/**
|
|
88
|
-
* OpenCode
|
|
89
|
-
* `
|
|
135
|
+
* Permission rules as OpenCode 2 takes them: its own `{ action, resource,
|
|
136
|
+
* effect }` as they are, the OpenCode 1 shapes a caller or a user's file may
|
|
137
|
+
* still hold (`[{ permission, pattern, action }]`, or the
|
|
138
|
+
* `{ bash: 'ask', edit: { '*.md': 'allow' } }` map) converted.
|
|
90
139
|
*/
|
|
91
140
|
export function rulesToV2(rules) {
|
|
92
141
|
if (rules == null) return undefined;
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
// ═══════════════════════════════════════════
|
|
2
|
+
// SynaBun — the one decision for the owner's routes: who may act with the owner's powers
|
|
3
|
+
// ═══════════════════════════════════════════
|
|
4
|
+
//
|
|
5
|
+
// Many of SynaBun's routes act with the owner's own powers without asking for the page secret: they were guarded
|
|
6
|
+
// by the Host, the Origin and the guest rules only (lib/http-guards.js ownerRouteGuard, lib/request-gate.js). A
|
|
7
|
+
// page of the app passes those by being a page of the app — and so did SynaBun's automation browser, which a
|
|
8
|
+
// sandboxed worker drives with its sanctioned browser tools: it could open the File Explorer and write anywhere,
|
|
9
|
+
// save in the code editor, run git, start the tunnel, make an invite, change Settings, open a terminal tab or an
|
|
10
|
+
// agent panel and type into it — each a way out of the worker's sandbox. A local relay (a proxy, ssh -L, any program
|
|
11
|
+
// that listens and calls SynaBun) was the same way out for a worker that cannot reach SynaBun's port itself.
|
|
12
|
+
//
|
|
13
|
+
// This module is the one decision for all of them, made on what the request cannot choose: the automation
|
|
14
|
+
// browser's marker (lib/page-session.js) and the process at the other end of the connection (lib/peer-identity.js,
|
|
15
|
+
// whose verdict the peer middleware keeps on the request). It covers:
|
|
16
|
+
// • every request to /api that is not a GET / HEAD / OPTIONS (default-deny: a route added later is covered), but
|
|
17
|
+
// for FEATURE_OPEN_PREFIXES — the hooks' own routes and the feature data the agents' MCP tools write too
|
|
18
|
+
// (memories, cards, the whiteboard…), where a refusal would stop the owner's integrations and buy nothing;
|
|
19
|
+
// • the two reads that hand out a secret: GET /api/mcp-key (the whole MCP key) and GET /api/mcp/env/<name>?reveal=1;
|
|
20
|
+
// • the owner's own reads (OWNER_READ_PREFIXES: what a guest is refused, and git), for the peers that are never the
|
|
21
|
+
// owner — the code editor's and File Explorer's roots include SynaBun's data home, whose secrets the worker
|
|
22
|
+
// sandbox keeps from a worker; an agent's tree reads them as before;
|
|
23
|
+
// • the owner's sockets: a terminal, the Claude / Codex / OpenCode panels, the Assistant, the browser panel —
|
|
24
|
+
// and /ws/sync, which stays open (the app's pages need it to draw) but read-only.
|
|
25
|
+
//
|
|
26
|
+
// Refused, whatever the request says (headers, pins, cookies, Origin): a request with the automation browser's
|
|
27
|
+
// marker; a peer that is SynaBun's automation browser or any browser started for automation, a relay (named, or a
|
|
28
|
+
// program that listens), another SynaBun server, a remote login (sshd), or a client that left before it was
|
|
29
|
+
// identified. Refused too, unless it is an agent's own call: an AI agent's process tree, and SynaBun's own MCP server
|
|
30
|
+
// over HTTP (mcp-server/dist/http.js: it listens, so it would read as a relay; lib/peer-identity.js knows it by its
|
|
31
|
+
// main script inside this install, and its tools call with the stdio MCP server's pin). An agent's own call is
|
|
32
|
+
// one that says who it is — an agent pin (X-Synabun-Terminal / -Role / -Assistant / -Desktop-Grant) or a brain
|
|
33
|
+
// credential that survived the peer check — and stays on its route's rules (the MCP git tool, desktop, loop and
|
|
34
|
+
// browser tools; the brain; the Assistant's route gate, asked with the session's pin by the OpenCode plugin and the
|
|
35
|
+
// Codex hook, which checks the session's own token), as do the few routes agents call without a pin
|
|
36
|
+
// (AGENT_OPEN_PREFIXES: the server's stop and restart the CLI asks, the MCP server's tab release, and the loops and
|
|
37
|
+
// schedules the /synabun skill creates with curl).
|
|
38
|
+
//
|
|
39
|
+
// Never refused by this module: the owner's own browser and the SynaBun app (the peer lookup allows them), this
|
|
40
|
+
// server itself, a request from outside (the tunnel, the invite proxy: the guest rules decide those, and the
|
|
41
|
+
// tunnel's own process would otherwise read as a relay), and any request whose peer could not be looked up (the
|
|
42
|
+
// rules from before apply: a failed lookup never locks the owner out).
|
|
43
|
+
|
|
44
|
+
import { readFileSync } from 'node:fs';
|
|
45
|
+
import { AGENT_HEADERS, sendGuardError } from './http-guards.js';
|
|
46
|
+
import { BRAIN_HEADER, PEER_VERDICT } from './peer-identity.js';
|
|
47
|
+
import { ADMIN_ONLY_PREFIXES, routedForms } from './request-gate.js';
|
|
48
|
+
|
|
49
|
+
const SAFE_METHODS = new Set(['GET', 'HEAD', 'OPTIONS']);
|
|
50
|
+
|
|
51
|
+
/** Writes left open to every caller the rules before allowed: the hooks' own routes, and the feature data the
|
|
52
|
+
* agents' MCP tools write too. A path counts as open only when every reading of it is open. */
|
|
53
|
+
export const FEATURE_OPEN_PREFIXES = Object.freeze([
|
|
54
|
+
'/api/hook-', '/api/greeting', '/api/sessions',
|
|
55
|
+
'/api/memory', '/api/memories', '/api/memory-maintenance', '/api/categories', '/api/trash', '/api/search',
|
|
56
|
+
'/api/cards', '/api/whiteboard', '/api/images', '/api/games',
|
|
57
|
+
'/api/cache', '/api/fetch-markdown', '/api/last-session', '/api/health',
|
|
58
|
+
'/api/ui-blobs',
|
|
59
|
+
]);
|
|
60
|
+
/** Paths under an open prefix that are not open: the code editor's copies of unsaved buffers (file content). */
|
|
61
|
+
export const NEVER_OPEN_PREFIXES = Object.freeze(['/api/ui-blobs/editor-backups']);
|
|
62
|
+
/** Routes agents call without a pin: an agent's tree may call them as it did (the other peers are still refused). */
|
|
63
|
+
export const AGENT_OPEN_PREFIXES = Object.freeze(['/api/server/', '/api/browser/release', '/api/loop', '/api/schedules', '/api/schedule-groups']);
|
|
64
|
+
/** The peers whose own calls (pinned, or on an agent-open route) keep their route's rules: an AI agent's process tree,
|
|
65
|
+
* and SynaBun's own MCP server over HTTP (lib/peer-identity.js isSynabunMcpServer), as the stdio one in an agent's tree. */
|
|
66
|
+
export const AGENT_CALL_KINDS = Object.freeze(['agent', 'synabun-mcp']);
|
|
67
|
+
/**
|
|
68
|
+
* The owner's own reads: what a guest is refused (lib/request-gate.js ADMIN_ONLY_PREFIXES — the owner's settings,
|
|
69
|
+
* the code editor's and the File Explorer's file contents, whose roots include SynaBun's data home with its secrets,
|
|
70
|
+
* the runs' transcripts, MCP and plugin configuration…) and git. Refused to the automation browser, relays, other
|
|
71
|
+
* SynaBun servers, remote logins and closed clients (the sandbox keeps a worker out of the data home; these reads
|
|
72
|
+
* would hand it over through a browser or a relay). An agent's tree reads them as before (it is not sandboxed when
|
|
73
|
+
* it can reach SynaBun at all, and the CLI and the MCP tools read some of them). The hooks' own routes are not here.
|
|
74
|
+
*/
|
|
75
|
+
export const OWNER_READ_PREFIXES = Object.freeze([...ADMIN_ONLY_PREFIXES.filter((prefix) => prefix !== '/api/hook-'), '/api/git']);
|
|
76
|
+
/** The owner's sockets: a terminal, the agent panels, the Assistant, the browser panel. */
|
|
77
|
+
export const OWNER_SOCKET_PREFIXES = Object.freeze(['/ws/terminal/', '/ws/claude-skin', '/ws/codex-skin', '/ws/opencode-v2', '/ws/assistant/', '/ws/browser/']);
|
|
78
|
+
/** Sockets that stay open for the app's pages to draw, read-only for a peer the owner's powers are refused to. */
|
|
79
|
+
export const READ_ONLY_SOCKET_PATHS = Object.freeze(['/ws/sync']);
|
|
80
|
+
|
|
81
|
+
/** A path form under a prefix: a prefix ending in "/" or "-" is a plain prefix, any other is a whole segment. */
|
|
82
|
+
function under(form, prefix) {
|
|
83
|
+
if (prefix.endsWith('/') || prefix.endsWith('-')) return form.startsWith(prefix);
|
|
84
|
+
return form === prefix || form.startsWith(`${prefix}/`);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// ── A proxy between the owner's browser and SynaBun ──────────────────────────
|
|
88
|
+
// A relay is refused because it hides who asked: through a system proxy, ssh -D or a proxy extension, the owner's own
|
|
89
|
+
// browser reads as the relay. Browsers normally send localhost and 127.0.0.1 straight past a system proxy, so this
|
|
90
|
+
// takes a browser told to proxy them (an extension, a PAC file, Firefox's localhost setting) or SynaBun opened by a
|
|
91
|
+
// name or address the bypass list lacks. The refusal then says what to do, in the request's language (Accept-Language:
|
|
92
|
+
// the i18n files' `ownerAuthority` strings). A relay is never trusted instead, not even one whose parents lead back to
|
|
93
|
+
// the owner's browser: who its client is cannot be seen from SynaBun, and a guarded worker's sandbox keeps the system
|
|
94
|
+
// proxy reachable for the worker's internet, so its requests would arrive from that same relay.
|
|
95
|
+
|
|
96
|
+
/** The refusal kinds that mean "something carries this request for someone else". */
|
|
97
|
+
export const PROXY_REFUSAL_KINDS = Object.freeze(['relay', 'listener']);
|
|
98
|
+
const COPY_LOCALES = Object.freeze(['en', 'pt-BR']);
|
|
99
|
+
let ownerCopies = null;
|
|
100
|
+
/** The `ownerAuthority` strings of every locale (read once, when a refusal first needs them). */
|
|
101
|
+
function ownerCopy(locale) {
|
|
102
|
+
if (!ownerCopies) {
|
|
103
|
+
ownerCopies = {};
|
|
104
|
+
for (const code of COPY_LOCALES) {
|
|
105
|
+
try { ownerCopies[code] = JSON.parse(readFileSync(new URL(`../i18n/${code}.json`, import.meta.url), 'utf8'))?.ownerAuthority || {}; } catch { ownerCopies[code] = {}; }
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return { ...(ownerCopies.en || {}), ...(ownerCopies[locale] || {}) };
|
|
109
|
+
}
|
|
110
|
+
/** The request's language among the i18n files' (pt-* → pt-BR), by the Accept-Language preference order; else en. */
|
|
111
|
+
export function requestLocale(req) {
|
|
112
|
+
const header = String(req?.headers?.['accept-language'] || '');
|
|
113
|
+
const ranked = header.split(',').map((part, index) => {
|
|
114
|
+
const [tag, ...params] = part.trim().split(';');
|
|
115
|
+
const q = Number(params.map((p) => /^\s*q=([\d.]+)\s*$/.exec(p)?.[1]).find(Boolean) ?? 1);
|
|
116
|
+
return { tag: tag.trim().toLowerCase(), q: Number.isFinite(q) ? q : 0, index };
|
|
117
|
+
}).filter((x) => x.tag && x.q > 0).sort((a, b) => b.q - a.q || a.index - b.index);
|
|
118
|
+
for (const { tag } of ranked) {
|
|
119
|
+
if (tag === 'pt' || tag.startsWith('pt-')) return 'pt-BR';
|
|
120
|
+
if (tag === 'en' || tag.startsWith('en-')) return 'en';
|
|
121
|
+
}
|
|
122
|
+
return 'en';
|
|
123
|
+
}
|
|
124
|
+
/** What to do when the owner's browser reaches SynaBun through a proxy (`ownerAuthority.proxyRefused`), filled in. */
|
|
125
|
+
export function proxyRefusalText(req, refuse) {
|
|
126
|
+
const template = ownerCopy(requestLocale(req)).proxyRefused;
|
|
127
|
+
const params = { name: String(refuse?.name || 'a proxy').slice(0, 64), pid: String(refuse?.pid ?? '?') };
|
|
128
|
+
if (typeof template !== 'string' || !template) return `Your browser reaches SynaBun through ${params.name} (pid ${params.pid}), a proxy or relay, so SynaBun refused this: add localhost and 127.0.0.1 to the proxy's bypass list, or turn the proxy off for SynaBun, then reload.`;
|
|
129
|
+
return template.replace(/\{(\w+)\}/g, (whole, key) => (params[key] != null ? params[key] : whole));
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/** Does a request say it is an agent's own call (a pin, or a brain credential that survived the peer check)? */
|
|
133
|
+
export function isAgentCall(req) {
|
|
134
|
+
const h = req?.headers || {};
|
|
135
|
+
return AGENT_HEADERS.some((name) => h[name] !== undefined) || typeof h[BRAIN_HEADER] === 'string';
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Where an HTTP request stands: `gated` (one of the owner's writes, one of the owner's reads, or a secret read), and
|
|
140
|
+
* `agentOpen` (an agent's tree may call it without a pin: every owner's read but the secret ones, and the
|
|
141
|
+
* AGENT_OPEN_PREFIXES writes). A path with no safe reading is gated.
|
|
142
|
+
*/
|
|
143
|
+
export function restScope(req) {
|
|
144
|
+
const method = String(req?.method || 'GET').toUpperCase();
|
|
145
|
+
const forms = routedForms(String(req?.path ?? req?.url ?? ''));
|
|
146
|
+
if (!forms) return { gated: !SAFE_METHODS.has(method), agentOpen: false, reason: 'no safe reading of the path' };
|
|
147
|
+
if (SAFE_METHODS.has(method)) {
|
|
148
|
+
if (method === 'OPTIONS') return { gated: false, agentOpen: false };
|
|
149
|
+
const reveal = String(req?.query?.reveal || '') === '1';
|
|
150
|
+
if (forms.some((form) => form === '/api/mcp-key' || (reveal && form.startsWith('/api/mcp/env/')))) {
|
|
151
|
+
return { gated: true, agentOpen: false, reason: 'a read that hands out a secret' };
|
|
152
|
+
}
|
|
153
|
+
// (ADMIN_ONLY_PREFIXES are plain prefixes, as lib/request-gate.js reads them)
|
|
154
|
+
const ownerRead = forms.some((form) => OWNER_READ_PREFIXES.some((prefix) => form.startsWith(prefix)));
|
|
155
|
+
return { gated: ownerRead, agentOpen: true, reason: ownerRead ? 'one of the owner\'s reads' : null };
|
|
156
|
+
}
|
|
157
|
+
if (!forms.some((form) => under(form, '/api'))) return { gated: false, agentOpen: false };
|
|
158
|
+
const open = (form) => FEATURE_OPEN_PREFIXES.some((prefix) => under(form, prefix)) && !NEVER_OPEN_PREFIXES.some((prefix) => under(form, prefix));
|
|
159
|
+
if (forms.every(open)) return { gated: false, agentOpen: false };
|
|
160
|
+
return { gated: true, agentOpen: forms.every((form) => AGENT_OPEN_PREFIXES.some((prefix) => under(form, prefix))), reason: 'one of the owner\'s writes' };
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/** Where a socket stands: `owner` (refused to the peers below) or `readOnly` (open, read-only for them). */
|
|
164
|
+
export function socketScope(pathname) {
|
|
165
|
+
const p = String(pathname || '');
|
|
166
|
+
if (OWNER_SOCKET_PREFIXES.some((prefix) => (prefix.endsWith('/') ? p.startsWith(prefix) : p === prefix))) return { owner: true, readOnly: false };
|
|
167
|
+
if (READ_ONLY_SOCKET_PATHS.includes(p)) return { owner: false, readOnly: true };
|
|
168
|
+
return { owner: false, readOnly: false };
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* The decision for one request whose peer verdict is on it (or not: then only the marker counts).
|
|
173
|
+
* @param {object} req
|
|
174
|
+
* @param {{ agentOpen?: boolean, fromWorkerBrowser?: (req) => boolean }} o
|
|
175
|
+
* @returns {{ code: string, error: string, hint?: string, peer?: object } | null} `hint: 'proxy'` (with the relay's
|
|
176
|
+
* kind, pid and name) when the peer carries requests for others: `error` then says what to do, in the request's language
|
|
177
|
+
*/
|
|
178
|
+
export function ownerRefusal(req, { agentOpen = false, fromWorkerBrowser = () => false } = {}) {
|
|
179
|
+
let marked = false;
|
|
180
|
+
try { marked = !!fromWorkerBrowser(req); } catch { marked = false; }
|
|
181
|
+
if (marked) return { code: 'WORKER_BROWSER', error: 'SynaBun\'s automation browser cannot act as the owner: it reads SynaBun\'s pages, clicks and screenshots; the owner\'s own settings, files and actions are the owner\'s, from the owner\'s browser or the app.' };
|
|
182
|
+
const peer = req?.[PEER_VERDICT];
|
|
183
|
+
if (!peer) return null;
|
|
184
|
+
if (peer.status === 'gone') return { code: 'PEER_REFUSED', error: `This is the owner's, and ${peer.reason || 'the connection closed before its request was identified'}.` };
|
|
185
|
+
if (peer.status !== 'ok' || peer.self || !peer.refuse) return null;
|
|
186
|
+
if (AGENT_CALL_KINDS.includes(peer.refuse.kind) && (agentOpen || isAgentCall(req))) return null; // an agent's own call: its route's rules
|
|
187
|
+
if (PROXY_REFUSAL_KINDS.includes(peer.refuse.kind)) {
|
|
188
|
+
return { code: 'PEER_REFUSED', error: proxyRefusalText(req, peer.refuse), hint: 'proxy', peer: { kind: peer.refuse.kind, pid: peer.refuse.pid, name: peer.refuse.name } };
|
|
189
|
+
}
|
|
190
|
+
return { code: 'PEER_REFUSED', error: `This is the owner's, from the owner's own browser or the app; this request comes from ${peer.refuse.why}: pid ${peer.refuse.pid} (${peer.refuse.name}).` };
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* @param {object} o
|
|
195
|
+
* @param {() => ({ fromWorkerBrowser(req): boolean } | null)} [o.pageSession] the page session (read at request time)
|
|
196
|
+
* @param {(req) => boolean} [o.isRemote] a request from outside (the tunnel, the invite proxy): the guest rules decide
|
|
197
|
+
* @param {{ lookup(req): Promise<object> }} [o.peer] lib/peer-identity.js (for sockets: no middleware runs for them)
|
|
198
|
+
* @param {(line: string) => void} [o.log]
|
|
199
|
+
*/
|
|
200
|
+
export function createOwnerAuthority({ pageSession = () => null, isRemote = () => false, peer = null, log = () => {} } = {}) {
|
|
201
|
+
const fromWorkerBrowser = (req) => { const s = pageSession(); return typeof s?.fromWorkerBrowser === 'function' ? s.fromWorkerBrowser(req) : false; };
|
|
202
|
+
const remote = (req) => { try { return isRemote(req) === true; } catch { return false; } };
|
|
203
|
+
const logged = new Map();
|
|
204
|
+
const note = (key, line) => {
|
|
205
|
+
const now = Date.now();
|
|
206
|
+
if (now - (logged.get(key) || 0) < 60_000) return;
|
|
207
|
+
logged.set(key, now);
|
|
208
|
+
if (logged.size > 500) logged.delete(logged.keys().next().value);
|
|
209
|
+
try { log(line); } catch { /* a logger's own failure */ }
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
/** Whether the peer middleware should look this request up (it is one of the owner's, and not from outside). */
|
|
213
|
+
function needsLookup(req) {
|
|
214
|
+
if (remote(req)) return false;
|
|
215
|
+
try { return restScope(req).gated; } catch { return true; }
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/** Express middleware, mounted after the peer middleware: 403 for a refused request to one of the owner's routes
|
|
219
|
+
* (its writes, its reads, a secret read). */
|
|
220
|
+
function restGate(req, res, next) {
|
|
221
|
+
let scope;
|
|
222
|
+
try { scope = restScope(req); } catch { scope = { gated: true, agentOpen: false }; }
|
|
223
|
+
if (!scope.gated || remote(req)) return next();
|
|
224
|
+
const refused = ownerRefusal(req, { agentOpen: scope.agentOpen, fromWorkerBrowser });
|
|
225
|
+
if (!refused) return next();
|
|
226
|
+
note(`${refused.code}:${req[PEER_VERDICT]?.pid || 'marker'}:${String(req.path).slice(0, 80)}`, `[owner-authority] refused ${req.method} ${String(req.path).slice(0, 120)}: ${refused.hint === 'proxy' ? `${req[PEER_VERDICT]?.refuse?.why}: pid ${refused.peer?.pid} (${refused.peer?.name})` : refused.error}`);
|
|
227
|
+
if (refused.hint) return res.status(403).json({ ok: false, code: refused.code, error: refused.error, hint: refused.hint, peer: refused.peer });
|
|
228
|
+
return sendGuardError(res, 403, refused.code, refused.error);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* The decision for a WebSocket upgrade (no middleware runs for one): looks the peer up for an owner socket and for
|
|
233
|
+
* /ws/sync. → { refuse: boolean, readOnly: boolean, code?, error? }. Never rejects; a lookup that cannot run
|
|
234
|
+
* refuses nothing.
|
|
235
|
+
*/
|
|
236
|
+
async function checkUpgrade(req, pathname) {
|
|
237
|
+
const scope = socketScope(pathname);
|
|
238
|
+
if ((!scope.owner && !scope.readOnly) || remote(req)) return { refuse: false, readOnly: false };
|
|
239
|
+
if (peer && typeof peer.lookup === 'function' && !req[PEER_VERDICT]) {
|
|
240
|
+
try { req[PEER_VERDICT] = await peer.lookup(req); } catch { /* unknown: the rules from before */ }
|
|
241
|
+
}
|
|
242
|
+
const refused = ownerRefusal(req, { agentOpen: false, fromWorkerBrowser });
|
|
243
|
+
if (!refused) return { refuse: false, readOnly: false };
|
|
244
|
+
note(`ws:${refused.code}:${req[PEER_VERDICT]?.pid || 'marker'}:${pathname}`, `[owner-authority] ${scope.owner ? 'refused' : 'read-only'} socket ${pathname}: ${refused.error}`);
|
|
245
|
+
return scope.owner ? { refuse: true, readOnly: false, ...refused } : { refuse: false, readOnly: true, ...refused };
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
return { needsLookup, restGate, checkUpgrade, restScope, socketScope };
|
|
249
|
+
}
|