synabun 2.0.10 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +207 -0
- package/README.md +25 -2
- package/THIRD-PARTY-LICENSES.md +22 -0
- package/bin/synabun.js +71 -24
- package/docs/whatsapp.md +13 -13
- package/hooks/claude-code/pre-websearch.mjs +12 -1
- package/hooks/claude-code/shared.mjs +5 -0
- package/hooks/claude-code/stop.mjs +1 -1
- package/lib/claude-hooks.js +172 -18
- package/lib/client-config-repair.js +30 -17
- package/lib/desktop-app.js +7 -1
- package/lib/external-tools.js +7 -6
- package/lib/first-launch-protection.js +57 -12
- package/lib/mcp-dist.js +176 -0
- package/lib/release-npm-ci.mjs +138 -0
- package/lib/release-publish.mjs +91 -0
- package/lib/release-scan.mjs +50 -0
- package/lib/server-crash-record.js +123 -0
- package/lib/server-exit.js +318 -0
- package/lib/server-supervisor.js +508 -0
- package/lib/start-launcher.js +37 -4
- package/lib/tools-cli.js +45 -0
- package/lib/update-snapshot.js +302 -0
- package/lib/virustotal.mjs +203 -0
- package/lib/windows-crash-event.js +269 -0
- package/mcp-server/dist/http.d.ts +20 -1
- package/mcp-server/dist/http.d.ts.map +1 -1
- package/mcp-server/dist/http.js +59 -12
- package/mcp-server/dist/http.js.map +1 -1
- package/mcp-server/dist/index.d.ts +33 -27
- package/mcp-server/dist/index.d.ts.map +1 -1
- package/mcp-server/dist/index.js +128 -143
- package/mcp-server/dist/index.js.map +1 -1
- package/mcp-server/dist/preload.js +1 -1
- package/mcp-server/dist/preload.js.map +1 -1
- package/mcp-server/dist/services/budget-judgments.d.ts +1 -1
- package/mcp-server/dist/services/budget-judgments.d.ts.map +1 -1
- package/mcp-server/dist/services/budget-judgments.js +5 -3
- package/mcp-server/dist/services/budget-judgments.js.map +1 -1
- package/mcp-server/dist/services/codex-config-heal.d.ts +6 -2
- package/mcp-server/dist/services/codex-config-heal.d.ts.map +1 -1
- package/mcp-server/dist/services/codex-config-heal.js +81 -28
- package/mcp-server/dist/services/codex-config-heal.js.map +1 -1
- package/mcp-server/dist/services/identity.d.ts +2 -2
- package/mcp-server/dist/services/identity.js +2 -2
- package/mcp-server/dist/services/memory-judge-backfill.d.ts +6 -0
- package/mcp-server/dist/services/memory-judge-backfill.d.ts.map +1 -1
- package/mcp-server/dist/services/memory-judge-backfill.js +7 -1
- package/mcp-server/dist/services/memory-judge-backfill.js.map +1 -1
- package/mcp-server/dist/services/memory-sessions.d.ts +1 -1
- package/mcp-server/dist/services/memory-sessions.d.ts.map +1 -1
- package/mcp-server/dist/services/memory-sessions.js +28 -2
- package/mcp-server/dist/services/memory-sessions.js.map +1 -1
- package/mcp-server/dist/services/neural-interface.d.ts +18 -11
- package/mcp-server/dist/services/neural-interface.d.ts.map +1 -1
- package/mcp-server/dist/services/neural-interface.js +67 -11
- package/mcp-server/dist/services/neural-interface.js.map +1 -1
- package/mcp-server/dist/services/server-instructions.d.ts +7 -2
- package/mcp-server/dist/services/server-instructions.d.ts.map +1 -1
- package/mcp-server/dist/services/server-instructions.js +22 -63
- package/mcp-server/dist/services/server-instructions.js.map +1 -1
- package/mcp-server/dist/services/tool-catalog.d.ts +120 -0
- package/mcp-server/dist/services/tool-catalog.d.ts.map +1 -0
- package/mcp-server/dist/services/tool-catalog.js +339 -0
- package/mcp-server/dist/services/tool-catalog.js.map +1 -0
- package/mcp-server/dist/services/tool-list-refresh-barrier.d.ts +12 -0
- package/mcp-server/dist/services/tool-list-refresh-barrier.d.ts.map +1 -0
- package/mcp-server/dist/services/tool-list-refresh-barrier.js +40 -0
- package/mcp-server/dist/services/tool-list-refresh-barrier.js.map +1 -0
- package/mcp-server/dist/services/tool-list.d.ts +108 -0
- package/mcp-server/dist/services/tool-list.d.ts.map +1 -0
- package/mcp-server/dist/services/tool-list.js +334 -0
- package/mcp-server/dist/services/tool-list.js.map +1 -0
- package/mcp-server/dist/services/tool-runtime.d.ts +161 -0
- package/mcp-server/dist/services/tool-runtime.d.ts.map +1 -0
- package/mcp-server/dist/services/tool-runtime.js +400 -0
- package/mcp-server/dist/services/tool-runtime.js.map +1 -0
- package/mcp-server/dist/services/typesafe-config.js +1 -1
- package/mcp-server/dist/services/typesafe-config.js.map +1 -1
- package/mcp-server/dist/services/whiteboard-geometry.d.ts +26 -2
- package/mcp-server/dist/services/whiteboard-geometry.d.ts.map +1 -1
- package/mcp-server/dist/services/whiteboard-geometry.js +91 -8
- package/mcp-server/dist/services/whiteboard-geometry.js.map +1 -1
- package/mcp-server/dist/tools/agents.d.ts +14 -14
- package/mcp-server/dist/tools/agents.d.ts.map +1 -1
- package/mcp-server/dist/tools/agents.js +29 -19
- package/mcp-server/dist/tools/agents.js.map +1 -1
- package/mcp-server/dist/tools/browser-batch.d.ts +3 -3
- package/mcp-server/dist/tools/choice.d.ts +6 -0
- package/mcp-server/dist/tools/choice.d.ts.map +1 -1
- package/mcp-server/dist/tools/choice.js +18 -13
- package/mcp-server/dist/tools/choice.js.map +1 -1
- package/mcp-server/dist/tools/git-tools.js +2 -2
- package/mcp-server/dist/tools/git-tools.js.map +1 -1
- package/mcp-server/dist/tools/image-tools.d.ts +1 -1
- package/mcp-server/dist/tools/image-tools.js +1 -1
- package/mcp-server/dist/tools/morelogin.d.ts.map +1 -1
- package/mcp-server/dist/tools/morelogin.js +9 -6
- package/mcp-server/dist/tools/morelogin.js.map +1 -1
- package/mcp-server/dist/tools/skill-tools.d.ts +505 -0
- package/mcp-server/dist/tools/skill-tools.d.ts.map +1 -0
- package/mcp-server/dist/tools/skill-tools.js +642 -0
- package/mcp-server/dist/tools/skill-tools.js.map +1 -0
- package/mcp-server/dist/tools/skill.d.ts +7 -0
- package/mcp-server/dist/tools/skill.d.ts.map +1 -0
- package/mcp-server/dist/tools/skill.js +11 -0
- package/mcp-server/dist/tools/skill.js.map +1 -0
- package/mcp-server/dist/tools/tool-groups.d.ts +68 -0
- package/mcp-server/dist/tools/tool-groups.d.ts.map +1 -0
- package/mcp-server/dist/tools/tool-groups.js +147 -0
- package/mcp-server/dist/tools/tool-groups.js.map +1 -0
- package/mcp-server/dist/tools/whiteboard-format.d.ts.map +1 -1
- package/mcp-server/dist/tools/whiteboard-format.js +7 -4
- package/mcp-server/dist/tools/whiteboard-format.js.map +1 -1
- package/mcp-server/dist/tools/whiteboard-tools.d.ts +64 -13
- package/mcp-server/dist/tools/whiteboard-tools.d.ts.map +1 -1
- package/mcp-server/dist/tools/whiteboard-tools.js +30 -5
- package/mcp-server/dist/tools/whiteboard-tools.js.map +1 -1
- package/mcp-server/package-lock.json +2 -2
- package/mcp-server/package.json +1 -1
- package/mcp-server/src/http.ts +75 -12
- package/mcp-server/src/index.ts +147 -154
- package/mcp-server/src/preload.ts +12 -12
- package/mcp-server/src/services/budget-judgments.ts +5 -3
- package/mcp-server/src/services/codex-config-heal.ts +80 -29
- package/mcp-server/src/services/identity.ts +2 -2
- package/mcp-server/src/services/memory-judge-backfill.ts +7 -1
- package/mcp-server/src/services/memory-sessions.ts +24 -3
- package/mcp-server/src/services/neural-interface.ts +81 -21
- package/mcp-server/src/services/server-instructions.ts +29 -64
- package/mcp-server/src/services/tool-catalog.ts +403 -0
- package/mcp-server/src/services/tool-list-refresh-barrier.ts +33 -0
- package/mcp-server/src/services/tool-list.ts +410 -0
- package/mcp-server/src/services/tool-runtime.ts +457 -0
- package/mcp-server/src/services/typesafe-config.ts +1 -1
- package/mcp-server/src/services/whiteboard-geometry.ts +94 -9
- package/mcp-server/src/tools/agents.ts +29 -20
- package/mcp-server/src/tools/choice.ts +17 -12
- package/mcp-server/src/tools/git-tools.ts +2 -2
- package/mcp-server/src/tools/image-tools.ts +1 -1
- package/mcp-server/src/tools/morelogin.ts +6 -4
- package/mcp-server/src/tools/skill-tools.ts +592 -0
- package/mcp-server/src/tools/skill.ts +13 -0
- package/mcp-server/src/tools/tool-groups.ts +164 -0
- package/mcp-server/src/tools/whiteboard-format.ts +9 -3
- package/mcp-server/src/tools/whiteboard-tools.ts +39 -5
- package/neural-interface/i18n/en.json +3953 -228
- package/neural-interface/i18n/pt-BR.json +3901 -179
- package/neural-interface/lib/agent-sandbox-elevation.js +6 -0
- package/neural-interface/lib/antigravity/acp-client-host.js +554 -0
- package/neural-interface/lib/antigravity/acp-connection.js +299 -0
- package/neural-interface/lib/antigravity/bypass.js +100 -0
- package/neural-interface/lib/antigravity/catalog.js +273 -0
- package/neural-interface/lib/antigravity/home.js +260 -0
- package/neural-interface/lib/antigravity/migrate-gemini.js +139 -0
- package/neural-interface/lib/antigravity/panel-bridge.js +1058 -0
- package/neural-interface/lib/antigravity/policy-hook.mjs +78 -0
- package/neural-interface/lib/antigravity/policy.js +74 -0
- package/neural-interface/lib/antigravity/tool-call.js +178 -0
- package/neural-interface/lib/antigravity/transcripts.js +252 -0
- package/neural-interface/lib/antigravity/usage.js +43 -0
- package/neural-interface/lib/assistant-api.js +128 -28
- package/neural-interface/lib/assistant-brains/antigravity.js +423 -0
- package/neural-interface/lib/assistant-brains/claude.js +4 -3
- package/neural-interface/lib/assistant-brains/codex-browser-policy-hook.mjs +12 -2
- package/neural-interface/lib/assistant-brains/codex-route-gate-hook.mjs +32 -9
- package/neural-interface/lib/assistant-brains/codex.js +9 -5
- package/neural-interface/lib/assistant-brains/opencode.js +120 -54
- package/neural-interface/lib/assistant-brains/opencode2-browser-policy/index.js +28 -13
- package/neural-interface/lib/assistant-brains/opencode2-route-gate/index.js +59 -19
- package/neural-interface/lib/assistant-budget-planner.js +7 -3
- package/neural-interface/lib/assistant-budget-split.js +42 -15
- package/neural-interface/lib/assistant-catalog.js +81 -15
- package/neural-interface/lib/assistant-config.js +6 -3
- package/neural-interface/lib/assistant-dispatch.js +1073 -200
- package/neural-interface/lib/assistant-envelope.js +156 -2
- package/neural-interface/lib/assistant-evidence.js +80 -0
- package/neural-interface/lib/assistant-hidden-models.js +7 -5
- package/neural-interface/lib/assistant-persona.js +93 -19
- package/neural-interface/lib/assistant-plan-permissions.js +25 -9
- package/neural-interface/lib/assistant-route-gate-codex.js +3 -0
- package/neural-interface/lib/assistant-route-gate.js +6 -4
- package/neural-interface/lib/assistant-router.js +245 -38
- package/neural-interface/lib/assistant-runtime.js +214 -30
- package/neural-interface/lib/assistant-task-prompt.js +87 -21
- package/neural-interface/lib/assistant-tools.js +51 -0
- package/neural-interface/lib/assistant-usage.js +29 -0
- package/neural-interface/lib/backup-service.js +626 -4
- package/neural-interface/lib/backup-zip-reader.js +10 -5
- package/neural-interface/lib/backup-zip-writer.js +257 -0
- package/neural-interface/lib/browser-execution.js +10 -2
- package/neural-interface/lib/browser-guard-cdp.js +84 -0
- package/neural-interface/lib/browser-network-guard.js +476 -0
- package/neural-interface/lib/browser-policy-roots.js +64 -0
- package/neural-interface/lib/browser-tool-policy.js +198 -38
- package/neural-interface/lib/claude-agent-bridge.js +11 -2
- package/neural-interface/lib/claude-history-cache.js +210 -0
- package/neural-interface/lib/claude-hooks-status.js +103 -0
- package/neural-interface/lib/claude-model-catalog.js +5 -1
- package/neural-interface/lib/claude-temporary.js +5 -11
- package/neural-interface/lib/cli-install-api.js +1 -1
- package/neural-interface/lib/cli-install.js +163 -154
- package/neural-interface/lib/cli-resolver.js +13 -3
- package/neural-interface/lib/cli-update-planner.js +52 -41
- package/neural-interface/lib/cloudflared/tunnel.js +42 -2
- package/neural-interface/lib/codex-mcp-approvals.js +11 -0
- package/neural-interface/lib/codex-rollout-reader.js +52 -0
- package/neural-interface/lib/codex-worker-app-server.js +191 -0
- package/neural-interface/lib/confined-fs.js +30 -3
- package/neural-interface/lib/crash-notice-api.js +98 -0
- package/neural-interface/lib/editor-completion-opencode.js +68 -68
- package/neural-interface/lib/editor-git-api.js +3 -20
- package/neural-interface/lib/exec-loop-command.js +13 -10
- package/neural-interface/lib/file-explorer-api.js +74 -40
- package/neural-interface/lib/file-explorer-watch.js +9 -3
- package/neural-interface/lib/git-bash/install.js +52 -6
- package/neural-interface/lib/git-bash/manager.js +59 -17
- package/neural-interface/lib/git-bash/pins.js +12 -0
- package/neural-interface/lib/git-read.js +2 -2
- package/neural-interface/lib/git-status-runner.js +390 -0
- package/neural-interface/lib/git-status-watchdog.js +40 -0
- package/neural-interface/lib/greeting/budgets.js +1 -0
- package/neural-interface/lib/greeting/engine.js +2 -2
- package/neural-interface/lib/greeting/sources.js +10 -12
- package/neural-interface/lib/greeting/writer.js +1 -1
- package/neural-interface/lib/http-guards.js +8 -2
- package/neural-interface/lib/install-details.js +4 -1
- package/neural-interface/lib/mcp-agent-servers.js +67 -0
- package/neural-interface/lib/mcp-client-config.js +35 -33
- package/neural-interface/lib/mcp-external-servers.js +332 -0
- package/neural-interface/lib/mcp-installer.js +2 -1
- package/neural-interface/lib/{mcp-profile-refresh-coordinator.js → mcp-tools-refresh-coordinator.js} +4 -4
- package/neural-interface/lib/memory-session-capture.js +17 -3
- package/neural-interface/lib/morelogin.js +177 -25
- package/neural-interface/lib/native-loop-providers.js +965 -66
- package/neural-interface/lib/native-loop-runtime.js +290 -42
- package/neural-interface/lib/opencode-config.js +557 -0
- package/neural-interface/lib/opencode-db-schema.js +17 -34
- package/neural-interface/lib/opencode-history.js +48 -218
- package/neural-interface/lib/opencode-mcp-ready.js +108 -0
- package/neural-interface/lib/opencode-native-boundary.js +53 -0
- package/neural-interface/lib/opencode-protocol.js +249 -112
- package/neural-interface/lib/opencode-runtime-config.js +32 -22
- package/neural-interface/lib/opencode-serve-records.js +39 -21
- package/neural-interface/lib/opencode-v2-client.js +48 -153
- package/neural-interface/lib/opencode-v2-ws-requests.js +36 -210
- package/neural-interface/lib/opencode-worker-data.js +27 -0
- package/neural-interface/lib/opencode2-client.js +73 -37
- package/neural-interface/lib/opencode2-proxy.js +23 -63
- package/neural-interface/lib/opencode2-translate.js +51 -2
- package/neural-interface/lib/owner-authority.js +249 -0
- package/neural-interface/lib/page-session.js +275 -0
- package/neural-interface/lib/path-confine.js +12 -9
- package/neural-interface/lib/peer-identity.js +793 -0
- package/neural-interface/lib/pty-host/core.js +28 -1
- package/neural-interface/lib/pty-host/lifetime.js +12 -0
- package/neural-interface/lib/pty-host/manager.js +12 -1
- package/neural-interface/lib/remote-policy.js +1 -1
- package/neural-interface/lib/request-gate.js +20 -2
- package/neural-interface/lib/rulesets/api.js +7 -6
- package/neural-interface/lib/rulesets/fs-safe.js +1 -1
- package/neural-interface/lib/rulesets/installer.js +180 -36
- package/neural-interface/lib/rulesets/json-edit.js +1 -1
- package/neural-interface/lib/rulesets/render.js +1 -1
- package/neural-interface/lib/session-cache-builder.js +81 -31
- package/neural-interface/lib/session-title-generator.js +58 -36
- package/neural-interface/lib/skills/api-v2.js +495 -0
- package/neural-interface/lib/skills/bundle.js +418 -0
- package/neural-interface/lib/skills/catalog.js +298 -0
- package/neural-interface/lib/skills/creation-api.js +191 -0
- package/neural-interface/lib/skills/creation-brief.js +247 -0
- package/neural-interface/lib/skills/creation-sources.js +285 -0
- package/neural-interface/lib/skills/creation.js +843 -0
- package/neural-interface/lib/skills/deploy.js +569 -0
- package/neural-interface/lib/skills/digest.js +119 -0
- package/neural-interface/lib/skills/discover.js +111 -0
- package/neural-interface/lib/skills/draft-confinement.js +216 -0
- package/neural-interface/lib/skills/eval-confinement.js +399 -0
- package/neural-interface/lib/skills/eval-sandbox.js +280 -0
- package/neural-interface/lib/skills/eval-trace.js +135 -0
- package/neural-interface/lib/skills/evals-api.js +212 -0
- package/neural-interface/lib/skills/evals.js +1573 -0
- package/neural-interface/lib/skills/export.js +203 -0
- package/neural-interface/lib/skills/frontmatter.js +64 -0
- package/neural-interface/lib/skills/health.js +75 -0
- package/neural-interface/lib/skills/json-edit.js +165 -0
- package/neural-interface/lib/skills/known-bridge-digests.json +441 -0
- package/neural-interface/lib/skills/known-bridges.js +96 -0
- package/neural-interface/lib/skills/library.js +823 -0
- package/neural-interface/lib/skills/local-store.js +21 -0
- package/neural-interface/lib/skills/migration.js +433 -0
- package/neural-interface/lib/skills/operations.js +45 -0
- package/neural-interface/lib/skills/ownership.js +427 -0
- package/neural-interface/lib/skills/packages.js +88 -0
- package/neural-interface/lib/skills/reviews.js +212 -0
- package/neural-interface/lib/skills/revision.js +80 -0
- package/neural-interface/lib/skills/roots.js +269 -0
- package/neural-interface/lib/skills/runtime-checks.js +358 -0
- package/neural-interface/lib/skills/scan-assets.js +252 -0
- package/neural-interface/lib/skills/scan-context.js +26 -0
- package/neural-interface/lib/skills/scan-shell.js +324 -0
- package/neural-interface/lib/skills/scan.js +364 -0
- package/neural-interface/lib/skills/scanners.js +54 -0
- package/neural-interface/lib/skills/service.js +530 -0
- package/neural-interface/lib/skills/telemetry.js +119 -0
- package/neural-interface/lib/sqlite-integrity-worker.js +22 -0
- package/neural-interface/lib/synabun-version.js +1 -1
- package/neural-interface/lib/system-activity.js +1 -1
- package/neural-interface/lib/tool-lists.js +124 -0
- package/neural-interface/lib/whatsapp/brain.js +7 -3
- package/neural-interface/lib/whatsapp/bridge.js +6 -3
- package/neural-interface/lib/whatsapp/cards.js +22 -9
- package/neural-interface/lib/whatsapp/config.js +1 -1
- package/neural-interface/lib/worker-confinement.js +1268 -0
- package/neural-interface/lib/worker-guard-setting.js +56 -0
- package/neural-interface/lib/worker-mcp-channel.js +175 -0
- package/neural-interface/lib/worker-question.js +74 -0
- package/neural-interface/lib/worker-relay-ports.js +227 -0
- package/neural-interface/lib/worker-resume.js +238 -0
- package/neural-interface/lib/worker-sandbox.js +329 -0
- package/neural-interface/package-lock.json +34 -12
- package/neural-interface/package.json +3 -2
- package/neural-interface/public/index.html +3 -1
- package/neural-interface/public/index2d.html +19 -11
- package/neural-interface/public/onboarding.html +3 -3
- package/neural-interface/public/shared/account-menu.js +8 -5
- package/neural-interface/public/shared/agent-runtime-options.js +125 -31
- package/neural-interface/public/shared/agy/agy-bypass.js +47 -0
- package/neural-interface/public/shared/agy/agy-client.js +266 -0
- package/neural-interface/public/shared/agy/agy-commands.js +120 -0
- package/neural-interface/public/shared/agy/agy-copy.js +326 -0
- package/neural-interface/public/shared/agy/agy-diff.js +161 -0
- package/neural-interface/public/shared/agy/agy-events.js +469 -0
- package/neural-interface/public/shared/agy/agy-greeting.js +26 -0
- package/neural-interface/public/shared/agy/agy-options.js +232 -0
- package/neural-interface/public/shared/agy/agy-panel.js +2543 -0
- package/neural-interface/public/shared/agy/agy-render.js +392 -0
- package/neural-interface/public/shared/agy/agy-setup.js +149 -0
- package/neural-interface/public/shared/agy/agy-styles.js +604 -0
- package/neural-interface/public/shared/agy/agy-tabs-logic.js +181 -0
- package/neural-interface/public/shared/api.js +1527 -1336
- package/neural-interface/public/shared/app-frame.js +192 -0
- package/neural-interface/public/shared/assistant/asst-agents-dock.js +36 -6
- package/neural-interface/public/shared/assistant/asst-api.js +1 -1
- package/neural-interface/public/shared/assistant/asst-ask-styles.js +270 -0
- package/neural-interface/public/shared/assistant/asst-ask-tail.js +118 -0
- package/neural-interface/public/shared/assistant/asst-ask.js +397 -0
- package/neural-interface/public/shared/assistant/asst-brain-picker.js +105 -44
- package/neural-interface/public/shared/assistant/asst-budget.js +5 -4
- package/neural-interface/public/shared/assistant/asst-control.js +205 -26
- package/neural-interface/public/shared/assistant/asst-followups-card.js +383 -0
- package/neural-interface/public/shared/assistant/asst-followups.js +417 -0
- package/neural-interface/public/shared/assistant/asst-hosts.js +16 -7
- package/neural-interface/public/shared/assistant/asst-limit-dock.js +45 -0
- package/neural-interface/public/shared/assistant/asst-limit-wait.js +327 -0
- package/neural-interface/public/shared/assistant/asst-limit.js +168 -0
- package/neural-interface/public/shared/assistant/asst-mascot.js +49 -12
- package/neural-interface/public/shared/assistant/asst-menu.js +7 -6
- package/neural-interface/public/shared/assistant/asst-panel.js +151 -19
- package/neural-interface/public/shared/assistant/asst-rack-styles.js +66 -49
- package/neural-interface/public/shared/assistant/asst-render.js +445 -82
- package/neural-interface/public/shared/assistant/asst-route.js +304 -53
- package/neural-interface/public/shared/assistant/asst-routes-editor.js +9 -8
- package/neural-interface/public/shared/assistant/asst-scenes.js +56 -1
- package/neural-interface/public/shared/assistant/asst-sidepanel.js +117 -10
- package/neural-interface/public/shared/assistant/asst-slash.js +17 -9
- package/neural-interface/public/shared/assistant/asst-state.js +87 -24
- package/neural-interface/public/shared/assistant/asst-stop.js +127 -0
- package/neural-interface/public/shared/assistant/asst-styles.js +93 -21
- package/neural-interface/public/shared/assistant/asst-tool-kinds.js +190 -23
- package/neural-interface/public/shared/assistant/asst-usage.js +2 -1
- package/neural-interface/public/shared/automation-context.js +5 -2
- package/neural-interface/public/shared/cc-dropdown.js +89 -19
- package/neural-interface/public/shared/cdx/cdx-context-menu.js +10 -9
- package/neural-interface/public/shared/cdx/cdx-copy.js +16 -0
- package/neural-interface/public/shared/cdx/cdx-output-model.js +22 -1
- package/neural-interface/public/shared/cdx/cdx-output.js +34 -10
- package/neural-interface/public/shared/cdx/cdx-panel.js +59 -151
- package/neural-interface/public/shared/cdx/cdx-preview.js +12 -0
- package/neural-interface/public/shared/cdx/cdx-protocol.js +39 -11
- package/neural-interface/public/shared/cdx/cdx-render.js +57 -38
- package/neural-interface/public/shared/cdx/cdx-requests.js +14 -4
- package/neural-interface/public/shared/cdx/cdx-skill-hints.js +54 -0
- package/neural-interface/public/shared/cdx/cdx-styles.js +15 -3
- package/neural-interface/public/shared/cdx/cdx-tabs.js +127 -44
- package/neural-interface/public/shared/cdx/cdx-ws.js +0 -1
- package/neural-interface/public/shared/cli-install-controller.js +218 -0
- package/neural-interface/public/shared/cli-install-view.js +11 -12
- package/neural-interface/public/shared/cli-status.js +11 -10
- package/neural-interface/public/shared/constants.js +5 -4
- package/neural-interface/public/shared/context-menu-areas.js +34 -0
- package/neural-interface/public/shared/context-menu-logic.js +243 -0
- package/neural-interface/public/shared/context-menu-model.js +367 -0
- package/neural-interface/public/shared/context-menu.js +372 -0
- package/neural-interface/public/shared/cp/cp-context-menu.js +10 -9
- package/neural-interface/public/shared/cp/cp-restore.js +162 -0
- package/neural-interface/public/shared/cp/cp-tool-cards.js +10 -3
- package/neural-interface/public/shared/crash-notice-view.js +168 -0
- package/neural-interface/public/shared/desktop-bridge.js +17 -0
- package/neural-interface/public/shared/desktop-titlebar-view.js +12 -0
- package/neural-interface/public/shared/desktop-titlebar.js +13 -4
- package/neural-interface/public/shared/desktop-update-view.js +21 -0
- package/neural-interface/public/shared/editor/editor-panel-logic.js +2 -2
- package/neural-interface/public/shared/explorer/fx-api.js +4 -4
- package/neural-interface/public/shared/explorer/fx-links.js +3 -3
- package/neural-interface/public/shared/explorer/fx-logic.js +1 -1
- package/neural-interface/public/shared/explorer/fx-main.js +48 -16
- package/neural-interface/public/shared/explorer/fx-tree.js +1 -0
- package/neural-interface/public/shared/greeting/greeting-card.js +2 -2
- package/neural-interface/public/shared/greeting/greeting-view.js +1 -0
- package/neural-interface/public/shared/html-shell.js +30 -15
- package/neural-interface/public/shared/i18n.js +2 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-approvals.js +7 -7
- package/neural-interface/public/shared/ocp-v2/ocp-v2-binding.js +4 -4
- package/neural-interface/public/shared/ocp-v2/ocp-v2-changes-logic.js +3 -101
- package/neural-interface/public/shared/ocp-v2/ocp-v2-childpanel.js +2 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-compact-button.js +1 -3
- package/neural-interface/public/shared/ocp-v2/ocp-v2-composer-logic.js +2 -6
- package/neural-interface/public/shared/ocp-v2/ocp-v2-context-menu.js +11 -11
- package/neural-interface/public/shared/ocp-v2/ocp-v2-context-model.js +0 -3
- package/neural-interface/public/shared/ocp-v2/ocp-v2-events.js +8 -4
- package/neural-interface/public/shared/ocp-v2/ocp-v2-manager.js +7 -7
- package/neural-interface/public/shared/ocp-v2/ocp-v2-outcome-notifications.js +16 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-panel.js +74 -259
- package/neural-interface/public/shared/ocp-v2/ocp-v2-plan.js +1 -2
- package/neural-interface/public/shared/ocp-v2/ocp-v2-projectbar.js +95 -202
- package/neural-interface/public/shared/ocp-v2/ocp-v2-rehydrate.js +13 -4
- package/neural-interface/public/shared/ocp-v2/ocp-v2-render.js +13 -22
- package/neural-interface/public/shared/ocp-v2/ocp-v2-send.js +4 -4
- package/neural-interface/public/shared/ocp-v2/ocp-v2-session-actions.js +8 -61
- package/neural-interface/public/shared/ocp-v2/ocp-v2-sessions-logic.js +2 -91
- package/neural-interface/public/shared/ocp-v2/ocp-v2-slash-hints.js +16 -15
- package/neural-interface/public/shared/ocp-v2/ocp-v2-state.js +8 -21
- package/neural-interface/public/shared/ocp-v2/ocp-v2-status-logic.js +1 -99
- package/neural-interface/public/shared/ocp-v2/ocp-v2-status.js +5 -35
- package/neural-interface/public/shared/ocp-v2/ocp-v2-styles.js +17 -21
- package/neural-interface/public/shared/ocp-v2/{ocp-v2-profile-inheritance.js → ocp-v2-tools-inheritance.js} +16 -16
- package/neural-interface/public/shared/ocp-v2/ocp-v2-ws.js +60 -50
- package/neural-interface/public/shared/page-session.js +96 -0
- package/neural-interface/public/shared/provider-icons.js +4 -2
- package/neural-interface/public/shared/registry.js +5 -3
- package/neural-interface/public/shared/retired-2d.js +3 -0
- package/neural-interface/public/shared/schedules-view.js +195 -61
- package/neural-interface/public/shared/settings/settings-claude-hooks.js +135 -0
- package/neural-interface/public/shared/settings/settings-data.js +3 -1
- package/neural-interface/public/shared/settings/settings-ia.js +6 -6
- package/neural-interface/public/shared/settings/settings-opencode.js +89 -0
- package/neural-interface/public/shared/settings/settings-rules.js +2 -2
- package/neural-interface/public/shared/settings/settings-skill-folders-pane.js +265 -0
- package/neural-interface/public/shared/settings/settings-skill-folders.js +130 -0
- package/neural-interface/public/shared/settings/settings-worker-guard.js +72 -0
- package/neural-interface/public/shared/showcase-privacy.js +6 -1
- package/neural-interface/public/shared/sidepanel-session-status.js +3 -3
- package/neural-interface/public/shared/skills/ss-args.js +96 -0
- package/neural-interface/public/shared/skills/ss-creation.js +222 -0
- package/neural-interface/public/shared/skills/ss-dialog.js +133 -0
- package/neural-interface/public/shared/skills/ss-doc.js +173 -0
- package/neural-interface/public/shared/skills/ss-eval-adapters.js +269 -0
- package/neural-interface/public/shared/skills/ss-eval-grade.js +359 -0
- package/neural-interface/public/shared/skills/ss-eval-optimise.js +153 -0
- package/neural-interface/public/shared/skills/ss-eval-plan.js +315 -0
- package/neural-interface/public/shared/skills/ss-evals.js +417 -0
- package/neural-interface/public/shared/skills/ss-form.js +159 -0
- package/neural-interface/public/shared/skills/ss-frontmatter.js +376 -0
- package/neural-interface/public/shared/skills/ss-ids.js +32 -0
- package/neural-interface/public/shared/skills/ss-lint.js +149 -0
- package/neural-interface/public/shared/skills/ss-presets.js +117 -0
- package/neural-interface/public/shared/skills/ss-profiles.js +513 -0
- package/neural-interface/public/shared/skills/ss-resources.js +165 -0
- package/neural-interface/public/shared/skills/ss-review-view.js +190 -0
- package/neural-interface/public/shared/skills/ss-tabs.js +79 -0
- package/neural-interface/public/shared/skills/ss-unicode.js +135 -0
- package/neural-interface/public/shared/skills/studio/sx-actions.js +222 -0
- package/neural-interface/public/shared/skills/studio/sx-cm.js +101 -0
- package/neural-interface/public/shared/skills/studio/sx-create-ai-view.js +749 -0
- package/neural-interface/public/shared/skills/studio/sx-create-ai.js +237 -0
- package/neural-interface/public/shared/skills/studio/sx-create-view.js +254 -0
- package/neural-interface/public/shared/skills/studio/sx-create.js +126 -0
- package/neural-interface/public/shared/skills/studio/sx-diff-view.js +43 -0
- package/neural-interface/public/shared/skills/studio/sx-diff.js +133 -0
- package/neural-interface/public/shared/skills/studio/sx-docs.js +480 -0
- package/neural-interface/public/shared/skills/studio/sx-dom.js +230 -0
- package/neural-interface/public/shared/skills/studio/sx-edit-view.js +848 -0
- package/neural-interface/public/shared/skills/studio/sx-editor-model.js +193 -0
- package/neural-interface/public/shared/skills/studio/sx-errors.js +22 -0
- package/neural-interface/public/shared/skills/studio/sx-fixes-view.js +359 -0
- package/neural-interface/public/shared/skills/studio/sx-fixes.js +327 -0
- package/neural-interface/public/shared/skills/studio/sx-geometry.js +82 -0
- package/neural-interface/public/shared/skills/studio/sx-import.js +262 -0
- package/neural-interface/public/shared/skills/studio/sx-inspector.js +308 -0
- package/neural-interface/public/shared/skills/studio/sx-install-flow.js +282 -0
- package/neural-interface/public/shared/skills/studio/sx-install.js +313 -0
- package/neural-interface/public/shared/skills/studio/sx-library-view.js +748 -0
- package/neural-interface/public/shared/skills/studio/sx-library.js +479 -0
- package/neural-interface/public/shared/skills/studio/sx-main.js +690 -0
- package/neural-interface/public/shared/skills/studio/sx-operations-view.js +98 -0
- package/neural-interface/public/shared/skills/studio/sx-operations.js +11 -0
- package/neural-interface/public/shared/skills/studio/sx-plan.js +158 -0
- package/neural-interface/public/shared/skills/studio/sx-publish-view.js +621 -0
- package/neural-interface/public/shared/skills/studio/sx-review-view.js +369 -0
- package/neural-interface/public/shared/skills/studio/sx-review.js +148 -0
- package/neural-interface/public/shared/skills/studio/sx-scan.js +35 -0
- package/neural-interface/public/shared/skills/studio/sx-snippets.js +96 -0
- package/neural-interface/public/shared/skills/studio/sx-subject.js +249 -0
- package/neural-interface/public/shared/skills/studio/sx-test-view.js +994 -0
- package/neural-interface/public/shared/skills/studio/sx-test.js +328 -0
- package/neural-interface/public/shared/skills/studio/sx-versions-view.js +241 -0
- package/neural-interface/public/shared/skills/studio/sx-workspace-view.js +426 -0
- package/neural-interface/public/shared/state.js +1 -1
- package/neural-interface/public/shared/streaming-markdown.js +58 -0
- package/neural-interface/public/shared/styleguide/sg-panel.js +4 -2
- package/neural-interface/public/shared/styles.css +1822 -1756
- package/neural-interface/public/shared/synabun-mascot.js +1115 -9
- package/neural-interface/public/shared/text-cache.js +29 -0
- package/neural-interface/public/shared/tool-list-picker.js +55 -0
- package/neural-interface/public/shared/tool-list-storage.js +24 -0
- package/neural-interface/public/shared/tool-list-view.js +112 -0
- package/neural-interface/public/shared/topright-overflow-logic.js +54 -0
- package/neural-interface/public/shared/tour/tour-actor.js +268 -0
- package/neural-interface/public/shared/tour/tour-beats.js +336 -0
- package/neural-interface/public/shared/tour/tour-engine.js +884 -0
- package/neural-interface/public/shared/tour/tour-ink.js +390 -0
- package/neural-interface/public/shared/tour/tour-stage.js +440 -0
- package/neural-interface/public/shared/tour/tour-state.js +40 -0
- package/neural-interface/public/shared/tour/tour-tips.js +99 -0
- package/neural-interface/public/shared/tour/tour.css +144 -0
- package/neural-interface/public/shared/ui-antigravity-panel.js +19 -0
- package/neural-interface/public/shared/ui-assistant.js +2 -0
- package/neural-interface/public/shared/ui-automation-studio.js +111 -140
- package/neural-interface/public/shared/ui-claude-panel.js +376 -82
- package/neural-interface/public/shared/ui-cli-banner.js +23 -167
- package/neural-interface/public/shared/ui-command-runner.js +6 -3
- package/neural-interface/public/shared/ui-context-menu.js +295 -0
- package/neural-interface/public/shared/ui-cost-widget.js +57 -59
- package/neural-interface/public/shared/ui-crash-notice.js +187 -0
- package/neural-interface/public/shared/ui-detail.js +15 -3
- package/neural-interface/public/shared/ui-file-explorer.js +48 -6
- package/neural-interface/public/shared/ui-file-links.js +2 -2
- package/neural-interface/public/shared/ui-games.js +2 -2
- package/neural-interface/public/shared/ui-image-gallery.js +50 -47
- package/neural-interface/public/shared/ui-judgments.js +1 -1
- package/neural-interface/public/shared/ui-keybinds.js +33 -2
- package/neural-interface/public/shared/ui-link.js +3 -3
- package/neural-interface/public/shared/ui-menubar.js +10 -20
- package/neural-interface/public/shared/ui-native-loop-router-state.js +5 -0
- package/neural-interface/public/shared/ui-native-loop-router.js +11 -1
- package/neural-interface/public/shared/ui-navbar.js +49 -24
- package/neural-interface/public/shared/ui-notifications.js +1 -0
- package/neural-interface/public/shared/ui-panels.js +96 -65
- package/neural-interface/public/shared/ui-resume.js +9 -7
- package/neural-interface/public/shared/ui-schedules-studio.js +546 -431
- package/neural-interface/public/shared/ui-scroll-follow.js +16 -5
- package/neural-interface/public/shared/ui-sessions.js +27 -15
- package/neural-interface/public/shared/ui-settings.js +683 -526
- package/neural-interface/public/shared/ui-sidepanel-session-entry.js +9 -2
- package/neural-interface/public/shared/ui-sidepanel-sessions.js +4 -4
- package/neural-interface/public/shared/ui-sidepanel-state.js +23 -12
- package/neural-interface/public/shared/ui-sidepanel-tray.js +48 -7
- package/neural-interface/public/shared/ui-sidepanel-windows.js +18 -13
- package/neural-interface/public/shared/ui-skills.js +33 -2830
- package/neural-interface/public/shared/ui-styleguide.js +5 -2
- package/neural-interface/public/shared/ui-sync.js +15 -5
- package/neural-interface/public/shared/ui-terminal.js +270 -190
- package/neural-interface/public/shared/ui-tool-updates.js +6 -4
- package/neural-interface/public/shared/ui-tooltip.js +81 -51
- package/neural-interface/public/shared/ui-topright-overflow.js +233 -0
- package/neural-interface/public/shared/ui-trash.js +6 -4
- package/neural-interface/public/shared/ui-tutorial-layout.js +3 -117
- package/neural-interface/public/shared/ui-tutorial-preview.js +103 -0
- package/neural-interface/public/shared/ui-tutorial-steps.js +3 -65
- package/neural-interface/public/shared/ui-tutorial.css +47 -100
- package/neural-interface/public/shared/ui-tutorial.js +285 -509
- package/neural-interface/public/shared/ui-update.js +38 -2
- package/neural-interface/public/shared/ui-whiteboard.js +312 -59
- package/neural-interface/public/shared/ui-worker-end.js +5 -1
- package/neural-interface/public/shared/ui-workspaces.js +3 -2
- package/neural-interface/public/shared/view-variant.js +66 -0
- package/neural-interface/public/shared/whatsapp/wa-view.js +3 -3
- package/neural-interface/public/shared/whiteboard-list.js +172 -0
- package/neural-interface/public/shared/worker-end.js +10 -3
- package/neural-interface/public/shared/worker-questions.js +34 -0
- package/neural-interface/public/shared/worker-restart.js +12 -0
- package/neural-interface/public/sidepanel-session.html +2 -2
- package/neural-interface/public/variant/2d/background.js +2 -1
- package/neural-interface/public/variant/2d/context-menu.js +8 -2
- package/neural-interface/public/variant/2d/graph.js +42 -20
- package/neural-interface/public/variant/2d/hulls.js +14 -9
- package/neural-interface/public/variant/2d/lasso.js +11 -7
- package/neural-interface/public/variant/2d/main.js +32 -1
- package/neural-interface/public/variant/2d/minimap.js +11 -13
- package/neural-interface/public/variant/3d/main.js +69 -6
- package/neural-interface/public/variant/3d/map-controls.js +24 -9
- package/neural-interface/public/vendor/caveat/OFL.txt +93 -0
- package/neural-interface/public/vendor/caveat/caveat-latin-400-normal.woff2 +0 -0
- package/neural-interface/public/vendor/caveat/caveat-latin-700-normal.woff2 +0 -0
- package/neural-interface/public/vendor/caveat/caveat.css +17 -0
- package/neural-interface/public/vendor/caveat/manifest.json +12 -0
- package/neural-interface/public/vendor/yaml/LICENSE +13 -0
- package/neural-interface/public/vendor/yaml/manifest.json +4 -0
- package/neural-interface/public/vendor/yaml/yaml-2.9.1.min.js +137 -0
- package/neural-interface/scripts/build-vendor.mjs +32 -0
- package/neural-interface/server.js +4553 -2855
- package/neural-interface/templates/rulesets/README.md +1 -1
- package/neural-interface/templates/rulesets/core.md +1 -1
- package/neural-interface/templates/rulesets/legacy-hashes.json +23 -5
- package/neural-interface/templates/rulesets/manifest.json +8 -8
- package/npm-shrinkwrap.json +34 -12
- package/package.json +17 -3
- package/postinstall.js +9 -4
- package/preuninstall.js +1 -1
- package/setup.js +97 -322
- package/skills/skill-forge/SKILL.md +177 -0
- package/skills/skill-forge/evals/evals.json +54 -0
- package/skills/skill-forge/references/package.md +105 -0
- package/skills/skill-forge/references/review-and-recovery.md +63 -0
- package/skills/skill-forge/references/runtime-profiles.md +20 -0
- package/skills/skill-forge/references/sources-and-capabilities.md +51 -0
- package/skills/synabun/SKILL.md +10 -7
- package/skills/synabun/modules/audit.md +1 -5
- package/skills/synabun/modules/changelog.md +1 -5
- package/skills/synabun/modules/idea.md +1 -1
- package/skills/synabun/modules/memorize.md +6 -9
- package/skills/synabun/modules/schedule.md +6 -6
- package/mcp-server/dist/services/profiles.d.ts +0 -120
- package/mcp-server/dist/services/profiles.d.ts.map +0 -1
- package/mcp-server/dist/services/profiles.js +0 -387
- package/mcp-server/dist/services/profiles.js.map +0 -1
- package/mcp-server/dist/tools/leonardo-browser-tools.d.ts +0 -97
- package/mcp-server/dist/tools/leonardo-browser-tools.d.ts.map +0 -1
- package/mcp-server/dist/tools/leonardo-browser-tools.js +0 -228
- package/mcp-server/dist/tools/leonardo-browser-tools.js.map +0 -1
- package/mcp-server/dist/tools/leonardo.d.ts +0 -13
- package/mcp-server/dist/tools/leonardo.d.ts.map +0 -1
- package/mcp-server/dist/tools/leonardo.js +0 -21
- package/mcp-server/dist/tools/leonardo.js.map +0 -1
- package/mcp-server/dist/tools/profile.d.ts +0 -17
- package/mcp-server/dist/tools/profile.d.ts.map +0 -1
- package/mcp-server/dist/tools/profile.js +0 -114
- package/mcp-server/dist/tools/profile.js.map +0 -1
- package/mcp-server/src/services/profiles.ts +0 -428
- package/mcp-server/src/tools/leonardo-browser-tools.ts +0 -291
- package/mcp-server/src/tools/leonardo.ts +0 -30
- package/mcp-server/src/tools/profile.ts +0 -122
- package/neural-interface/lib/assistant-brains/opencode-browser-policy.js +0 -47
- package/neural-interface/lib/assistant-brains/opencode-route-gate.js +0 -62
- package/neural-interface/lib/mcp-profile-servers.js +0 -120
- package/neural-interface/public/shared/ui-tutorial-draw.js +0 -311
- package/skills/leonardo/SKILL.md +0 -168
- package/skills/leonardo/icon.svg +0 -1
- package/skills/leonardo/modules/browser-guide.md +0 -378
- package/skills/leonardo/modules/image-prompter.md +0 -283
- package/skills/leonardo/modules/model-advisor.md +0 -100
- package/skills/leonardo/modules/prompt-library.md +0 -110
- package/skills/leonardo/modules/style-guide.md +0 -186
- package/skills/leonardo/modules/video-prompter.md +0 -317
- /package/neural-interface/templates/rulesets/{gemini.md → antigravity.md} +0 -0
|
@@ -0,0 +1,399 @@
|
|
|
1
|
+
// ── The confinement of a skill-evaluation run (P4) ──
|
|
2
|
+
// An evaluation (lib/skills/evals.js) runs untrusted skill text with real models: a skill under test can tell the
|
|
3
|
+
// model anything. So every run of an evaluation is held to its own job folder, the way a drafting run is
|
|
4
|
+
// (lib/skills/draft-confinement.js), by what each provider can enforce, and it never sees SynaBun's MCP server, the
|
|
5
|
+
// owner's skills or the owner's runtime folders: the skill under test is copied into the run's own folder, in the
|
|
6
|
+
// project skill folder its runtime reads (EVAL_SKILL_ROOTS), and nothing is ever installed for a test.
|
|
7
|
+
//
|
|
8
|
+
// role what it does its tools (Claude Code names)
|
|
9
|
+
// trial the case's request, with or without the skill Read, Glob, Grep in its folder; Write, Edit in its folder
|
|
10
|
+
// but never in a skill folder (.claude, .agents, .opencode);
|
|
11
|
+
// Skill; Bash only when `shell` (the case asks for one AND
|
|
12
|
+
// the run is under the OS sandbox: server.js wraps it)
|
|
13
|
+
// grader grades one answer against its assertions Read, Glob, Grep in its folder; its JSON answer
|
|
14
|
+
// judge compares two answers blind the same
|
|
15
|
+
// proposer proposes a description (the optimiser) the same
|
|
16
|
+
//
|
|
17
|
+
// Claude Code: `tools` is exactly the list above, no MCP server (strictMcpConfig), no settings file at all
|
|
18
|
+
// (settingSources []: no project, user or local settings, no CLAUDE.md), hooks and a skill's inline shell switched off
|
|
19
|
+
// in the flag settings (disableAllHooks, disableSkillShellExecution: a skill's own frontmatter hooks and `!` commands
|
|
20
|
+
// never run; SynaBun's SDK hooks still do), the skill under test loaded as the one local plugin `workspace` from the
|
|
21
|
+
// run's .claude folder (`skills` names it, so nothing else is in its catalog; a baseline loads none), and every call
|
|
22
|
+
// checked twice (a PreToolUse hook Claude Code runs before any permission mode, and canUseTool). Codex: its sandbox
|
|
23
|
+
// (workspace-write in the folder for a trial, read-only otherwise), no network, no web search, every MCP server
|
|
24
|
+
// disabled; it keeps its shell, which its sandbox holds to writes in the folder but not to reads: Codex is the owner's
|
|
25
|
+
// opt-in per skill version (lib/skills/evals.js). OpenCode: no project configuration (OPENCODE_DISABLE_PROJECT_CONFIG:
|
|
26
|
+
// no opencode.json, no .opencode plugin, agent, command or tool of the folder, no AGENTS.md at its top), no formatter
|
|
27
|
+
// and no snapshot (OPENCODE_EVAL_SETTINGS), the skill under test copied into the run's own configuration folder
|
|
28
|
+
// (placeOpenCodeEvalSkill), Code Mode, web, subagents, todo, LSP and question tools off, the shell off unless `shell`,
|
|
29
|
+
// the skill tool on for a trial only, no MCP server, reads outside the folder denied, and every edit asked and answered
|
|
30
|
+
// inside the folder (evalOpenCodeDecision). Every run gets git's safety settings (evalGitSafetyEnv). A shell, where a
|
|
31
|
+
// case asks, runs under the evaluation's own macOS sandbox (lib/skills/eval-sandbox.js). A run whose confinement
|
|
32
|
+
// cannot be set up never starts (CONFINEMENT_UNSUPPORTED), and it is never escalated to another provider.
|
|
33
|
+
|
|
34
|
+
import { constants as fsConstants, copyFileSync, lstatSync, mkdirSync, readdirSync, realpathSync, rmSync, writeFileSync } from 'node:fs';
|
|
35
|
+
import { dirname, isAbsolute, join, relative, resolve, sep } from 'node:path';
|
|
36
|
+
import { isInside, realPathOf } from '../path-confine.js';
|
|
37
|
+
import { DRAFT_DISALLOWED_TOOLS, codexMcpServerNames } from './draft-confinement.js';
|
|
38
|
+
import { evalConfigPathProblem } from '../../public/shared/skills/ss-evals.js';
|
|
39
|
+
|
|
40
|
+
export const EVAL_CONFINEMENT = 'skill-eval';
|
|
41
|
+
/** Part of every run's experiment identity: a change to what an evaluation run may do is a new version. */
|
|
42
|
+
export const EVAL_CONFINEMENT_VERSION = 'skill-eval/5';
|
|
43
|
+
export const EVAL_ROLES = Object.freeze(['trial', 'grader', 'judge', 'proposer']);
|
|
44
|
+
/** Where a trial's copy of the skill goes in its folder: the project skill folder each runtime reads. */
|
|
45
|
+
export const EVAL_SKILL_ROOTS = Object.freeze({ 'claude-code': '.claude/skills', codex: '.agents/skills', opencode: '.opencode/skills' });
|
|
46
|
+
/** The skill folders of a trial (SynaBun writes them; no tool does: a skill folder written mid-run would change what the
|
|
47
|
+
* runtime sees). Every other folder or file a runtime reads its settings or code from is refused the same way
|
|
48
|
+
* (ss-evals.js evalConfigPathProblem); an instruction file (CLAUDE.md, AGENTS.md) is a file a trial may write. */
|
|
49
|
+
export const EVAL_PROTECTED_DIRS = Object.freeze(['.claude', '.agents', '.opencode', '.codex']);
|
|
50
|
+
/** The local plugin a Claude Code trial loads the skill under test from (its catalog names it workspace:<skill>). */
|
|
51
|
+
export const EVAL_CLAUDE_PLUGIN = 'workspace';
|
|
52
|
+
/** Claude Code's flag settings for every evaluation run: no hook of any settings file, plugin or skill, no inline shell. */
|
|
53
|
+
export const EVAL_CLAUDE_SETTINGS = Object.freeze({ disableAllHooks: true, disableSkillShellExecution: true });
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* git's settings for every evaluation run's process tree (the runtime and what it starts outside the evaluation's
|
|
57
|
+
* shell sandbox: Claude Code's and OpenCode's own git calls, Codex and its shell). The job folder never holds a
|
|
58
|
+
* repository: no `.git` is copied there (ss-evals.js), written there by a tool (evalToolDecision) or by a shell step
|
|
59
|
+
* (lib/skills/eval-sandbox.js, whose git keeps its repository outside the folder). On top of that, git here never looks
|
|
60
|
+
* above the job folder for one (GIT_CEILING_DIRECTORIES), never takes a folder as a bare repository it was not pointed
|
|
61
|
+
* at (a HEAD, objects/ and refs/ left in the folder: safe.bareRepository), reads no system and no global configuration
|
|
62
|
+
* (GIT_CONFIG_NOSYSTEM, GIT_CONFIG_GLOBAL=/dev/null: no ~/.gitconfig or $XDG_CONFIG_HOME/git/config, wherever HOME and
|
|
63
|
+
* XDG_CONFIG_HOME point), and runs no fsmonitor program and no hook (command-line scope: what a repository's own
|
|
64
|
+
* configuration cannot override). So no configuration a run could have written is read by the runtime's git.
|
|
65
|
+
*/
|
|
66
|
+
export function evalGitSafetyEnv(root) {
|
|
67
|
+
return {
|
|
68
|
+
// withServeEnv clears the prefix first, then installs only these deliberate settings. A list of known names
|
|
69
|
+
// misses alternate object/index paths and command-line config (including future GIT_* variables).
|
|
70
|
+
'GIT_*': null,
|
|
71
|
+
GIT_CEILING_DIRECTORIES: dirname(String(root)),
|
|
72
|
+
GIT_CONFIG_NOSYSTEM: '1',
|
|
73
|
+
GIT_CONFIG_GLOBAL: '/dev/null',
|
|
74
|
+
GIT_CONFIG_COUNT: '3',
|
|
75
|
+
GIT_CONFIG_KEY_0: 'safe.bareRepository', GIT_CONFIG_VALUE_0: 'explicit',
|
|
76
|
+
GIT_CONFIG_KEY_1: 'core.fsmonitor', GIT_CONFIG_VALUE_1: 'false',
|
|
77
|
+
GIT_CONFIG_KEY_2: 'core.hooksPath', GIT_CONFIG_VALUE_2: '/dev/null',
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
export const EVAL_TRIAL_TOOLS = Object.freeze(['Read', 'Write', 'Edit', 'Glob', 'Grep', 'Skill']);
|
|
81
|
+
export const EVAL_READER_TOOLS = Object.freeze(['Read', 'Glob', 'Grep', 'StructuredOutput']);
|
|
82
|
+
const READERS = new Set(['Read', 'Glob', 'Grep']);
|
|
83
|
+
const WRITERS = new Set(['Write', 'Edit']);
|
|
84
|
+
const REFUSED = 'An evaluation run works only inside its own folder: no web, no MCP tools, no subagents.';
|
|
85
|
+
|
|
86
|
+
/** The providers an evaluation can run on, in the order the Test tab lists them. */
|
|
87
|
+
export const EVAL_CONFINED_PROVIDERS = Object.freeze(['claude-code', 'codex', 'opencode']);
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* What a provider can hold an evaluation run to: { ok, level, note, shell } or { ok: false, reason }. `shell`:
|
|
91
|
+
* 'sandbox' (a shell only under the OS sandbox: macOS, Protect workers = Enforce), 'own-sandbox' (Codex's own, always
|
|
92
|
+
* on), 'never'.
|
|
93
|
+
*/
|
|
94
|
+
export function evalConfinementSupport(provider, { platform = process.platform } = {}) {
|
|
95
|
+
const name = String(provider || '');
|
|
96
|
+
if (name === 'claude-code') return { ok: true, level: 'strict', shell: platform === 'darwin' ? 'sandbox' : 'never', optIn: false, note: 'Read, Write, Edit, Glob, Grep and Skill inside its folder; no settings file, hook or plugin but the skill under test; a shell only under the evaluation\'s macOS sandbox (no network, no home folder); no web, no MCP tools, no subagents.' };
|
|
97
|
+
if (name === 'codex') return { ok: true, level: 'sandbox', shell: 'own-sandbox', optIn: true, note: `Codex keeps its shell under its ${platform === 'win32' ? 'Windows' : platform === 'darwin' ? 'Seatbelt' : 'Linux'} sandbox: writes inside its folder only, no network, no web search, no MCP server; its shell can read files anywhere on this computer, and what it reads can reach its model provider.` };
|
|
98
|
+
if (name === 'opencode') return { ok: true, level: 'rules', shell: platform === 'darwin' ? 'sandbox' : 'never', optIn: false, note: 'OpenCode with no project configuration or plugin of the folder, its web, subagent and todo tools off, no MCP server, reads and edits inside its folder only; a shell only under the evaluation\'s macOS sandbox (no network, no home folder).' };
|
|
99
|
+
// Antigravity (a worker of the Assistant) has no evaluation confinement in SynaBun: an evaluation never runs unconfined.
|
|
100
|
+
if (name === 'antigravity') return { ok: false, reason: 'Antigravity cannot be held to an evaluation folder: skill evaluations run on Claude Code, Codex and OpenCode.' };
|
|
101
|
+
return { ok: false, reason: `${name || 'That provider'} cannot be held to an evaluation folder: skill evaluations run on Claude Code, Codex and OpenCode.` };
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* A confinement as a run carries it, checked: { kind, role, shell, root (the folder's real path), protected (the
|
|
106
|
+
* skill folders' places), skill (the name under test, or null) }. Throws when it cannot be used: the run must not
|
|
107
|
+
* start unconfined.
|
|
108
|
+
*/
|
|
109
|
+
export function resolveEvalConfinement(confinement, cwd) {
|
|
110
|
+
if (!confinement || confinement.kind !== EVAL_CONFINEMENT) throw new Error('Unknown confinement.');
|
|
111
|
+
const role = EVAL_ROLES.includes(confinement.role) ? confinement.role : null;
|
|
112
|
+
if (!role) throw new Error('Unknown evaluation role.');
|
|
113
|
+
const root = realpathSync(String(cwd || ''));
|
|
114
|
+
if (!lstatSync(root).isDirectory()) throw new Error('The evaluation folder is not a folder.');
|
|
115
|
+
const skill = typeof confinement.skill === 'string' && /^[a-z0-9][a-z0-9._-]{0,63}$/.test(confinement.skill) ? confinement.skill : null;
|
|
116
|
+
return { kind: EVAL_CONFINEMENT, role, shell: role === 'trial' && confinement.shell === true, root, trialDir: dirname(root), protected: EVAL_PROTECTED_DIRS.map((d) => join(root, d)), skill };
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function placeOf(raw, root) {
|
|
120
|
+
if (typeof raw !== 'string' || !raw || raw.length > 4096 || /[\u0000-\u001f\u007f]/.test(raw) || raw.startsWith('~')) return null;
|
|
121
|
+
if (raw.split(/[\\/]+/).includes('..')) return null;
|
|
122
|
+
const abs = isAbsolute(raw) ? resolve(raw) : resolve(root, raw);
|
|
123
|
+
try { return realPathOf(abs); } catch { return null; }
|
|
124
|
+
}
|
|
125
|
+
function patternProblem(p) {
|
|
126
|
+
if (p === undefined || p === null) return null;
|
|
127
|
+
if (typeof p !== 'string' || p.length > 1000 || /[\u0000-\u001f\u007f]/.test(p)) return 'is not a plain pattern';
|
|
128
|
+
if (p.startsWith('/') || p.startsWith('\\') || p.startsWith('~') || /^[A-Za-z]:/.test(p)) return 'is absolute: patterns are relative to the evaluation folder';
|
|
129
|
+
if (p.split(/[\\/]+/).includes('..')) return 'climbs out with "..": patterns stay inside the evaluation folder';
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
const inProtected = (confined, at) => confined.protected.some((dir) => at === dir || isInside(dir, at));
|
|
133
|
+
/** Why a place of the folder holds a runtime's settings or code (a skill folder, .git, opencode.json, …), or null. */
|
|
134
|
+
function configPlace(confined, at) {
|
|
135
|
+
if (inProtected(confined, at)) return 'a skill folder (.claude, .agents, .opencode, .codex): the skill under test stays as it is';
|
|
136
|
+
const rel = relative(confined.root, at).split(sep).join('/');
|
|
137
|
+
const why = rel ? evalConfigPathProblem(rel) : null;
|
|
138
|
+
return why ? `${why.name}, which ${why.who || 'a runtime'} reads as its own settings or code` : null;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Whether an evaluation run may make this tool call: null when it may, else why not (the model reads the reason).
|
|
143
|
+
* @param {string} toolName @param {object} input @param {object} confined resolveEvalConfinement()'s answer
|
|
144
|
+
*/
|
|
145
|
+
export function evalToolDecision(toolName, input, confined) {
|
|
146
|
+
try {
|
|
147
|
+
const name = String(toolName || '');
|
|
148
|
+
const args = input && typeof input === 'object' ? input : {};
|
|
149
|
+
const { root, role } = confined || {};
|
|
150
|
+
if (!root || !role) return 'This run\'s evaluation folder is not known: nothing can be done.';
|
|
151
|
+
if (name === 'StructuredOutput' && role !== 'trial') return null; // the answer itself (an output schema), no file access
|
|
152
|
+
const trial = role === 'trial';
|
|
153
|
+
if (trial && name === 'Skill') return null; // the catalog is the run's own folder: only the skill under test is in it
|
|
154
|
+
if (trial && name === 'Bash') return confined.shell ? null : `Bash is not available in this evaluation (the case does not ask for a shell, or no OS sandbox holds one). ${REFUSED}`;
|
|
155
|
+
if (!READERS.has(name) && !(trial && WRITERS.has(name))) return `${name || 'That tool'} is not available. ${REFUSED}`;
|
|
156
|
+
if (name === 'Read') {
|
|
157
|
+
const at = placeOf(args.file_path, root);
|
|
158
|
+
if (!at || !isInside(root, at)) return `Read is limited to this run's folder (${root}). ${REFUSED}`;
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
161
|
+
if (name === 'Glob' || name === 'Grep') {
|
|
162
|
+
if (args.path !== undefined && args.path !== null && args.path !== '') {
|
|
163
|
+
const at = placeOf(args.path, root);
|
|
164
|
+
if (!at || !isInside(root, at, { allowRoot: true })) return `${name} searches this run's folder only (${root}).`;
|
|
165
|
+
}
|
|
166
|
+
if (name === 'Glob' && (typeof args.pattern !== 'string' || !args.pattern)) return 'Glob needs a pattern.';
|
|
167
|
+
const bad = name === 'Glob' ? patternProblem(args.pattern) : patternProblem(args.glob);
|
|
168
|
+
if (bad) return `The ${name === 'Glob' ? 'pattern' : 'glob'} ${bad}.`;
|
|
169
|
+
return null;
|
|
170
|
+
}
|
|
171
|
+
// Write, Edit (trials only): a plain file inside the folder, never in a skill folder.
|
|
172
|
+
const at = placeOf(args.file_path, root);
|
|
173
|
+
if (!at || !isInside(root, at)) return `${name} writes inside this run's folder only (${root}). ${REFUSED}`;
|
|
174
|
+
const place = configPlace(confined, at);
|
|
175
|
+
if (place) return `${name} cannot write into ${place}.`;
|
|
176
|
+
let st = null;
|
|
177
|
+
try { st = lstatSync(at); } catch { st = null; }
|
|
178
|
+
if (st && (!st.isFile() || st.nlink > 1)) return `${at} is not a plain file of this run: it cannot be written.`;
|
|
179
|
+
return null;
|
|
180
|
+
} catch (err) {
|
|
181
|
+
return `The call could not be checked (${err?.message || err}), so it is refused.`;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/** The PreToolUse hook an evaluation run gets (no matcher: every call). */
|
|
186
|
+
export function evalPreToolUseHook(confined) {
|
|
187
|
+
return async (input) => {
|
|
188
|
+
const reason = evalToolDecision(input?.tool_name, input?.tool_input || {}, confined);
|
|
189
|
+
return reason ? { hookSpecificOutput: { hookEventName: 'PreToolUse', permissionDecision: 'deny', permissionDecisionReason: reason } } : {};
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Claude Code's options for an evaluation run: the tools, what is removed by name, no settings file of any source,
|
|
195
|
+
* the flag settings that switch hooks and inline shell off, the one plugin (a trial with the skill: the run's .claude
|
|
196
|
+
* folder, where SynaBun copied the skill and wrote the plugin's manifest; anything else: none), the skills it may use
|
|
197
|
+
* (that one, as workspace:<skill>; a baseline and the helpers: none) and git's safety settings for its environment.
|
|
198
|
+
*/
|
|
199
|
+
export function evalClaudeOptions(confined) {
|
|
200
|
+
const trial = confined.role === 'trial';
|
|
201
|
+
const tools = trial ? [...EVAL_TRIAL_TOOLS, ...(confined.shell ? ['Bash'] : [])] : [...EVAL_READER_TOOLS];
|
|
202
|
+
const disallowed = DRAFT_DISALLOWED_TOOLS.filter((t) => !tools.includes(t));
|
|
203
|
+
const withSkill = trial && !!confined.skill;
|
|
204
|
+
return {
|
|
205
|
+
tools, disallowedTools: disallowed, settingSources: [], settings: { ...EVAL_CLAUDE_SETTINGS },
|
|
206
|
+
plugins: withSkill ? [{ type: 'local', path: join(confined.root, '.claude') }] : [],
|
|
207
|
+
skills: withSkill ? [`${EVAL_CLAUDE_PLUGIN}:${confined.skill}`] : [],
|
|
208
|
+
env: evalGitSafetyEnv(confined.root),
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/** The manifest of a trial's Claude Code plugin (<root>/.claude/.claude-plugin/plugin.json): its name, nothing else. */
|
|
213
|
+
export function evalClaudePluginManifest() {
|
|
214
|
+
return `${JSON.stringify({ name: EVAL_CLAUDE_PLUGIN, version: '1.0.0', description: 'The skill under test (a SynaBun evaluation).' }, null, 2)}\n`;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Codex: the thread options and the config overrides of an evaluation run. A trial writes in its folder (the
|
|
219
|
+
* sandbox's writable root, no parent folder); the others read only. No network, no web search, every MCP server the
|
|
220
|
+
* account's config declares (and SynaBun's) disabled.
|
|
221
|
+
*/
|
|
222
|
+
export function codexEvalOptions(confined, { codexHome = null, projectDir = null } = {}) {
|
|
223
|
+
if (!confined || confined.kind !== EVAL_CONFINEMENT) throw new Error('Unknown confinement.');
|
|
224
|
+
const servers = new Set(['SynaBun', ...codexMcpServerNames(codexHome), ...(projectDir ? codexMcpServerNames(join(String(projectDir), '.codex')) : [])]);
|
|
225
|
+
const mcp_servers = {};
|
|
226
|
+
for (const name of servers) mcp_servers[name] = { enabled: false };
|
|
227
|
+
return {
|
|
228
|
+
thread: { sandboxMode: confined.role === 'trial' ? 'workspace-write' : 'read-only', networkAccessEnabled: false, webSearchMode: 'disabled', additionalDirectories: undefined },
|
|
229
|
+
config: { mcp_servers },
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* OpenCode's tools an evaluation run does without: refused by its rules (OpenCode 2's permission actions; a tool
|
|
235
|
+
* denied everywhere leaves the model's tool list). `execute` is Code Mode, which reaches the `opencode` namespace
|
|
236
|
+
* (session_move to another folder, worktree_create / worktree_remove, MCP resources) and the browser; `question`
|
|
237
|
+
* would wait for an answer nobody gives. What is left is Claude Code's list: read, write, edit, glob, grep, skill
|
|
238
|
+
* (and the shell when the case asks for it).
|
|
239
|
+
*/
|
|
240
|
+
export const OPENCODE_EVAL_TOOLS_OFF = Object.freeze(['webfetch', 'websearch', 'subagent', 'todo', 'lsp', 'external_directory', 'browser', 'execute', 'question']);
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* OpenCode settings every evaluation serve reads last of its configuration files (OPENCODE_CONFIG, after the run's own
|
|
244
|
+
* configuration, which starts from the owner's): no formatter (OpenCode 2 runs one after an edit, outside any sandbox,
|
|
245
|
+
* when a configuration turns them on, and prettier or biome would then load the folder's prettier.config.js or
|
|
246
|
+
* biome.json: a test file would run as code) and no snapshot (OpenCode 2 snapshots a git project's files with git).
|
|
247
|
+
*/
|
|
248
|
+
export const OPENCODE_EVAL_SETTINGS = Object.freeze({ formatter: false, snapshots: false });
|
|
249
|
+
/** Where an evaluation serve's last configuration file goes: the trial's own folder, beside the job folder (no tool or
|
|
250
|
+
* shell step of the run writes there). */
|
|
251
|
+
export const OPENCODE_EVAL_CONFIG_FILE = 'opencode-eval.json';
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* OpenCode: the environment of an evaluation run's serve. No project configuration of the folder at all (no
|
|
255
|
+
* opencode.json, no .opencode plugin, agent, command, tool or skill, no .agents skill, no AGENTS.md at the top:
|
|
256
|
+
* OPENCODE_DISABLE_PROJECT_CONFIG), nothing of Claude Code's (OPENCODE_DISABLE_CLAUDE_CODE), no file watcher (nothing is
|
|
257
|
+
* loaded again mid-run), OPENCODE_EVAL_SETTINGS (written here, as OPENCODE_CONFIG), git's safety settings. An inherited
|
|
258
|
+
* OPENCODE_CONFIG_DIR is removed (null), not merely left unset: OpenCode 2 reads that folder in place of its global one
|
|
259
|
+
* (config.directory, before XDG), so a SynaBun launched from a shell that exports it would lose the run's own
|
|
260
|
+
* configuration (its providers, rules and the skill under test placed in it; seen live on 2.1.4: "Model unavailable"
|
|
261
|
+
* for a provider the configuration defines). Every inherited GIT_* variable is removed before evalGitSafetyEnv's
|
|
262
|
+
* deliberate settings are applied, so none points the runtime's git around them. The skill under test goes into the
|
|
263
|
+
* run's configuration folder (placeOpenCodeEvalSkill). OpenCode's OPENCODE_CONFIG_CONTENT stays server.js's (the
|
|
264
|
+
* runtime overlay of every isolated serve).
|
|
265
|
+
*/
|
|
266
|
+
export function openCodeEvalEnv(confined) {
|
|
267
|
+
const file = join(confined.trialDir || dirname(confined.root), OPENCODE_EVAL_CONFIG_FILE);
|
|
268
|
+
rmSync(file, { force: true });
|
|
269
|
+
writeFileSync(file, `${JSON.stringify(OPENCODE_EVAL_SETTINGS)}\n`, { flag: 'wx', mode: 0o600 });
|
|
270
|
+
return {
|
|
271
|
+
OPENCODE_DISABLE_PROJECT_CONFIG: '1', OPENCODE_CONFIG_PROJECT_DISABLE: '1', OPENCODE_DISABLE_CLAUDE_CODE: '1', OPENCODE_DISABLE_FILEWATCHER: '1',
|
|
272
|
+
OPENCODE_CONFIG: file,
|
|
273
|
+
// An inherited OPENCODE_CONFIG_DIR takes the place of the run's own configuration folder (OpenCode 2 reads
|
|
274
|
+
// config.directory = process.env.OPENCODE_CONFIG_DIR, before XDG): removed, or SynaBun launched from a shell that
|
|
275
|
+
// set it would lose this run's isolated config (and the skill under test placed in it). A value of null tells
|
|
276
|
+
// server.js ensureIsolatedServe (withServeEnv) to delete the variable.
|
|
277
|
+
OPENCODE_CONFIG_DIR: null,
|
|
278
|
+
...evalGitSafetyEnv(confined.root),
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/** The most a skill copy may hold (lib/skills/evals.js wrote it from a library revision, which is bounded already). */
|
|
283
|
+
const OPENCODE_SKILL_COPY_LIMITS = Object.freeze({ entries: 2000, bytes: 64 * 1024 * 1024 });
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* OpenCode: a trial's copy of the skill under test placed in the run's own configuration folder (`configDir`, the
|
|
287
|
+
* folder server.js writes the run's configuration into and removes with its serve; OpenCode reads skills/<name>
|
|
288
|
+
* there as a global skill). Copied from the trial's .opencode/skills/<name>, which lib/skills/evals.js wrote and checked
|
|
289
|
+
* before the run, without following a link: regular files and folders only, bounded. → the folder, or null for a run
|
|
290
|
+
* without the skill (a baseline, a grader). Throws when the copy cannot be placed: a trial without its skill tests
|
|
291
|
+
* nothing, so it must not start.
|
|
292
|
+
*/
|
|
293
|
+
export function placeOpenCodeEvalSkill(confined, configDir) {
|
|
294
|
+
if (!confined || confined.kind !== EVAL_CONFINEMENT) throw new Error('Unknown confinement.');
|
|
295
|
+
if (confined.role !== 'trial' || !confined.skill) return null;
|
|
296
|
+
if (!/^[a-z0-9][a-z0-9._-]{0,63}$/.test(String(confined.skill))) throw new Error('The skill under test has no usable name.');
|
|
297
|
+
if (typeof configDir !== 'string' || !isAbsolute(configDir)) throw new Error('The run has no configuration folder.');
|
|
298
|
+
const from = join(confined.root, EVAL_SKILL_ROOTS.opencode, confined.skill);
|
|
299
|
+
const to = join(configDir, 'skills', confined.skill);
|
|
300
|
+
const top = lstatSync(from, { throwIfNoEntry: false });
|
|
301
|
+
if (!top || !top.isDirectory()) throw new Error(`The trial has no copy of the skill (${EVAL_SKILL_ROOTS.opencode}/${confined.skill}).`);
|
|
302
|
+
rmSync(to, { recursive: true, force: true });
|
|
303
|
+
let entries = 0;
|
|
304
|
+
let bytes = 0;
|
|
305
|
+
const copy = (src, dest) => {
|
|
306
|
+
mkdirSync(dest, { recursive: true, mode: 0o700 });
|
|
307
|
+
for (const name of readdirSync(src)) {
|
|
308
|
+
if (++entries > OPENCODE_SKILL_COPY_LIMITS.entries) throw new Error('The skill copy holds too many files.');
|
|
309
|
+
const s = join(src, name);
|
|
310
|
+
const st = lstatSync(s);
|
|
311
|
+
if (st.isDirectory()) copy(s, join(dest, name));
|
|
312
|
+
else if (st.isFile()) {
|
|
313
|
+
bytes += st.size;
|
|
314
|
+
if (bytes > OPENCODE_SKILL_COPY_LIMITS.bytes) throw new Error('The skill copy is too large.');
|
|
315
|
+
copyFileSync(s, join(dest, name), fsConstants.COPYFILE_EXCL);
|
|
316
|
+
} else throw new Error(`The skill copy holds something that is not a file or a folder (${relative(from, s)}).`);
|
|
317
|
+
}
|
|
318
|
+
};
|
|
319
|
+
copy(from, to);
|
|
320
|
+
return to;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* OpenCode: the config an evaluation run's serve and session get: OpenCode 2's permission rules (a trial's edits
|
|
325
|
+
* and shell asked, its skill allowed; a grader's refused) and no MCP server.
|
|
326
|
+
*/
|
|
327
|
+
export function openCodeEvalConfig(confined) {
|
|
328
|
+
const trial = confined?.role === 'trial';
|
|
329
|
+
const shell = !!confined?.shell;
|
|
330
|
+
const rule = (action, effect) => ({ action, resource: '*', effect });
|
|
331
|
+
return {
|
|
332
|
+
permissions: [
|
|
333
|
+
// read / grep / glob are asked, not allowed: OpenCode 2's FileAccess.resolve checks only that a path is
|
|
334
|
+
// syntactically inside the folder. The adapter answers each ask by evalOpenCodeDecision, which resolves the real
|
|
335
|
+
// path and refuses one that leaves the folder. On its own that is check-then-open (TOCTOU): a shell step could
|
|
336
|
+
// swap a job-folder symlink between the ask and the read tool's open, which runs in the runtime's own process,
|
|
337
|
+
// not under the shell's sandbox — so the ask cannot bind the path finally opened. What closes it is that no
|
|
338
|
+
// symlink can exist in the job folder to swap: the eval shell's Seatbelt profile denies symlink creation in every
|
|
339
|
+
// writable place (lib/skills/eval-sandbox.js), SynaBun's skill copy follows none, Write/Edit make plain files
|
|
340
|
+
// only, and the folder starts empty — the shell is the sole possible symlink writer. With the race surface gone
|
|
341
|
+
// this realpath check is sound (and stays as defense in depth). (A denied tool would leave the model's list;
|
|
342
|
+
// 'ask' keeps it.)
|
|
343
|
+
rule('read', 'ask'),
|
|
344
|
+
rule('grep', 'ask'),
|
|
345
|
+
rule('glob', 'ask'),
|
|
346
|
+
rule('edit', trial ? 'ask' : 'deny'),
|
|
347
|
+
rule('shell', shell ? 'ask' : 'deny'),
|
|
348
|
+
rule('skill', trial ? 'allow' : 'deny'),
|
|
349
|
+
...OPENCODE_EVAL_TOOLS_OFF.map((action) => rule(action, 'deny')),
|
|
350
|
+
],
|
|
351
|
+
mcp: 'off',
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/** The path a read / grep / glob ask names: its resource (read: the file; the search root otherwise) or metadata. */
|
|
356
|
+
function evalReadPathOf(request, kind) {
|
|
357
|
+
const meta = request?.metadata && typeof request.metadata === 'object' ? request.metadata : {};
|
|
358
|
+
// grep / glob carry the search root in metadata.path (its resource is the pattern); read carries the file in its resource.
|
|
359
|
+
if (kind === 'grep' || kind === 'glob') {
|
|
360
|
+
for (const key of ['path', 'directory', 'root']) if (typeof meta[key] === 'string' && meta[key]) return meta[key];
|
|
361
|
+
return '.';
|
|
362
|
+
}
|
|
363
|
+
for (const key of ['filePath', 'filepath', 'file_path', 'path']) if (typeof meta[key] === 'string' && meta[key]) return meta[key];
|
|
364
|
+
const pattern = request?.pattern ?? request?.patterns;
|
|
365
|
+
return typeof pattern === 'string' ? pattern : Array.isArray(pattern) && typeof pattern[0] === 'string' ? pattern[0] : null;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/** A read / grep / glob ask under an evaluation confinement: null when the real path is inside the folder, else why not. */
|
|
369
|
+
function evalReadDecision(request, confined, kind) {
|
|
370
|
+
const raw = evalReadPathOf(request, kind);
|
|
371
|
+
const root = confined?.root;
|
|
372
|
+
if (!root) return 'This run\'s evaluation folder is not known: nothing can be read.';
|
|
373
|
+
const at = placeOf(raw, root);
|
|
374
|
+
// placeOf follows every symlink (realPathOf): a link that leaves the folder resolves outside it and is refused.
|
|
375
|
+
// This check is race-free because the eval shell's sandbox denies symlink creation (lib/skills/eval-sandbox.js), so
|
|
376
|
+
// no link can be planted or repointed between this resolve and the read tool's open.
|
|
377
|
+
if (!at || !isInside(root, at, { allowRoot: true })) return `${kind === 'read' ? 'Read' : kind === 'grep' ? 'Grep' : 'Glob'} stays inside this run's folder (${root}); a path that resolves outside it (a symlink) is refused. ${REFUSED}`;
|
|
378
|
+
return null;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/** An OpenCode permission ask under an evaluation confinement: null when it may go ahead, else why not. */
|
|
382
|
+
export function evalOpenCodeDecision(request, confined) {
|
|
383
|
+
const kind = String(request?.permission || request?.type || '').toLowerCase();
|
|
384
|
+
const trial = confined?.role === 'trial';
|
|
385
|
+
if (kind === 'read' || kind === 'grep' || kind === 'glob') return evalReadDecision(request, confined, kind);
|
|
386
|
+
if (trial && kind === 'skill') return null;
|
|
387
|
+
if (trial && kind === 'bash') return confined.shell ? null : `The shell is not available in this evaluation. ${REFUSED}`;
|
|
388
|
+
if (trial && /^(?:edit|write|patch|multiedit|apply_patch)$/.test(kind)) {
|
|
389
|
+
const meta = request?.metadata && typeof request.metadata === 'object' ? request.metadata : {};
|
|
390
|
+
let raw = null;
|
|
391
|
+
for (const key of ['filePath', 'filepath', 'file_path', 'path']) if (typeof meta[key] === 'string' && meta[key]) { raw = meta[key]; break; }
|
|
392
|
+
if (!raw) {
|
|
393
|
+
const pattern = request?.pattern ?? request?.patterns;
|
|
394
|
+
raw = typeof pattern === 'string' ? pattern : Array.isArray(pattern) && typeof pattern[0] === 'string' ? pattern[0] : null;
|
|
395
|
+
}
|
|
396
|
+
return evalToolDecision('Write', { file_path: raw }, confined);
|
|
397
|
+
}
|
|
398
|
+
return `${kind || 'That tool'} is not available. ${REFUSED}`;
|
|
399
|
+
}
|