synabun 2.0.9 → 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 +115 -0
- package/README.md +25 -2
- package/THIRD-PARTY-LICENSES.md +68 -4
- 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/launcher.mjs +9 -3
- 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 +43 -5
- 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 +3680 -206
- package/neural-interface/i18n/pt-BR.json +3628 -157
- package/neural-interface/lib/account-usage.js +5 -3
- package/neural-interface/lib/app-controls-api.js +161 -0
- package/neural-interface/lib/assistant-api.js +148 -35
- 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 +122 -44
- package/neural-interface/lib/assistant-brains/opencode2-browser-policy/index.js +59 -0
- package/neural-interface/lib/assistant-brains/opencode2-route-gate/index.js +97 -0
- package/neural-interface/lib/assistant-catalog.js +23 -9
- package/neural-interface/lib/assistant-dispatch.js +874 -156
- package/neural-interface/lib/assistant-envelope.js +22 -2
- 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 +183 -26
- 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-model-catalog.js +64 -14
- 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-settings-schema.js +109 -47
- 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 +164 -67
- package/neural-interface/lib/exec-loop-command.js +4 -1
- package/neural-interface/lib/http-guards.js +8 -2
- package/neural-interface/lib/install-details.js +4 -1
- package/neural-interface/lib/launch-cache.js +293 -0
- package/neural-interface/lib/login-start.js +524 -0
- 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 +565 -50
- package/neural-interface/lib/native-loop-runtime.js +287 -41
- package/neural-interface/lib/opencode-config.js +557 -0
- package/neural-interface/lib/opencode-db-schema.js +58 -0
- package/neural-interface/lib/opencode-history.js +49 -204
- 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 +310 -0
- package/neural-interface/lib/opencode-provider-view.js +81 -0
- package/neural-interface/lib/opencode-runtime-config.js +32 -15
- package/neural-interface/lib/opencode-serve-records.js +624 -0
- package/neural-interface/lib/opencode-v2-client.js +53 -131
- package/neural-interface/lib/opencode-v2-ws-requests.js +35 -195
- package/neural-interface/lib/opencode-worker-activity.js +229 -0
- package/neural-interface/lib/opencode-worker-data.js +27 -0
- package/neural-interface/lib/opencode2-client.js +796 -0
- package/neural-interface/lib/opencode2-proxy.js +76 -0
- package/neural-interface/lib/opencode2-translate.js +1057 -0
- 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/process-identity.js +361 -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 +18 -10
- package/neural-interface/lib/session-title-generator.js +58 -18
- 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/style-guide/api.js +4 -3
- package/neural-interface/lib/tool-lists.js +124 -0
- package/neural-interface/lib/untrusted-file-headers.js +27 -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 +1354 -50
- package/neural-interface/package.json +6 -2
- package/neural-interface/public/index.html +5 -3
- 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 +76 -16
- 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 +205 -19
- package/neural-interface/public/shared/assistant/asst-api.js +11 -3
- 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 +241 -112
- package/neural-interface/public/shared/assistant/asst-composer.js +1 -1
- 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-hosts.js +49 -2
- 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 +84 -12
- package/neural-interface/public/shared/assistant/asst-panel.js +303 -44
- package/neural-interface/public/shared/assistant/asst-rack-styles.js +93 -58
- package/neural-interface/public/shared/assistant/asst-redact.js +186 -0
- package/neural-interface/public/shared/assistant/asst-render.js +770 -100
- package/neural-interface/public/shared/assistant/asst-route.js +83 -12
- package/neural-interface/public/shared/assistant/asst-run-stage.js +231 -0
- package/neural-interface/public/shared/assistant/asst-sanitize.js +193 -3
- package/neural-interface/public/shared/assistant/asst-scene-styles.js +273 -0
- package/neural-interface/public/shared/assistant/asst-scenes.js +530 -0
- package/neural-interface/public/shared/assistant/asst-sidepanel-styles.js +3 -15
- 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 +25 -15
- package/neural-interface/public/shared/assistant/asst-stop.js +127 -0
- package/neural-interface/public/shared/assistant/asst-styles.js +102 -21
- package/neural-interface/public/shared/assistant/asst-tool-kinds.js +165 -13
- package/neural-interface/public/shared/automation-context.js +5 -2
- package/neural-interface/public/shared/cc-dropdown.js +550 -0
- 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 +58 -150
- package/neural-interface/public/shared/cdx/cdx-protocol.js +28 -1
- package/neural-interface/public/shared/cdx/cdx-render.js +62 -32
- 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 +15 -3
- package/neural-interface/public/shared/cdx/cdx-tabs.js +201 -74
- 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/cp/cp-markdown.js +4 -57
- package/neural-interface/public/shared/crash-notice-view.js +168 -0
- package/neural-interface/public/shared/data-cache.js +223 -0
- package/neural-interface/public/shared/desktop-bridge.js +11 -0
- package/neural-interface/public/shared/desktop-titlebar-view.js +78 -1
- package/neural-interface/public/shared/desktop-titlebar.js +214 -28
- package/neural-interface/public/shared/desktop-update-view.js +35 -5
- package/neural-interface/public/shared/editor/editor-panel-logic.js +2 -2
- package/neural-interface/public/shared/file-links.js +73 -8
- package/neural-interface/public/shared/html-shell.js +78 -86
- package/neural-interface/public/shared/i18n.js +2 -0
- package/neural-interface/public/shared/launch-prefetch.js +59 -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-caps.js +3 -2
- 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 +9 -2
- 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-modelpicker.js +54 -17
- 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 +140 -254
- package/neural-interface/public/shared/ocp-v2/ocp-v2-plan.js +1 -2
- package/neural-interface/public/shared/ocp-v2/ocp-v2-projectbar.js +97 -203
- package/neural-interface/public/shared/ocp-v2/ocp-v2-providers.js +11 -9
- package/neural-interface/public/shared/ocp-v2/ocp-v2-rehydrate.js +15 -4
- package/neural-interface/public/shared/ocp-v2/ocp-v2-render.js +7 -22
- package/neural-interface/public/shared/ocp-v2/ocp-v2-send-logic.js +401 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-send.js +20 -13
- 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 +53 -82
- 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 +48 -40
- 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 +205 -62
- package/neural-interface/public/shared/opencode-providers.js +39 -0
- 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 +452 -0
- package/neural-interface/public/shared/settings/settings-app-pane.js +335 -0
- package/neural-interface/public/shared/settings/settings-app.js +243 -0
- package/neural-interface/public/shared/settings/settings-claude-hooks.js +135 -0
- package/neural-interface/public/shared/settings/settings-data.js +90 -0
- package/neural-interface/public/shared/settings/settings-ia.js +23 -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/sidepanel-session-status.js +49 -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 +2065 -2150
- 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-assistant.js +27 -5
- package/neural-interface/public/shared/ui-automation-studio.js +155 -152
- package/neural-interface/public/shared/ui-bookmarks.js +2 -1
- package/neural-interface/public/shared/ui-claude-panel.js +153 -13
- package/neural-interface/public/shared/ui-codex-panel.js +1 -0
- 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 +21 -9
- package/neural-interface/public/shared/ui-file-links.js +1 -0
- package/neural-interface/public/shared/ui-image-gallery.js +56 -52
- package/neural-interface/public/shared/ui-invite.js +18 -2
- package/neural-interface/public/shared/ui-keybinds.js +26 -1
- package/neural-interface/public/shared/ui-link.js +9 -9
- package/neural-interface/public/shared/ui-menubar.js +229 -40
- package/neural-interface/public/shared/ui-native-loop-router-state.js +5 -0
- package/neural-interface/public/shared/ui-native-loop-router.js +9 -1
- package/neural-interface/public/shared/ui-navbar.js +4 -24
- package/neural-interface/public/shared/ui-opencode-panel-v2.js +1 -0
- package/neural-interface/public/shared/ui-panels.js +96 -65
- package/neural-interface/public/shared/ui-schedules-studio.js +2267 -953
- package/neural-interface/public/shared/ui-sessions.js +20 -7
- package/neural-interface/public/shared/ui-settings.js +679 -496
- package/neural-interface/public/shared/ui-sidebar.js +4 -4
- package/neural-interface/public/shared/ui-sidepanel-session-entry.js +13 -0
- package/neural-interface/public/shared/ui-sidepanel-sessions.js +56 -5
- package/neural-interface/public/shared/ui-sidepanel-state.js +23 -12
- package/neural-interface/public/shared/ui-sidepanel-tray.js +84 -8
- package/neural-interface/public/shared/ui-sidepanel-windows.js +16 -11
- package/neural-interface/public/shared/ui-skills.js +42 -2781
- package/neural-interface/public/shared/ui-styleguide.js +5 -2
- package/neural-interface/public/shared/ui-sync.js +22 -5
- package/neural-interface/public/shared/ui-terminal.js +159 -199
- 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 +14 -5
- 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 -61
- package/neural-interface/public/shared/ui-tutorial.css +47 -100
- package/neural-interface/public/shared/ui-tutorial.js +285 -499
- package/neural-interface/public/shared/ui-update.js +121 -16
- package/neural-interface/public/shared/ui-whiteboard.js +313 -59
- 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 +36 -2
- package/neural-interface/public/variant/2d/minimap.js +11 -13
- package/neural-interface/public/variant/3d/main.js +72 -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/highlight/LICENSE +29 -0
- package/neural-interface/public/vendor/highlight/github-dark-dimmed-11.12.0.min.css +9 -0
- package/neural-interface/public/vendor/highlight/highlight-11.12.0.min.js +1262 -0
- package/neural-interface/public/vendor/highlight/manifest.json +5 -0
- package/neural-interface/public/vendor/html2canvas/LICENSE +22 -0
- package/neural-interface/public/vendor/html2canvas/html2canvas-1.4.1.min.js +20 -0
- package/neural-interface/public/vendor/html2canvas/manifest.json +4 -0
- package/neural-interface/public/vendor/marked/LICENSE.md +44 -0
- package/neural-interface/public/vendor/marked/manifest.json +4 -0
- package/neural-interface/public/vendor/marked/marked-14.1.4.esm.js +2502 -0
- package/neural-interface/public/vendor/mermaid/LICENSE +21 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/abnfDiagram-PAR5IXJI.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/architecture-7GRP2DOG-M7G3SWCO.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/architectureDiagram-2PNWDENW.mjs +36 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/blockDiagram-PUWGUBOA.mjs +129 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/c4Diagram-3NLNHZP5.mjs +38 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-2NMSUPJH.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-32MCUW2P.mjs +206 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-3NPNU5GP.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-3SMGFRGC.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-4CAJECRU.mjs +14 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-4OADUZ5Q.mjs +10 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-5IMINLNL.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-5IQCK5RY.mjs +3 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-5MVFYWFU.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-AQ6EADP3.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-AZZRMDJM.mjs +15 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-CLS4B6BI.mjs +168 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-DZP67EKU.mjs +70 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-EICP7K5X.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-GDY2UAB4.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-H7VHZCWX.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-IJBDOHL6.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-JFFVMJIA.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-JQRUD6KW.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-JZGDI5JK.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-KD6SPIPN.mjs +2 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-NF366YI6.mjs +231 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-NUDPKBEF.mjs +32 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-OJINMHTS.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-Q6NGPIAH.mjs +2 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-QJSWEUOL.mjs +132 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-R7JDMUKV.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-RCXAM2GK.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-RT4MAWR3.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-SFMINX4W.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-SLDQ463B.mjs +88 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-STOV2HOB.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-T5OCTHI4.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-TCEHX7R3.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-VQC2EELJ.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-VRZKL3EH.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-VTHDQ7BV.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-VY2OSTJR.mjs +2 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-WUBWJARI.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-YBMQ5JGJ.mjs +2 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-YDMLL4PJ.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-Z6V44ARX.mjs +62 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-ZJJ7VQJP.mjs +339 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-ZNLK7HRR.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-ZQN7UHIL.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-ZS6VBONO.mjs +174 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-ZUNWM646.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/classDiagram-FGAMPOII.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/classDiagram-v2-AI5RJEK4.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/cose-bilkent-Q72C2OJ3.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/cynefin-OW5HDTMX-6OCTWOGG.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/cynefinDiagram-2OOWUY4M.mjs +62 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/dagre-MPVFI544.mjs +4 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/diagram-AE4NWXFW.mjs +24 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/diagram-BUJID5UG.mjs +41 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/diagram-C44CZ5NI.mjs +24 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/diagram-EYOLEXXS.mjs +30 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/diagram-P7B6PWOJ.mjs +3 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/ebnfDiagram-FTPZ3PV6.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/erDiagram-H3ERR26V.mjs +99 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/eventmodeling-NTZA5JFV-WKSWQHFS.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/flowDiagram-YHGXBVSY.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/ganttDiagram-RWFTB7ED.mjs +292 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/gitGraph-4MIJSDKK-JH2HKYUO.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/gitGraphDiagram-MAR6GKOP.mjs +106 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/info-A6RAGUB7-3TX3OFWW.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/infoDiagram-LV547AFH.mjs +2 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/ishikawaDiagram-PUJQGNDS.mjs +70 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/journeyDiagram-EW5QJT4W.mjs +139 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/kanban-definition-JSQERAZB.mjs +89 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/katex-CZ4GXH2S.mjs +257 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/mindmap-definition-VBJCLQLM.mjs +96 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/packet-AYTQ26CC-MKII6P3Y.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/pegDiagram-7WILOQTJ.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/pie-WAS4IAKB-6B4OPMJ5.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/pieDiagram-EFA7CBSB.mjs +39 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/quadrantDiagram-WARVYA7P.mjs +7 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/radar-RG4KPBEZ-UPTR3XUL.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/railroad-74A4TZTK-MEFUPFMS.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/railroad-abnf-HS5TGJTU-R5YG2S5D.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/railroad-ebnf-LZEXJU2U-G5QEX2L6.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/railroad-peg-WCYAUIDC-H5I2ZRY2.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/railroadDiagram-5NIQVNLQ.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/requirementDiagram-SXREGOKZ.mjs +84 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/sankeyDiagram-VV74M2VP.mjs +40 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/sequenceDiagram-52ZFIFDL.mjs +162 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/sizeCapture-FGA5AGYP.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/stateDiagram-3QAKPIVI.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/stateDiagram-v2-HN2P4RDZ.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/swimlanes-QLVP42QD.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/swimlanesDiagram-JKPDBFCN.mjs +8 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/timeline-definition-GS45XAXW.mjs +120 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/treeView-Q6P3EWNA-ZRJGANNQ.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/treemap-WGGIJYW6-K64VN5AS.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/vennDiagram-QIQU2ZRJ.mjs +34 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/wardley-WFR3VGLG-D67OWCCH.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/wardleyDiagram-U6YNM66N.mjs +78 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/xychartDiagram-XJAZEDNM.mjs +7 -0
- package/neural-interface/public/vendor/mermaid/manifest.json +4 -0
- package/neural-interface/public/vendor/mermaid/mermaid-11.17.2.esm.min.mjs +14 -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 +116 -3
- package/neural-interface/server.js +4834 -2541
- 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 +5 -5
- 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
|
@@ -91,11 +91,13 @@ export function createAccountUsage({ accounts = {}, readCodex = null, fetchImpl
|
|
|
91
91
|
combined.fetchedAt = new Date(Math.max(...fresh.map(w => w.at), value.windows.length ? Date.parse(value.fetchedAt) : 0)).toISOString();
|
|
92
92
|
return combined;
|
|
93
93
|
}
|
|
94
|
-
|
|
94
|
+
// `stale`: a reading older than ttlMs still counts (a display that refreshes in the background); the
|
|
95
|
+
// account's own state must still match it, and a window past its reset is still unknown.
|
|
96
|
+
function peek(provider, id, { stale = false } = {}) {
|
|
95
97
|
const row = rowOf(provider, id);
|
|
96
98
|
if (row?.mode === 'apiKey' || row?.mode === 'api') return unknown('not_applicable', now());
|
|
97
99
|
const item = cache.get(keyOf(provider, id));
|
|
98
|
-
const value = item?.signature === signature(row) && now() - item.at < ttlMs ? summarize(item.value.windows, item.value.source, Date.parse(item.value.fetchedAt), item.value.limited && !item.value.windows.some(w => w.usedPercent >= 100)) : unknown('unknown', now());
|
|
100
|
+
const value = item?.signature === signature(row) && (stale || now() - item.at < ttlMs) ? summarize(item.value.windows, item.value.source, Date.parse(item.value.fetchedAt), item.value.limited && !item.value.windows.some(w => w.usedPercent >= 100)) : unknown('unknown', now());
|
|
99
101
|
// Do not keep a limited window alive after its reset.
|
|
100
102
|
if (value.windows.some(w => w.resetsAt && Date.parse(w.resetsAt) <= now())) return overlay(provider, id, unknown('unknown', now()));
|
|
101
103
|
return overlay(provider, id, value);
|
|
@@ -137,7 +139,7 @@ export function createAccountUsage({ accounts = {}, readCodex = null, fetchImpl
|
|
|
137
139
|
await Promise.all(Object.entries(accounts).filter(([p]) => !provider || p === provider).flatMap(([p, service]) => service.list().map(row => read(p, row.id))));
|
|
138
140
|
return list();
|
|
139
141
|
}
|
|
140
|
-
function list() { return Object.fromEntries(Object.entries(accounts).map(([p, service]) => [p, service.listForClient().map(row => ({ ...row, usage: peek(p, row.id) }))])); }
|
|
142
|
+
function list({ stale = false } = {}) { return Object.fromEntries(Object.entries(accounts).map(([p, service]) => [p, service.listForClient().map(row => ({ ...row, usage: peek(p, row.id, { stale }) }))])); }
|
|
141
143
|
function invalidate(p, id) { const key = keyOf(p, id); generations.set(key, (generations.get(key) || 0) + 1); cache.delete(key); overlays.delete(key); }
|
|
142
144
|
return { read, peek, note, refresh, list, invalidate };
|
|
143
145
|
}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
// ═══════════════════════════════════════════
|
|
2
|
+
// SynaBun — /api/system/app: Settings > App for an npm or Git install
|
|
3
|
+
// ═══════════════════════════════════════════
|
|
4
|
+
//
|
|
5
|
+
// GET /api/system/app { ok, install, desktop, updates: { auto }, startup: { … } }
|
|
6
|
+
// PUT /api/system/app/updates { auto: boolean } the automatic update check and its badge
|
|
7
|
+
// PUT /api/system/app/startup { enabled: boolean } start the server at login (lib/login-start.js)
|
|
8
|
+
// POST /api/system/app/open-folder { which: 'data' | 'logs' }
|
|
9
|
+
//
|
|
10
|
+
// Automatic updates here are the check: on (the default), the server looks for
|
|
11
|
+
// a newer version when it starts and the page shows the update badge and asks
|
|
12
|
+
// again every half hour; off, it looks only when the user asks (Check for
|
|
13
|
+
// updates). Installing always goes through the update dialog and its backup
|
|
14
|
+
// step; nothing installs unattended. The setting is DATA_HOME/data/app-settings.json.
|
|
15
|
+
//
|
|
16
|
+
// In the desktop app (`desktop: true`) the app's own settings are the
|
|
17
|
+
// window's (packaging/desktop/src/app-prefs.mjs, through the preload bridge):
|
|
18
|
+
// this answers what it is and changes nothing.
|
|
19
|
+
//
|
|
20
|
+
// These are the owner's acts on this computer (a login entry, a folder opened
|
|
21
|
+
// on its screen), so the routes take the guards of /api/cli/install
|
|
22
|
+
// (lib/http-guards.js): a loopback socket and no proxy header, a localhost
|
|
23
|
+
// Host, no invite guest; a write also its own Origin, a JSON body,
|
|
24
|
+
// X-SynaBun-UI: 1 and no agent header. (`/api/system` is admin-only in
|
|
25
|
+
// lib/request-gate.js too.) A request names a switch, never a path or a command.
|
|
26
|
+
|
|
27
|
+
import { Router } from 'express';
|
|
28
|
+
import { mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs';
|
|
29
|
+
import { dirname } from 'node:path';
|
|
30
|
+
import { guestForbidden, noStore, requireLocal, requireLocalHost, requireSameOriginJson, sendGuardError, uiOnly } from './http-guards.js';
|
|
31
|
+
import { runProgram } from './file-explorer-system.js';
|
|
32
|
+
|
|
33
|
+
export const APP_SETTINGS_DEFAULTS = Object.freeze({ autoUpdateCheck: true });
|
|
34
|
+
|
|
35
|
+
export function normalizeAppSettings(raw) {
|
|
36
|
+
const source = raw && typeof raw === 'object' && !Array.isArray(raw) ? raw : {};
|
|
37
|
+
const out = {};
|
|
38
|
+
for (const [key, value] of Object.entries(APP_SETTINGS_DEFAULTS)) out[key] = typeof source[key] === typeof value ? source[key] : value;
|
|
39
|
+
return out;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** DATA_HOME/data/app-settings.json, read once and written through (this server is its only writer). */
|
|
43
|
+
export function createAppSettingsStore({ path, fs = { mkdirSync, readFileSync, renameSync, writeFileSync } } = {}) {
|
|
44
|
+
let current = null;
|
|
45
|
+
const load = () => {
|
|
46
|
+
if (current) return current;
|
|
47
|
+
try { current = normalizeAppSettings(JSON.parse(fs.readFileSync(path, 'utf8'))); } catch { current = normalizeAppSettings(null); }
|
|
48
|
+
return current;
|
|
49
|
+
};
|
|
50
|
+
return {
|
|
51
|
+
get: () => ({ ...load() }),
|
|
52
|
+
set(patch) {
|
|
53
|
+
const next = normalizeAppSettings({ ...load(), ...patch });
|
|
54
|
+
fs.mkdirSync(dirname(path), { recursive: true });
|
|
55
|
+
const temp = `${path}.${process.pid}.tmp`;
|
|
56
|
+
fs.writeFileSync(temp, JSON.stringify(next, null, 2) + '\n');
|
|
57
|
+
fs.renameSync(temp, path);
|
|
58
|
+
current = next;
|
|
59
|
+
return { ...next };
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** The program that shows a folder in the system's file manager (no shell; the path is an argument of its own). */
|
|
65
|
+
export function openFolderCommand(platform, path, { env = process.env } = {}) {
|
|
66
|
+
if (platform === 'darwin') return { file: 'open', args: [path] };
|
|
67
|
+
// explorer.exe answers 1 even when it opened the folder.
|
|
68
|
+
if (platform === 'win32') return { file: 'explorer.exe', args: [path], anyExit: true };
|
|
69
|
+
if (!env.DISPLAY && !env.WAYLAND_DISPLAY) return null;
|
|
70
|
+
return { file: 'xdg-open', args: [path] };
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** Open a folder on this computer's screen; resolves true when the file manager took it. */
|
|
74
|
+
export async function openFolderOnScreen(path, { platform = process.platform, env = process.env, run = runProgram, mkdir = mkdirSync } = {}) {
|
|
75
|
+
const command = openFolderCommand(platform, path, { env });
|
|
76
|
+
if (!command) return false;
|
|
77
|
+
try { mkdir(path, { recursive: true }); } catch {}
|
|
78
|
+
try {
|
|
79
|
+
await run(command.file, command.args);
|
|
80
|
+
return true;
|
|
81
|
+
} catch (error) {
|
|
82
|
+
return !!command.anyExit && error?.code !== 'ENOENT';
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function localRouter({ isGuestRequest, port }) {
|
|
87
|
+
const router = Router();
|
|
88
|
+
const portOf = () => Number(typeof port === 'function' ? port() : port);
|
|
89
|
+
const built = new Map();
|
|
90
|
+
const perPort = (name, factory) => (req, res, next) => {
|
|
91
|
+
const key = `${name}:${portOf()}`;
|
|
92
|
+
let guard = built.get(key);
|
|
93
|
+
if (!guard) {
|
|
94
|
+
try { guard = factory(portOf()); } catch { return sendGuardError(res, 500, 'BAD_PORT', 'The app settings have no valid port.'); }
|
|
95
|
+
built.set(key, guard);
|
|
96
|
+
}
|
|
97
|
+
return guard(req, res, next);
|
|
98
|
+
};
|
|
99
|
+
router.use(noStore, guestForbidden(isGuestRequest), requireLocal, perPort('host', requireLocalHost));
|
|
100
|
+
return { router, mutating: [perPort('origin', requireSameOriginJson), uiOnly] };
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* @param {object} deps
|
|
105
|
+
* @param {ReturnType<typeof createAppSettingsStore>} deps.store
|
|
106
|
+
* @param {ReturnType<import('./login-start.js').createLoginStart>} deps.loginStart
|
|
107
|
+
* @param {{ data: string, logs: string }} deps.folders
|
|
108
|
+
* @param {string} deps.install 'npm' | 'git' | 'app' | 'desktop'
|
|
109
|
+
* @param {(auto: boolean) => void} [deps.onAutoUpdateChange]
|
|
110
|
+
* @param {(path: string) => Promise<boolean>} [deps.openFolder]
|
|
111
|
+
*/
|
|
112
|
+
export function createAppControlsApi({
|
|
113
|
+
store, loginStart, folders, install = 'npm', onAutoUpdateChange = () => {}, openFolder = (path) => openFolderOnScreen(path),
|
|
114
|
+
isGuestRequest = () => false, port = 3344, log = () => {},
|
|
115
|
+
} = {}) {
|
|
116
|
+
if (!store || !loginStart || !folders) throw new Error('createAppControlsApi needs the settings store, the login start and the folders');
|
|
117
|
+
const { router, mutating } = localRouter({ isGuestRequest, port });
|
|
118
|
+
const desktop = install === 'desktop';
|
|
119
|
+
|
|
120
|
+
const body = () => {
|
|
121
|
+
let startup;
|
|
122
|
+
try { startup = loginStart.status(); } catch (error) { startup = { supported: false, reason: 'unsupported', enabled: false, state: 'off', owner: null, error: String(error?.message || error) }; }
|
|
123
|
+
return { ok: true, install, desktop, updates: { auto: store.get().autoUpdateCheck !== false }, startup };
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
router.get('/', (req, res) => { res.json(body()); });
|
|
127
|
+
|
|
128
|
+
router.put('/updates', ...mutating, (req, res) => {
|
|
129
|
+
const auto = req.body?.auto;
|
|
130
|
+
if (typeof auto !== 'boolean') return res.status(400).json({ ok: false, code: 'BAD_REQUEST', error: 'Send { auto: true | false }.' });
|
|
131
|
+
if (desktop) return res.status(409).json({ ok: false, code: 'DESKTOP_MANAGED', error: 'The SynaBun app keeps this setting itself.' });
|
|
132
|
+
try { store.set({ autoUpdateCheck: auto }); } catch (error) {
|
|
133
|
+
return res.status(500).json({ ok: false, code: 'SAVE_FAILED', error: String(error?.message || error) });
|
|
134
|
+
}
|
|
135
|
+
try { onAutoUpdateChange(auto); } catch {}
|
|
136
|
+
res.json(body());
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
router.put('/startup', ...mutating, async (req, res) => {
|
|
140
|
+
const enabled = req.body?.enabled;
|
|
141
|
+
if (typeof enabled !== 'boolean') return res.status(400).json({ ok: false, code: 'BAD_REQUEST', error: 'Send { enabled: true | false }.' });
|
|
142
|
+
try {
|
|
143
|
+
await loginStart.set(enabled);
|
|
144
|
+
} catch (error) {
|
|
145
|
+
const code = String(error?.code || 'refused');
|
|
146
|
+
log(`[app] start at login could not be turned ${enabled ? 'on' : 'off'}: ${error?.message || error}`);
|
|
147
|
+
return res.status(409).json({ ...body(), ok: false, code, error: String(error?.message || error).slice(0, 300) });
|
|
148
|
+
}
|
|
149
|
+
res.json(body());
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
router.post('/open-folder', ...mutating, async (req, res) => {
|
|
153
|
+
const which = req.body?.which;
|
|
154
|
+
if (which !== 'data' && which !== 'logs') return res.status(400).json({ ok: false, code: 'BAD_REQUEST', error: "Send { which: 'data' | 'logs' }." });
|
|
155
|
+
const opened = await openFolder(folders[which]).catch(() => false);
|
|
156
|
+
if (!opened) return res.status(422).json({ ok: false, code: 'NO_FILE_MANAGER', error: 'No file manager opened the folder.' });
|
|
157
|
+
res.json({ ok: true });
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
return router;
|
|
161
|
+
}
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
// composer attachments, Claude/Codex account management, and the sidepanel tab registry.
|
|
8
8
|
// Mounted from server.js with `app.use('/api/assistant', createAssistantApi(deps))`.
|
|
9
9
|
|
|
10
|
+
import { dispatchInput } from './assistant-tools.js';
|
|
10
11
|
import { Router } from 'express';
|
|
11
12
|
import { DispatchError } from './assistant-dispatch.js';
|
|
12
13
|
import { openServable } from './assistant-media.js';
|
|
@@ -17,6 +18,7 @@ import { tooLargeMessage } from './assistant-attachments.js';
|
|
|
17
18
|
import { getSessionPolicy, requiresHumanApproval } from './remote-policy.js';
|
|
18
19
|
import { clampPlanDispatch, PLAN_DISPATCH_NOTE, runCanChangeCode } from './assistant-plan-permissions.js';
|
|
19
20
|
import { noStore, requireJson, requireLocal, requireLocalHost, sendGuardError } from './http-guards.js';
|
|
21
|
+
import { setUntrustedFileHeaders } from './untrusted-file-headers.js';
|
|
20
22
|
|
|
21
23
|
/** The header whatsapp_send_file's caller proves it is the WhatsApp conversation's own brain with (assistant-runtime.js BRAIN_CREDENTIAL_RE). */
|
|
22
24
|
export const BRAIN_CREDENTIAL_HEADER = 'x-synabun-brain-token';
|
|
@@ -41,7 +43,7 @@ const NO_CATALOG = Object.freeze({});
|
|
|
41
43
|
function sendError(res, error, fallbackStatus = 500) {
|
|
42
44
|
if (error instanceof DispatchError || (error && error.code && error.status)) {
|
|
43
45
|
const status = Number(error.status) || fallbackStatus;
|
|
44
|
-
const body = typeof error.toJSON === 'function' ? error.toJSON() : { code: error.code, message: error.message };
|
|
46
|
+
const body = typeof error.toJSON === 'function' ? error.toJSON() : { code: error.code, message: error.message, ...(error.problems ? { problems: error.problems } : {}) };
|
|
45
47
|
return res.status(status).json({ ok: false, error: body.message, ...body });
|
|
46
48
|
}
|
|
47
49
|
return res.status(fallbackStatus).json({ ok: false, error: error?.message || String(error), code: error?.code || 'INTERNAL' });
|
|
@@ -95,7 +97,7 @@ export function slimRunView(run) {
|
|
|
95
97
|
* @param {object} [deps.runtime] createAssistantRuntime() (sessions; optional until wired)
|
|
96
98
|
* @param {object} [deps.claudeAccounts] createClaudeAccounts()
|
|
97
99
|
* @param {object} [deps.codexAccounts] createCodexAccounts() (lib/codex-accounts.js)
|
|
98
|
-
* @param {Function} [deps.buildCatalog] async () => catalog object (models/accounts/projects/
|
|
100
|
+
* @param {Function} [deps.buildCatalog] async () => catalog object (models/accounts/projects/tools)
|
|
99
101
|
* @param {Function} [deps.createLoginTerminal] async ({ env, cwd, profile, accountId }) => { terminalSessionId, profile }
|
|
100
102
|
* @param {Function} [deps.claudeSignIn] async (accountId) => { sessionId, status, error } — Claude Code's own
|
|
101
103
|
* `auth login` in a SynaBun terminal under the account's config directory (lib/provider-panel-terminal-auth.js)
|
|
@@ -152,6 +154,11 @@ export function createAssistantApi({
|
|
|
152
154
|
port = 3344,
|
|
153
155
|
// The Admin sandbox setting (lib/agent-sandbox-setting.js): one global value for every agent SynaBun starts.
|
|
154
156
|
adminSandbox = null,
|
|
157
|
+
// Protect workers (lib/worker-guard-setting.js): what capability read-only / workspace means for every worker.
|
|
158
|
+
workerGuard = null,
|
|
159
|
+
// The page secret (lib/page-session.js): a request without an agent pin is the owner's page only when it carries
|
|
160
|
+
// this boot's cookie; a local process that merely sends no headers is nobody (never 'ui').
|
|
161
|
+
pageSession = null,
|
|
155
162
|
} = {}) {
|
|
156
163
|
if (!dispatcher) throw new Error('createAssistantApi requires a dispatcher');
|
|
157
164
|
const router = Router();
|
|
@@ -163,20 +170,31 @@ export function createAssistantApi({
|
|
|
163
170
|
next();
|
|
164
171
|
});
|
|
165
172
|
|
|
166
|
-
// Resolve who is calling: the UI (no pin),
|
|
167
|
-
//
|
|
173
|
+
// Resolve who is calling: the UI (the page secret cookie, no pin), a dispatched worker (run id pin →
|
|
174
|
+
// forbidden for orchestration), or nobody known. A brain is NOT decided here: a pin only records which
|
|
175
|
+
// session a request *claims* to be (for attribution), never that the request is that session's brain.
|
|
176
|
+
// Brain authority is the per-launch credential alone (brainCaller) — the final pre-restart review
|
|
177
|
+
// (run f283e53b) showed a forged `X-Synabun-Terminal: assistant-*`, and equally a real but non-secret
|
|
178
|
+
// session id (a worker's environment and its task text both carry one), would otherwise pass as the brain.
|
|
168
179
|
function callerContext(req) {
|
|
169
180
|
const pin = String(req.get('x-synabun-terminal') || req.get('x-synabun-assistant') || '').trim();
|
|
170
181
|
const bodySession = req.body?.assistantSessionId || req.body?.assistant_session_id || req.query?.assistantSessionId || null;
|
|
171
|
-
if (!pin)
|
|
182
|
+
if (!pin) {
|
|
183
|
+
// The page: this boot's page secret cookie (the browser sends it by itself). Without a page session wired
|
|
184
|
+
// (a test, an older host) every pinless request is the page, as before.
|
|
185
|
+
if (pageSession && typeof pageSession.verify === 'function' && !pageSession.verify(req)) return { kind: 'unknown', assistantSessionId: bodySession ? String(bodySession) : null, pin: '', pageless: true };
|
|
186
|
+
return { kind: 'ui', assistantSessionId: bodySession ? String(bodySession) : null };
|
|
187
|
+
}
|
|
172
188
|
if (dispatcher.get(pin)) return { kind: 'worker', forbidden: true, pin };
|
|
173
|
-
//
|
|
174
|
-
// OpenCode brain pins assistant-oc-<24
|
|
189
|
+
// The session a request claims, for attribution once a credential has proven it a brain: a Claude brain's
|
|
190
|
+
// pin resolves to its session; the OpenCode brain pins assistant-oc-<24> (never taken as an id) and names
|
|
191
|
+
// the session in the body. The claim grants nothing on its own.
|
|
175
192
|
const resolved = runtime?.resolveTerminal?.(pin) || null;
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
193
|
+
const claimed = resolved
|
|
194
|
+
|| (/^assistant-oc-/.test(pin) ? (bodySession ? String(bodySession) : null)
|
|
195
|
+
: /^assistant-/.test(pin) ? pin
|
|
196
|
+
: (bodySession ? String(bodySession) : null));
|
|
197
|
+
return { kind: 'unknown', assistantSessionId: claimed, pin };
|
|
180
198
|
}
|
|
181
199
|
/**
|
|
182
200
|
* The plan mode of the brain making this call: 'read-only' (a remote session
|
|
@@ -211,20 +229,56 @@ export function createAssistantApi({
|
|
|
211
229
|
function orchestrationGuard(req, res, next) {
|
|
212
230
|
const caller = callerContext(req);
|
|
213
231
|
if (caller.forbidden) return res.status(403).json({ ok: false, code: 'AGENTS_NOT_PERMITTED', error: 'Dispatched workers cannot orchestrate other agents.' });
|
|
214
|
-
|
|
215
|
-
next();
|
|
232
|
+
// The user's own page (this boot's page secret cookie): the only caller that orchestrates without being a brain.
|
|
233
|
+
if (caller.kind === 'ui') { req.assistantCaller = caller; return next(); }
|
|
234
|
+
// The only other caller allowed is an Assistant brain, and only its per-launch credential proves it (brainCaller):
|
|
235
|
+
// never a pin, never a session id, which a worker's environment and its task text both carry. This is the forged-
|
|
236
|
+
// and known-pin bypass the final pre-restart review found (run f283e53b, assistant-api.js:189): an
|
|
237
|
+
// `X-Synabun-Terminal: assistant-*` header, or a real live session id, used to pass here as the brain.
|
|
238
|
+
const brain = brainCaller(req);
|
|
239
|
+
if (brain) { req.assistantCaller = brain; return next(); }
|
|
240
|
+
return res.status(403).json({ ok: false, code: 'UI_ONLY', error: 'Orchestration is the user\'s (from SynaBun\'s own page) and the Assistant\'s brain\'s: this request is neither (no page secret, no brain launch credential a live session knows).' });
|
|
216
241
|
}
|
|
217
242
|
/**
|
|
218
|
-
* The caller when it is an assistant brain, else null.
|
|
219
|
-
*
|
|
220
|
-
*
|
|
221
|
-
*
|
|
243
|
+
* The caller when it is an assistant brain, else null. The one proof is the per-launch credential
|
|
244
|
+
* (X-Synabun-Brain-Token, SYNABUN_BRAIN_TOKEN in the brain's own environment only, minted per brain launch and
|
|
245
|
+
* resolved by runtime.sessionForBrainCredential over the live brains): a pin or a session id names nobody here,
|
|
246
|
+
* because any local process can send a header and a session id is not secret (a worker carries its own, and ids
|
|
247
|
+
* appear in task text). The credential's session is authoritative, whatever pin or body the request carries. The
|
|
248
|
+
* UI, workers and other sessions never count.
|
|
222
249
|
*/
|
|
223
250
|
function brainCaller(req) {
|
|
251
|
+
if (req.assistantCaller?.credentialed) return req.assistantCaller;
|
|
252
|
+
if (String(req.get('x-synabun-role') || '').trim().toLowerCase() !== 'assistant') return null;
|
|
253
|
+
let session = null;
|
|
254
|
+
try { session = runtime?.sessionForBrainCredential?.(req.get('x-synabun-brain-token')) || null; } catch { session = null; }
|
|
255
|
+
if (!session) return null;
|
|
224
256
|
const caller = req.assistantCaller || callerContext(req);
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
257
|
+
return { ...caller, kind: 'assistant', assistantSessionId: String(session), credentialed: true };
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Who may READ a run (GET /runs/:id, /result, /transcript): the owner's page (ui), a credential-verified
|
|
261
|
+
* Assistant brain (its session's runs, as today), or the worker of that very run — a worker's pin is its own
|
|
262
|
+
* run id, so it reads only itself, never another run. Everyone else (a pinless local process with no page
|
|
263
|
+
* secret, a worker naming another run) is refused. Listing and deletion are owner-or-brain only (never a worker):
|
|
264
|
+
* the list is not "its own run", and a finished run is cleared by the owner or the brain that owns its session.
|
|
265
|
+
*/
|
|
266
|
+
function runReadAllowed(req, runId) {
|
|
267
|
+
const caller = callerContext(req);
|
|
268
|
+
if (caller.kind === 'ui') return true;
|
|
269
|
+
const brain = brainCaller(req);
|
|
270
|
+
if (brain) {
|
|
271
|
+
// A brain reads only its OWN session's runs (like DELETE): another session's run is not readable through the
|
|
272
|
+
// credential. A run with no session, or a sessionless brain, falls through as before (nothing to scope to).
|
|
273
|
+
const runSession = dispatcher.get(runId)?.assistantSessionId || null;
|
|
274
|
+
if (runSession && brain.assistantSessionId && String(runSession) !== String(brain.assistantSessionId)) return false;
|
|
275
|
+
return true;
|
|
276
|
+
}
|
|
277
|
+
if (caller.kind === 'worker' && caller.pin && String(caller.pin) === String(runId)) return true;
|
|
278
|
+
return false;
|
|
279
|
+
}
|
|
280
|
+
function refuseRunRead(res) {
|
|
281
|
+
return res.status(403).json({ ok: false, code: 'RUN_FORBIDDEN', error: 'This run is readable by the owner (from SynaBun\'s own page), its own worker and the Assistant brain of its session only.' });
|
|
228
282
|
}
|
|
229
283
|
/** A remote session whose workers only a person may answer (strict worker approvals below autonomous). */
|
|
230
284
|
function humanApprovalRequired(assistantSessionId) {
|
|
@@ -301,7 +355,10 @@ export function createAssistantApi({
|
|
|
301
355
|
// ── catalog ────────────────────────────────────────────────────────────────
|
|
302
356
|
router.get('/catalog', async (req, res) => {
|
|
303
357
|
try {
|
|
304
|
-
|
|
358
|
+
// Quotas are shown as last read and read again in the background (the probe can take seconds; the
|
|
359
|
+
// dispatcher and the router read them fresh before they choose an account).
|
|
360
|
+
accountUsage?.refresh()?.catch?.(() => {});
|
|
361
|
+
const usage = () => accountUsage?.list({ stale: true });
|
|
305
362
|
// refresh=1 rebuilds from the providers' endpoints; deep=1 also makes them ask the CLI / app-server again.
|
|
306
363
|
const deep = req.query.deep === '1';
|
|
307
364
|
const force = req.query.refresh === '1' || deep;
|
|
@@ -320,8 +377,8 @@ export function createAssistantApi({
|
|
|
320
377
|
// names none.
|
|
321
378
|
const accounts = {
|
|
322
379
|
...(brief.accounts || {}),
|
|
323
|
-
...(claudeAccounts ? { 'claude-code':
|
|
324
|
-
...(codexAccounts ? { codex:
|
|
380
|
+
...(claudeAccounts ? { 'claude-code': usage()?.['claude-code'] || claudeAccounts.listForClient() } : {}),
|
|
381
|
+
...(codexAccounts ? { codex: usage()?.codex || codexAccounts.listForClient() } : {}),
|
|
325
382
|
};
|
|
326
383
|
return res.json({ ok: true, generatedAt: new Date(now()).toISOString(), ...brief, accounts, claudeWorkerAccount: claudeWorkerAccountId(), codexWorkerAccount: codexWorkerAccountId(), limits: dispatcher.limits, runs: dispatcher.list({ activeOnly: true }), totals: dispatcher.totals() });
|
|
327
384
|
}
|
|
@@ -329,7 +386,7 @@ export function createAssistantApi({
|
|
|
329
386
|
// within seconds), so it is asked every time: this answer is reused only while it hands back the
|
|
330
387
|
// build the answer was made from (a rebuild or invalidate() gives another one).
|
|
331
388
|
const base = typeof buildCatalog === 'function' ? await buildCatalog({ force, deep }) : NO_CATALOG;
|
|
332
|
-
if (!force && catalogCache && catalogCache.base === base && now() - catalogCache.at < 30_000) return res.json(accountUsage ? { ...catalogCache.value, accounts: { ...catalogCache.value.accounts, ...
|
|
389
|
+
if (!force && catalogCache && catalogCache.base === base && now() - catalogCache.at < 30_000) return res.json(accountUsage ? { ...catalogCache.value, accounts: { ...catalogCache.value.accounts, ...usage() } } : catalogCache.value);
|
|
333
390
|
// Hidden rows stay server-side (view=manage lists them); the lists themselves ship.
|
|
334
391
|
const { hiddenRows: _hiddenRows, ...visible } = base || {};
|
|
335
392
|
const value = {
|
|
@@ -338,8 +395,8 @@ export function createAssistantApi({
|
|
|
338
395
|
...visible,
|
|
339
396
|
accounts: {
|
|
340
397
|
...(base.accounts || {}),
|
|
341
|
-
'claude-code':
|
|
342
|
-
codex:
|
|
398
|
+
'claude-code': usage()?.['claude-code'] || (claudeAccounts ? claudeAccounts.listForClient() : (base.accounts?.['claude-code'] || [])),
|
|
399
|
+
codex: usage()?.codex || (codexAccounts ? codexAccounts.listForClient() : (base.accounts?.codex || [])),
|
|
343
400
|
},
|
|
344
401
|
claudeWorkerAccount: claudeWorkerAccountId(),
|
|
345
402
|
codexWorkerAccount: codexWorkerAccountId(),
|
|
@@ -359,9 +416,8 @@ export function createAssistantApi({
|
|
|
359
416
|
try {
|
|
360
417
|
const body = req.body || {};
|
|
361
418
|
const spec = {
|
|
362
|
-
...body,
|
|
419
|
+
...dispatchInput(body),
|
|
363
420
|
accountId: body.accountId || body.account_id || body.codexAccountId || body.claudeAccountId || null,
|
|
364
|
-
mcpProfile: body.mcpProfile || body.mcp_profile,
|
|
365
421
|
permissionPolicy: body.permissionPolicy || body.permission_policy,
|
|
366
422
|
maxMinutes: body.maxMinutes ?? body.max_minutes,
|
|
367
423
|
budgetUsd: body.budgetUsd ?? body.budget_usd,
|
|
@@ -720,18 +776,25 @@ export function createAssistantApi({
|
|
|
720
776
|
});
|
|
721
777
|
|
|
722
778
|
router.get('/runs', (req, res) => {
|
|
779
|
+
// Listing is owner-or-brain only: a worker reads its own run by id, never the roster of every run.
|
|
780
|
+
const caller = callerContext(req);
|
|
781
|
+
const brain = brainCaller(req);
|
|
782
|
+
if (caller.kind !== 'ui' && !brain) return refuseRunRead(res);
|
|
723
783
|
try {
|
|
724
784
|
const active = req.query.active === '1' || req.query.activeOnly === '1';
|
|
785
|
+
// A brain sees only its OWN session's runs (its session id forced over whatever the query asks); the owner's
|
|
786
|
+
// page may list any session.
|
|
787
|
+
const scopedSession = (brain && caller.kind !== 'ui') ? (brain.assistantSessionId || null) : (req.query.assistantSessionId || null);
|
|
725
788
|
res.json({
|
|
726
789
|
ok: true,
|
|
727
790
|
runs: dispatcher.list({
|
|
728
791
|
activeOnly: active,
|
|
729
|
-
assistantSessionId:
|
|
792
|
+
assistantSessionId: scopedSession,
|
|
730
793
|
workflowId: req.query.workflowId || null,
|
|
731
794
|
status: req.query.status || null,
|
|
732
795
|
limit: clampInt(req.query.limit, 1, 500, 100),
|
|
733
796
|
}),
|
|
734
|
-
totals: dispatcher.totals({ assistantSessionId:
|
|
797
|
+
totals: dispatcher.totals({ assistantSessionId: scopedSession, workflowId: req.query.workflowId || null }),
|
|
735
798
|
});
|
|
736
799
|
} catch (error) { sendError(res, error); }
|
|
737
800
|
});
|
|
@@ -764,12 +827,19 @@ export function createAssistantApi({
|
|
|
764
827
|
if (!assistantSessionId && !workflowId && req.assistantCaller.kind !== 'ui') {
|
|
765
828
|
return res.status(400).json({ ok: false, code: 'SCOPE_REQUIRED', error: 'Pass assistant_session_id (your ASSISTANT_SESSION_ID) or workflow_id to stop runs.' });
|
|
766
829
|
}
|
|
767
|
-
const
|
|
830
|
+
const reason = body.reason || 'kill_all';
|
|
831
|
+
const result = await dispatcher.killAll({ assistantSessionId, workflowId, reason });
|
|
832
|
+
// Who stopped every run, when: the records only say `kill_all` (2026-10-24 had to be traced by elimination).
|
|
833
|
+
const caller = req.assistantCaller.kind === 'ui' ? 'the page' : `the brain of ${req.assistantCaller.assistantSessionId || 'an unknown session'}`;
|
|
834
|
+
const scope = [assistantSessionId ? `session ${assistantSessionId}` : null, workflowId ? `workflow ${workflowId}` : null].filter(Boolean).join(', ') || 'every session';
|
|
835
|
+
const stopped = Array.isArray(result?.stopped) ? result.stopped : [];
|
|
836
|
+
log('kill-all', `${new Date(now()).toISOString()} ${caller} stopped ${stopped.length} run(s) of ${scope} (${reason})${stopped.length ? `: ${stopped.join(', ')}` : ''}`);
|
|
768
837
|
res.json(result);
|
|
769
838
|
} catch (error) { sendError(res, error); }
|
|
770
839
|
});
|
|
771
840
|
|
|
772
841
|
router.get('/runs/:runId', (req, res) => {
|
|
842
|
+
if (!runReadAllowed(req, req.params.runId)) return refuseRunRead(res);
|
|
773
843
|
const run = dispatcher.get(req.params.runId);
|
|
774
844
|
if (!run) return res.status(404).json({ ok: false, code: 'RUN_NOT_FOUND', error: `Unknown run ${req.params.runId}` });
|
|
775
845
|
const brain = brainCaller(req);
|
|
@@ -777,6 +847,7 @@ export function createAssistantApi({
|
|
|
777
847
|
res.json({ ok: true, run: brain ? slimRunView(run) : run });
|
|
778
848
|
});
|
|
779
849
|
router.get('/runs/:runId/result', (req, res) => {
|
|
850
|
+
if (!runReadAllowed(req, req.params.runId)) return refuseRunRead(res);
|
|
780
851
|
try {
|
|
781
852
|
const out = dispatcher.transcript(req.params.runId, { format: 'result' });
|
|
782
853
|
if (out?.result) {
|
|
@@ -787,6 +858,7 @@ export function createAssistantApi({
|
|
|
787
858
|
} catch (error) { sendError(res, error); }
|
|
788
859
|
});
|
|
789
860
|
router.get('/runs/:runId/transcript', (req, res) => {
|
|
861
|
+
if (!runReadAllowed(req, req.params.runId)) return refuseRunRead(res);
|
|
790
862
|
try {
|
|
791
863
|
const format = req.query.format || 'tail';
|
|
792
864
|
const out = dispatcher.transcript(req.params.runId, {
|
|
@@ -807,6 +879,7 @@ export function createAssistantApi({
|
|
|
807
879
|
// path from the request; owner-only like everything here. sendFile answers
|
|
808
880
|
// Range requests, so a video seeks.
|
|
809
881
|
router.get('/runs/:runId/media/:n', async (req, res) => {
|
|
882
|
+
if (!runReadAllowed(req, req.params.runId)) return refuseRunRead(res);
|
|
810
883
|
const notFound = () => res.status(404).json({ ok: false, code: 'MEDIA_NOT_FOUND', error: `No media ${req.params.n} for run ${req.params.runId}` });
|
|
811
884
|
if (!/^\d{1,4}$/.test(String(req.params.n))) return notFound();
|
|
812
885
|
let file = null;
|
|
@@ -836,6 +909,8 @@ export function createAssistantApi({
|
|
|
836
909
|
'Accept-Ranges': 'bytes', 'X-Content-Type-Options': 'nosniff', 'Cache-Control': 'private, max-age=3600',
|
|
837
910
|
});
|
|
838
911
|
if (range) res.set('Content-Range', `bytes ${start}-${end}/${size}`);
|
|
912
|
+
// A run's media is what a worker made: opened by its address it runs nothing, and an SVG is a download.
|
|
913
|
+
setUntrustedFileHeaders(res, file.path, file.mime);
|
|
839
914
|
if (req.method === 'HEAD' || !size) { await handle.close().catch(() => {}); return res.end(); }
|
|
840
915
|
const stream = handle.createReadStream({ start, end });
|
|
841
916
|
stream.on('error', () => res.destroy());
|
|
@@ -894,10 +969,23 @@ export function createAssistantApi({
|
|
|
894
969
|
router.post('/runs/:runId/stop', orchestrationGuard, async (req, res) => {
|
|
895
970
|
try { res.json(await dispatcher.stop(req.params.runId, req.body?.reason || (req.assistantCaller.kind === 'ui' ? 'user' : 'assistant'))); } catch (error) { sendError(res, error); }
|
|
896
971
|
});
|
|
897
|
-
// Finished runs are cleared from the agents tray by the
|
|
972
|
+
// Finished runs are cleared from the agents tray by the owner (the page) or the Assistant brain of the run's
|
|
973
|
+
// own session; never by a worker (even its own run). A brain's delete is scoped to its session's runs.
|
|
898
974
|
router.delete('/runs/:runId', async (req, res) => {
|
|
899
|
-
|
|
900
|
-
|
|
975
|
+
const caller = callerContext(req);
|
|
976
|
+
const brain = brainCaller(req);
|
|
977
|
+
if (caller.kind !== 'ui' && !brain) return res.status(403).json({ ok: false, code: 'UI_ONLY', error: 'Finished runs are removed by the owner (from SynaBun\'s own page) or the Assistant brain of the run\'s session.' });
|
|
978
|
+
if (brain && caller.kind !== 'ui') {
|
|
979
|
+
// A brain removes only the runs of its own session: another session's run is left untouched.
|
|
980
|
+
const runSession = dispatcher.get(req.params.runId)?.assistantSessionId || null;
|
|
981
|
+
if (runSession && brain.assistantSessionId && String(runSession) !== String(brain.assistantSessionId)) {
|
|
982
|
+
return res.status(403).json({ ok: false, code: 'RUN_NOT_IN_SESSION', error: `Run ${req.params.runId} belongs to another assistant session` });
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
const assistantSessionId = (brain && caller.kind !== 'ui')
|
|
986
|
+
? (brain.assistantSessionId || null)
|
|
987
|
+
: (req.query.assistantSessionId || req.body?.assistantSessionId || null);
|
|
988
|
+
try { res.json(await dispatcher.remove(req.params.runId, { assistantSessionId })); } catch (error) { sendError(res, error); }
|
|
901
989
|
});
|
|
902
990
|
router.post('/runs/clear-finished', async (req, res) => {
|
|
903
991
|
if (callerContext(req).kind !== 'ui') return res.status(403).json({ ok: false, code: 'UI_ONLY', error: 'Finished runs are removed from the assistant panel only.' });
|
|
@@ -996,9 +1084,17 @@ export function createAssistantApi({
|
|
|
996
1084
|
if (!requireRuntime(res)) return;
|
|
997
1085
|
try { res.json({ ok: true, session: await runtime.closeSession(req.params.id) }); } catch (error) { sendError(res, error); }
|
|
998
1086
|
});
|
|
1087
|
+
// Remove (the Sessions menu): the record, its transcript and its usage journal go for good, after its
|
|
1088
|
+
// running turn and the workers it dispatched are stopped. Memories made from it stay.
|
|
999
1089
|
router.delete('/sessions/:id', async (req, res) => {
|
|
1000
1090
|
if (!requireRuntime(res)) return;
|
|
1001
|
-
try {
|
|
1091
|
+
try {
|
|
1092
|
+
if (runtime.removeSession) {
|
|
1093
|
+
const { removed, stoppedRuns } = await runtime.removeSession(req.params.id);
|
|
1094
|
+
return res.json({ ok: true, removed, stoppedRuns });
|
|
1095
|
+
}
|
|
1096
|
+
res.json({ ok: true, removed: await runtime.destroySession(req.params.id) });
|
|
1097
|
+
} catch (error) { sendError(res, error); }
|
|
1002
1098
|
});
|
|
1003
1099
|
|
|
1004
1100
|
// ── attachments ────────────────────────────────────────────────────────────
|
|
@@ -1249,6 +1345,23 @@ export function createAssistantApi({
|
|
|
1249
1345
|
try { res.json({ ok: true, ...adminSandbox.set(value) }); } catch (error) { sendError(res, error); }
|
|
1250
1346
|
});
|
|
1251
1347
|
|
|
1348
|
+
// ── Protect workers (lib/worker-guard-setting.js) ──────────────────────────
|
|
1349
|
+
// What capability read-only / workspace means for every worker the dispatcher starts
|
|
1350
|
+
// (lib/worker-confinement.js): enforce (default), warn, off. The user's setting: an agent cannot change it.
|
|
1351
|
+
router.get('/worker-guard', (req, res) => {
|
|
1352
|
+
if (!workerGuard) return res.status(503).json({ ok: false, code: 'WORKER_GUARD_UNAVAILABLE', error: 'The Protect workers setting is not available on this server' });
|
|
1353
|
+
res.json({ ok: true, ...workerGuard.view() });
|
|
1354
|
+
});
|
|
1355
|
+
router.put('/worker-guard', requireJson, (req, res) => {
|
|
1356
|
+
if (!workerGuard) return res.status(503).json({ ok: false, code: 'WORKER_GUARD_UNAVAILABLE', error: 'The Protect workers setting is not available on this server' });
|
|
1357
|
+
if (callerContext(req).kind !== 'ui' || req.get('x-synabun-desktop-grant') || req.get('x-synabun-role')) {
|
|
1358
|
+
return res.status(403).json({ ok: false, code: 'UI_ONLY', error: 'Only the user can change Protect workers.' });
|
|
1359
|
+
}
|
|
1360
|
+
const value = req.body?.mode;
|
|
1361
|
+
if (typeof value !== 'string' || !workerGuard.view().modes.includes(value)) return res.status(400).json({ ok: false, code: 'INVALID_VALUE', error: `mode must be one of ${workerGuard.view().modes.join(', ')}.` });
|
|
1362
|
+
try { res.json({ ok: true, ...workerGuard.set(value) }); } catch (error) { sendError(res, error); }
|
|
1363
|
+
});
|
|
1364
|
+
|
|
1252
1365
|
// ── sidepanel tab registry (UI heartbeat) ──────────────────────────────────
|
|
1253
1366
|
function listTabs() {
|
|
1254
1367
|
const cutoff = now() - tabTtlMs;
|
|
@@ -123,10 +123,11 @@ export function createClaudeBrain({ session, sink, deps = {}, persona = '', hook
|
|
|
123
123
|
'X-Synabun-Role': 'assistant', 'X-Synabun-Terminal': session.id, 'X-Synabun-Memory-Session': session.id,
|
|
124
124
|
...(deps.desktopGrant ? { 'X-Synabun-Desktop-Grant': deps.desktopGrant } : {}),
|
|
125
125
|
...mcpHeaders,
|
|
126
|
-
//
|
|
126
|
+
// This brain launch's credential (assistant-runtime.js mintBrainCredential). The header names the variable and
|
|
127
127
|
// the CLI expands it from its own environment (below): the MCP config is on its command line, which every
|
|
128
128
|
// account of the computer can read, an environment only this user's processes. The in-process MCP server
|
|
129
|
-
// keeps the value for the request it arrived with, and sends it
|
|
129
|
+
// keeps the value for the request it arrived with, and sends it only to the routes that ask who the brain is
|
|
130
|
+
// (whatsapp_send_file, the Skills Service). Last, so nothing replaces it.
|
|
130
131
|
...(deps.brainCredential ? { 'X-Synabun-Brain-Token': '${SYNABUN_BRAIN_TOKEN}' } : {}),
|
|
131
132
|
},
|
|
132
133
|
// A remote (WhatsApp) session never pre-approves computer use: its PreToolUse hook refuses, asks or allows each call.
|
|
@@ -143,7 +144,7 @@ export function createClaudeBrain({ session, sink, deps = {}, persona = '', hook
|
|
|
143
144
|
...(typeof deps.claudeAccountEnv === 'function' ? deps.claudeAccountEnv(brain.accountId) : {}),
|
|
144
145
|
SYNABUN_ASSISTANT_SESSION: String(session.id),
|
|
145
146
|
...(deps.userContextThreads === true ? { SYNABUN_ASSISTANT_THREADS: '1' } : {}),
|
|
146
|
-
// The value of the X-Synabun-Brain-Token header above
|
|
147
|
+
// The value of the X-Synabun-Brain-Token header above.
|
|
147
148
|
...(deps.brainCredential ? { SYNABUN_BRAIN_TOKEN: deps.brainCredential } : {}),
|
|
148
149
|
},
|
|
149
150
|
maxBudgetUsd: Number(deps.maxBudgetUsd) > 0 ? Number(deps.maxBudgetUsd) : undefined,
|
|
@@ -6,7 +6,9 @@
|
|
|
6
6
|
// PreToolUse payload from stdin and asks lib/browser-tool-policy.js here, with
|
|
7
7
|
// no server round trip; a refusal becomes permissionDecision "deny" with the
|
|
8
8
|
// reason. Script paths resolve against the payload's cwd, else
|
|
9
|
-
// SYNABUN_BROWSER_POLICY_CWD (the run's project)
|
|
9
|
+
// SYNABUN_BROWSER_POLICY_CWD (the run's project); SYNABUN_BROWSER_POLICY_ROOTS
|
|
10
|
+
// (a JSON list, written as the run starts) names the registered code projects
|
|
11
|
+
// its test runners may also run in. An unreadable payload allows
|
|
10
12
|
// the call: the policy is a speed bump, not a sandbox. A policy module that
|
|
11
13
|
// cannot load fails closed (logged on stderr): shell commands, web search and
|
|
12
14
|
// every MCP tool but SynaBun's are denied with that reason.
|
|
@@ -25,6 +27,14 @@ function unloadedDenial(tool) {
|
|
|
25
27
|
return `SynaBun browser policy: ${tool} was refused — SynaBun's browser policy could not load (${loadError?.message || 'browserToolDenial is missing'}), so no command, web search or other server's tool can be checked for a browser launch. SynaBun's own tools still work. Stop and report this`;
|
|
26
28
|
}
|
|
27
29
|
|
|
30
|
+
/** The registered code projects from the env (a JSON list of paths); anything unreadable is none. */
|
|
31
|
+
function policyRoots() {
|
|
32
|
+
try {
|
|
33
|
+
const list = JSON.parse(process.env.SYNABUN_BROWSER_POLICY_ROOTS || '[]');
|
|
34
|
+
return Array.isArray(list) ? list.filter((path) => typeof path === 'string') : [];
|
|
35
|
+
} catch { return []; }
|
|
36
|
+
}
|
|
37
|
+
|
|
28
38
|
let raw = '';
|
|
29
39
|
try { for await (const chunk of process.stdin) raw += chunk; } catch {}
|
|
30
40
|
let payload = {};
|
|
@@ -35,7 +45,7 @@ try {
|
|
|
35
45
|
const input = payload.tool_input && typeof payload.tool_input === 'object' ? payload.tool_input : {};
|
|
36
46
|
const cwd = (typeof payload.cwd === 'string' && payload.cwd) || process.env.SYNABUN_BROWSER_POLICY_CWD || process.cwd();
|
|
37
47
|
if (typeof browserToolDenial !== 'function') process.stderr.write(`[SynaBun] browser policy could not load (${loadError?.message || 'browserToolDenial is missing'}); denying shell, web search and other servers' tools\n`);
|
|
38
|
-
const reason = !tool ? null : typeof browserToolDenial === 'function' ? browserToolDenial(tool, input, { host: 'codex', cwd }) : unloadedDenial(tool);
|
|
48
|
+
const reason = !tool ? null : typeof browserToolDenial === 'function' ? browserToolDenial(tool, input, { host: 'codex', cwd, roots: policyRoots() }) : unloadedDenial(tool);
|
|
39
49
|
// Codex prints "Command blocked by PreToolUse hook: <reason>. Command: <cmd>", so
|
|
40
50
|
// the reason goes without its own final period.
|
|
41
51
|
if (reason) process.stdout.write(JSON.stringify({ hookSpecificOutput: { hookEventName: 'PreToolUse', permissionDecision: 'deny', permissionDecisionReason: reason.replace(/[.\s]+$/, '') } }));
|